tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: NetBSD bug/misbehavior in vdprintf
On Fri, Aug 28, 2020 at 2:50 PM Rob Newberry <robthedude%mac.com@localhost> wrote:
> NetBSD's implementation of vdprintf makes a special check -- if the
> descriptor is in non-blocking mode, it needs to be a regular file (I think
> I read that code correctly). But it apparently doesn't have this check
> problem for vfprintf. I think it's been there a long time (since the
> introduction of vdprintf), but it makes vdprintf behave differently than
> vfprintf. In my view, "vfprintf( FILE, ...)" and "vdprintf( fileno( FILE
> ), ... )" ought to behave the same -- but they don't (on NetBSD) if
> "fileno( FILE )" has been marked non-blocking and it's not a regular file.
>
> Other OSes do not behave this way.
>
> Here's some very simple code that demonstrates:
>
> #include <stdio.h>
> #include <fcntl.h>
> #include <errno.h>
>
> static void check_result( int n )
> {
> if ( n < 0 ) { fprintf( stderr, "\tfailure (error =
> %d)\n", errno ); }
> else { fprintf( stderr, "\tsuccess!\n" ); }
> }
>
> int main(int argc, const char * argv[])
> {
> int n;
> int flags;
> int err;
>
> n = fprintf( stdout, "fprintf to stdout (blocking)\n" );
> check_result( n );
>
> n = dprintf( fileno( stdout ), "dprintf to stdout
> (blocking)\n" );
> check_result( n );
>
> // now set stdout to non-blocking
> flags = fcntl( fileno( stdout ), F_GETFL );
> err = fcntl( fileno( stdout ), F_SETFL, flags | O_NONBLOCK
> );
> if ( err != 0 )
> {
> fprintf( stderr, "fcntl( F_SETFL ) failure
> (%d)\n", errno );
> }
>
> n = fprintf( stdout, "fprintf to stdout (non-blocking)\n"
> );
> check_result( n );
>
> n = dprintf( fileno( stdout ), "dprintf to stdout
> (non-blocking)\n" );
> check_result( n );
>
> return 0;
> }
>
> Here's the output on mac OS, FreeBSD and Linux:
>
> > ./dprintf_test
> fprintf to stdout (blocking)
> success!
> dprintf to stdout (blocking)
> success!
> fprintf to stdout (non-blocking)
> success!
> dprintf to stdout (non-blocking)
> success!
>
> But here's the output on NetBSD:
>
> > ./dprintf_test
> fprintf to stdout (blocking)
> success!
> dprintf to stdout (blocking)
> success!
> fprintf to stdout (non-blocking)
> success!
> failure (error = 79)
>
> The behavior is caused by code in libc/stdio/vdprintf.c -- around line 92:
>
> if (fdflags & O_NONBLOCK) {
> struct stat st;
> if (fstat(fd, &st) == -1)
> return -1;
> if (!S_ISREG(st.st_mode)) {
> errno = EFTYPE;
> return EOF;
> }
> }
>
> Why is this done on NetBSD (when it isn't on other OSes)?
(fwiw, i didn't check FreeBSD but Android [via OpenBSD] doesn't have this
either.)
> And why does vfprintf not have the same restriction/limitation?
>
> Thanks!
>
> Rob
>
>
Home |
Main Index |
Thread Index |
Old Index