diff --git a/include/stdio.h b/include/stdio.h --- a/include/stdio.h +++ b/include/stdio.h @@ -126,7 +126,7 @@ int _r; /* (*) read space left for getc() */ int _w; /* (*) write space left for putc() */ short _flags; /* (*) flags, below; this FILE is free if 0 */ - short _fileno; /* (*) fileno, if Unix descriptor, else -1 */ + short _fileno_short; /* (*) fileno, if Unix descriptor and <= SHRT_MAX, else -1 [legacy] */ struct __sbuf _bf; /* (*) the buffer (at least 1 byte, if !NULL) */ int _lbfsize; /* (*) 0 or -_bf._size, for inline putc */ @@ -159,6 +159,7 @@ int _orientation; /* orientation for fwide() */ __mbstate_t _mbstate; /* multibyte conversion state */ int _flags2; /* additional flags */ + int _fileno; /* (*) fileno, if Unix descriptor, else -1 */ }; #ifndef _STDFILE_DECLARED #define _STDFILE_DECLARED diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -61,6 +61,7 @@ if (HASLB(fp)) FREELB(fp); fp->_fileno = -1; + fp->_fileno_short = -1; fp->_r = fp->_w = 0; /* Mess up if reaccessed. */ /* diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c --- a/lib/libc/stdio/fdopen.c +++ b/lib/libc/stdio/fdopen.c @@ -48,17 +48,10 @@ FILE *fp; int flags, oflags, fdflags, rc, tmp; - /* - * File descriptors are a full int, but _fileno is only a short. - * If we get a valid file descriptor that is greater than - * SHRT_MAX, then the fd will get sign-extended into an - * invalid file descriptor. Handle this case by failing the - * open. - */ - if (fd > SHRT_MAX) { - errno = EMFILE; - return (NULL); - } + if (fd < 0) { + errno = EBADF; + return (NULL); + } if ((flags = __sflags(mode, &oflags)) == 0) return (NULL); @@ -102,6 +95,7 @@ else if (oflags & O_APPEND) fp->_flags |= __SAPP; fp->_fileno = fd; + fp->_fileno_short = (unsigned)fd > SHRT_MAX ? -1 : fd; fp->_cookie = fp; fp->_read = __sread; fp->_write = __swrite; diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c --- a/lib/libc/stdio/findfp.c +++ b/lib/libc/stdio/findfp.c @@ -53,6 +53,7 @@ #define std(flags, file) { \ ._flags = (flags), \ ._fileno = (file), \ + ._fileno_short = (file), \ ._cookie = __sF + (file), \ ._close = __sclose, \ ._read = __sread, \ @@ -146,6 +147,7 @@ fp->_bf._size = 0; fp->_lbfsize = 0; /* not line buffered */ fp->_fileno = -1; /* no file */ + fp->_fileno_short = -1; /* no file */ /* fp->_cookie = ; */ /* caller sets cookie, _read/_write etc */ fp->_ub._base = NULL; /* no ungetc buffer */ fp->_ub._size = 0; diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c --- a/lib/libc/stdio/fopen.c +++ b/lib/libc/stdio/fopen.c @@ -59,20 +59,8 @@ fp->_flags = 0; /* release */ return (NULL); } - /* - * File descriptors are a full int, but _fileno is only a short. - * If we get a valid file descriptor that is greater than - * SHRT_MAX, then the fd will get sign-extended into an - * invalid file descriptor. Handle this case by failing the - * open. - */ - if (f > SHRT_MAX) { - fp->_flags = 0; /* release */ - _close(f); - errno = EMFILE; - return (NULL); - } fp->_fileno = f; + fp->_fileno_short = (unsigned)f > SHRT_MAX ? -1 : f; fp->_flags = flags; fp->_cookie = fp; fp->_read = __sread; diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c --- a/lib/libc/stdio/freopen.c +++ b/lib/libc/stdio/freopen.c @@ -212,22 +212,9 @@ (void)_close(fp->_fileno); } - /* - * File descriptors are a full int, but _fileno is only a short. - * If we get a valid file descriptor that is greater than - * SHRT_MAX, then the fd will get sign-extended into an - * invalid file descriptor. Handle this case by failing the - * open. - */ - if (f > SHRT_MAX) { - fp->_flags = 0; /* set it free */ - errno = EMFILE; - fp = NULL; - goto end; - } - fp->_flags = flags; fp->_fileno = f; + fp->_fileno_short = (unsigned)f > SHRT_MAX ? -1 : f; fp->_cookie = fp; fp->_read = __sread; fp->_write = __swrite; diff --git a/lib/libc/stdio/funopen.c b/lib/libc/stdio/funopen.c --- a/lib/libc/stdio/funopen.c +++ b/lib/libc/stdio/funopen.c @@ -63,6 +63,7 @@ return (NULL); fp->_flags = flags; fp->_fileno = -1; + fp->_fileno_short = -1; fp->_cookie = (void *)cookie; fp->_read = readfn; fp->_write = writefn; diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -129,6 +129,7 @@ */ #define FAKE_FILE { \ ._fileno = -1, \ + ._fileno_short = -1, \ ._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \ } diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c --- a/lib/libc/stdio/vdprintf.c +++ b/lib/libc/stdio/vdprintf.c @@ -33,6 +33,7 @@ #include "namespace.h" #include +#include #include #include #include @@ -47,17 +48,27 @@ FILE f = FAKE_FILE; unsigned char buf[BUFSIZ]; int serrno = errno; - int ret; + int ret, fdflags; - if (fd > SHRT_MAX) { - errno = EMFILE; - return (EOF); + if (fd < 0) { + errno = EBADF; + return (-1); + } + + /* Ensure descriptor has been opened for writing */ + if ((fdflags = _fcntl(fd, F_GETFL, 0)) == -1) + return (-1); + fdflags &= (O_ACCMODE | O_EXEC); + if (fdflags != O_RDWR && fdflags != O_WRONLY) { + errno = EINVAL; + return (-1); } f._p = buf; f._w = sizeof(buf); f._flags = __SWR; f._fileno = fd; + f._fileno_short = (unsigned)fd > SHRT_MAX ? -1 : fd; f._cookie = &f; f._write = __swrite; f._bf._base = buf; diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -183,6 +183,7 @@ /* copy the important variables */ fake._flags = fp->_flags & ~__SNBF; fake._fileno = fp->_fileno; + fake._fileno_short = fp->_fileno_short; fake._cookie = fp->_cookie; fake._write = fp->_write; fake._orientation = fp->_orientation; diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -219,6 +219,7 @@ /* copy the important variables */ fake._flags = fp->_flags & ~__SNBF; fake._fileno = fp->_fileno; + fake._fileno_short = fp->_fileno_short; fake._cookie = fp->_cookie; fake._write = fp->_write; fake._orientation = fp->_orientation; diff --git a/lib/libc/stdio/xprintf.c b/lib/libc/stdio/xprintf.c --- a/lib/libc/stdio/xprintf.c +++ b/lib/libc/stdio/xprintf.c @@ -576,6 +576,7 @@ /* copy the important variables */ fake._flags = fp->_flags & ~__SNBF; fake._fileno = fp->_fileno; + fake._fileno_short = fp->_fileno_short; fake._cookie = fp->_cookie; fake._write = fp->_write; fake._orientation = fp->_orientation;