diff options
Diffstat (limited to 'libc/stdio/stdio.cpp')
-rw-r--r-- | libc/stdio/stdio.cpp | 93 |
1 files changed, 44 insertions, 49 deletions
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index a0b421923..c429ff2c3 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -50,15 +50,15 @@ #include <async_safe/log.h> -#include "local.h" #include "glue.h" +#include "local.h" +#include "private/ErrnoRestorer.h" +#include "private/FdPath.h" #include "private/__bionic_get_shell_path.h" #include "private/bionic_fortify.h" -#include "private/ErrnoRestorer.h" #include "private/thread_private.h" -#define ALIGNBYTES (sizeof(uintptr_t) - 1) -#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) +#include "private/bsd_sys_param.h" // For ALIGN/ALIGNBYTES. #define NDYNAMIC 10 /* add ten more whenever necessary */ @@ -226,25 +226,21 @@ extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) { _fwalk(__sflush); } -static FILE* __fopen(int fd, int flags) { +static FILE* __FILE_init(FILE* fp, int fd, int flags) { + if (fp == nullptr) return nullptr; + #if !defined(__LP64__) - if (fd > SHRT_MAX) { - errno = EMFILE; - return nullptr; - } + if (fd > SHRT_MAX) __fortify_fatal("stdio: fd %d > SHRT_MAX", fd); #endif - FILE* fp = __sfp(); - if (fp != nullptr) { - fp->_file = fd; - android_fdsan_exchange_owner_tag(fd, 0, __get_file_tag(fp)); - fp->_flags = flags; - fp->_cookie = fp; - fp->_read = __sread; - fp->_write = __swrite; - fp->_close = __sclose; - _EXT(fp)->_seek64 = __sseek64; - } + fp->_file = fd; + android_fdsan_exchange_owner_tag(fd, 0, __get_file_tag(fp)); + fp->_flags = flags; + fp->_cookie = fp; + fp->_read = __sread; + fp->_write = __swrite; + fp->_close = __sclose; + _EXT(fp)->_seek64 = __sseek64; return fp; } @@ -258,14 +254,15 @@ FILE* fopen(const char* file, const char* mode) { return nullptr; } - FILE* fp = __fopen(fd, flags); + FILE* fp = __FILE_init(__sfp(), fd, flags); if (fp == nullptr) { ErrnoRestorer errno_restorer; close(fd); return nullptr; } - // For append mode, even though we use O_APPEND, we need to seek to the end now. + // For append mode, O_APPEND sets the write position for free, but we need to + // set the read position manually. if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END); return fp; } @@ -296,15 +293,26 @@ FILE* fdopen(int fd, const char* mode) { fcntl(fd, F_SETFD, tmp | FD_CLOEXEC); } - return __fopen(fd, flags); + return __FILE_init(__sfp(), fd, flags); } -// Re-direct an existing, open (probably) file to some other file. -// ANSI is written such that the original file gets closed if at -// all possible, no matter what. -// TODO: rewrite this mess completely. FILE* freopen(const char* file, const char* mode, FILE* fp) { CHECK_FP(fp); + + // POSIX says: "If pathname is a null pointer, the freopen() function shall + // attempt to change the mode of the stream to that specified by mode, as if + // the name of the file currently associated with the stream had been used. In + // this case, the file descriptor associated with the stream need not be + // closed if the call to freopen() succeeds. It is implementation-defined + // which changes of mode are permitted (if any), and under what + // circumstances." + // + // Linux is quite restrictive about what changes you can make with F_SETFL, + // and in particular won't let you touch the access bits. It's easiest and + // most effective to just rely on /proc/self/fd/... + FdPath fd_path(fp->_file); + if (file == nullptr) file = fd_path.c_str(); + int mode_flags; int flags = __sflags(mode, &mode_flags); if (flags == 0) { @@ -314,6 +322,8 @@ FILE* freopen(const char* file, const char* mode, FILE* fp) { ScopedFileLock sfl(fp); + // TODO: rewrite this mess completely. + // There are actually programs that depend on being able to "freopen" // descriptors that weren't originally open. Keep this from breaking. // Remember whether the stream was open to begin with, and which file @@ -383,24 +393,12 @@ FILE* freopen(const char* file, const char* mode, FILE* fp) { } } - // _file is only a short. - if (fd > SHRT_MAX) { - fp->_flags = 0; // Release. - errno = EMFILE; - return nullptr; - } - - fp->_flags = flags; - fp->_file = fd; - android_fdsan_exchange_owner_tag(fd, 0, __get_file_tag(fp)); - fp->_cookie = fp; - fp->_read = __sread; - fp->_write = __swrite; - fp->_close = __sclose; - _EXT(fp)->_seek64 = __sseek64; + __FILE_init(fp, fd, flags); - // For append mode, even though we use O_APPEND, we need to seek to the end now. + // For append mode, O_APPEND sets the write position for free, but we need to + // set the read position manually. if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END); + return fp; } __strong_alias(freopen64, freopen); @@ -773,10 +771,7 @@ char* fgets(char* buf, int n, FILE* fp) { // Returns first argument, or nullptr if no characters were read. // Does not return nullptr if n == 1. char* fgets_unlocked(char* buf, int n, FILE* fp) { - if (n <= 0) { - errno = EINVAL; - return nullptr; - } + if (n <= 0) __fortify_fatal("fgets: buffer size %d <= 0", n); _SET_ORIENTATION(fp, -1); @@ -1026,9 +1021,9 @@ int vsnprintf(char* s, size_t n, const char* fmt, va_list ap) { __check_count("vsnprintf", "size", n); // Stdio internals do not deal correctly with zero length buffer. - char dummy; + char one_byte_buffer[1]; if (n == 0) { - s = &dummy; + s = one_byte_buffer; n = 1; } |