diff options
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 181 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_interceptors.h | 3 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.cc | 19 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.h | 20 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_fd.cc | 4 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_fd.h | 4 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 75 | ||||
-rw-r--r-- | test/msan/getc_unlocked.c | 32 | ||||
-rw-r--r-- | test/msan/open_memstream.cc | 18 |
9 files changed, 289 insertions, 67 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index b66e78d7b..a4305270a 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -65,6 +65,14 @@ #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg)) #endif +#ifndef COMMON_INTERCEPTOR_FILE_OPEN +#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {} +#endif + +#ifndef COMMON_INTERCEPTOR_FILE_CLOSE +#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {} +#endif + #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -3718,6 +3726,174 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp, #define INIT_TSEARCH #endif +#if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \ + SANITIZER_INTERCEPT_OPEN_MEMSTREAM +void unpoison_file(__sanitizer_FILE *fp) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp)); + if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base, + fp->_IO_read_end - fp->_IO_read_base); +} +#endif + +#if SANITIZER_INTERCEPT_LIBIO_INTERNALS +// These guys are called when a .c source is built with -O2. +INTERCEPTOR(int, __uflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __uflow, fp); + int res = REAL(__uflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __underflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __underflow, fp); + int res = REAL(__underflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __overflow, __sanitizer_FILE *fp, int ch) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __overflow, fp, ch); + int res = REAL(__overflow)(fp, ch); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __wuflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __wuflow, fp); + int res = REAL(__wuflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __wunderflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __wunderflow, fp); + int res = REAL(__wunderflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __woverflow, fp, ch); + int res = REAL(__woverflow)(fp, ch); + unpoison_file(fp); + return res; +} +#define INIT_LIBIO_INTERNALS \ + COMMON_INTERCEPT_FUNCTION(__uflow); \ + COMMON_INTERCEPT_FUNCTION(__underflow); \ + COMMON_INTERCEPT_FUNCTION(__overflow); \ + COMMON_INTERCEPT_FUNCTION(__wuflow); \ + COMMON_INTERCEPT_FUNCTION(__wunderflow); \ + COMMON_INTERCEPT_FUNCTION(__woverflow); +#else +#define INIT_LIBIO_INTERNALS +#endif + +#if SANITIZER_INTERCEPT_FOPEN +INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); + __sanitizer_FILE *res = REAL(fopen)(path, mode); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, fopen64, const char *path, const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fopen64, path, mode); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); + __sanitizer_FILE *res = REAL(fopen64)(path, mode); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, fdopen, int fd, const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fdopen, fd, mode); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); + __sanitizer_FILE *res = REAL(fdopen)(fd, mode); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode, + __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + __sanitizer_FILE *res = REAL(freopen)(path, mode, fp); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode, + __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +#define INIT_FOPEN \ + COMMON_INTERCEPT_FUNCTION(fopen); \ + COMMON_INTERCEPT_FUNCTION(fopen64); \ + COMMON_INTERCEPT_FUNCTION(fdopen); \ + COMMON_INTERCEPT_FUNCTION(freopen); \ + COMMON_INTERCEPT_FUNCTION(freopen64); +#else +#define INIT_FOPEN +#endif + +#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM +INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc); + __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc); + if (res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); + unpoison_file(res); + } + return res; +} +INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr, + SIZE_T *sizeloc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open_wmemstream, ptr, sizeloc); + __sanitizer_FILE *res = REAL(open_wmemstream)(ptr, sizeloc); + if (res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); + unpoison_file(res); + } + return res; +} +INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size, + const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode); + __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode); + if (res) unpoison_file(res); + return res; +} +#define INIT_OPEN_MEMSTREAM \ + COMMON_INTERCEPT_FUNCTION(open_memstream); \ + COMMON_INTERCEPT_FUNCTION(open_wmemstream); \ + COMMON_INTERCEPT_FUNCTION(fmemopen); +#else +#define INIT_OPEN_MEMSTREAM +#endif + #define SANITIZER_COMMON_INTERCEPTORS_INIT \ INIT_TEXTDOMAIN; \ INIT_STRCMP; \ @@ -3848,5 +4024,8 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp, INIT___BZERO; \ INIT_FTIME; \ INIT_XDR; \ - INIT_TSEARCH; + INIT_TSEARCH; \ + INIT_LIBIO_INTERNALS; \ + INIT_FOPEN; \ + INIT_OPEN_MEMSTREAM; /**/ diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a26a8f8f3..2401e470b 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -196,5 +196,8 @@ #define SANITIZER_INTERCEPT_FTIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index 9ae4870c1..59ad8e271 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -1126,4 +1126,23 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); #endif +#if SANITIZER_LINUX && !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); +CHECK_SIZE_AND_OFFSET(FILE, _flags); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); +CHECK_SIZE_AND_OFFSET(FILE, _markers); +CHECK_SIZE_AND_OFFSET(FILE, _chain); +CHECK_SIZE_AND_OFFSET(FILE, _fileno); +#endif + #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index a780ee282..5b165c917 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -630,6 +630,26 @@ namespace __sanitizer { #endif }; +#if SANITIZER_LINUX && !SANITIZER_ANDROID + struct __sanitizer_FILE { + int _flags; + char *_IO_read_ptr; + char *_IO_read_end; + char *_IO_read_base; + char *_IO_write_base; + char *_IO_write_ptr; + char *_IO_write_end; + char *_IO_buf_base; + char *_IO_buf_end; + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + void *_markers; + __sanitizer_FILE *_chain; + int _fileno; + }; +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64)) extern unsigned struct_user_regs_struct_sz; diff --git a/lib/tsan/rtl/tsan_fd.cc b/lib/tsan/rtl/tsan_fd.cc index b858514c6..6c7fc174a 100644 --- a/lib/tsan/rtl/tsan_fd.cc +++ b/lib/tsan/rtl/tsan_fd.cc @@ -285,13 +285,13 @@ void FdSocketConnect(ThreadState *thr, uptr pc, int fd) { init(thr, pc, fd, &fdctx.socksync); } -uptr File2addr(char *path) { +uptr File2addr(const char *path) { (void)path; static u64 addr; return (uptr)&addr; } -uptr Dir2addr(char *path) { +uptr Dir2addr(const char *path) { (void)path; static u64 addr; return (uptr)&addr; diff --git a/lib/tsan/rtl/tsan_fd.h b/lib/tsan/rtl/tsan_fd.h index 979198e2e..75c616dae 100644 --- a/lib/tsan/rtl/tsan_fd.h +++ b/lib/tsan/rtl/tsan_fd.h @@ -57,8 +57,8 @@ void FdSocketConnect(ThreadState *thr, uptr pc, int fd); bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack); void FdOnFork(ThreadState *thr, uptr pc); -uptr File2addr(char *path); -uptr Dir2addr(char *path); +uptr File2addr(const char *path); +uptr Dir2addr(const char *path); } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index b545f8c52..6f23a460b 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -1599,64 +1599,6 @@ TSAN_INTERCEPTOR(int, unlink, char *path) { return res; } -TSAN_INTERCEPTOR(void*, fopen, char *path, char *mode) { - SCOPED_TSAN_INTERCEPTOR(fopen, path, mode); - void *res = REAL(fopen)(path, mode); - Acquire(thr, pc, File2addr(path)); - if (res) { - int fd = fileno_unlocked(res); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - } - return res; -} - -TSAN_INTERCEPTOR(void*, fopen64, char *path, char *mode) { - SCOPED_TSAN_INTERCEPTOR(fopen64, path, mode); - void *res = REAL(fopen64)(path, mode); - Acquire(thr, pc, File2addr(path)); - if (res) { - int fd = fileno_unlocked(res); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - } - return res; -} - -TSAN_INTERCEPTOR(void*, freopen, char *path, char *mode, void *stream) { - SCOPED_TSAN_INTERCEPTOR(freopen, path, mode, stream); - if (stream) { - int fd = fileno_unlocked(stream); - if (fd >= 0) - FdClose(thr, pc, fd); - } - void *res = REAL(freopen)(path, mode, stream); - Acquire(thr, pc, File2addr(path)); - if (res) { - int fd = fileno_unlocked(res); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - } - return res; -} - -TSAN_INTERCEPTOR(void*, freopen64, char *path, char *mode, void *stream) { - SCOPED_TSAN_INTERCEPTOR(freopen64, path, mode, stream); - if (stream) { - int fd = fileno_unlocked(stream); - if (fd >= 0) - FdClose(thr, pc, fd); - } - void *res = REAL(freopen64)(path, mode, stream); - Acquire(thr, pc, File2addr(path)); - if (res) { - int fd = fileno_unlocked(res); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - } - return res; -} - TSAN_INTERCEPTOR(void*, tmpfile, int fake) { SCOPED_TSAN_INTERCEPTOR(tmpfile, fake); void *res = REAL(tmpfile)(fake); @@ -2100,6 +2042,19 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, ctx = (void *)&_ctx; \ (void) ctx; +#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ + Acquire(thr, pc, File2addr(path)); \ + if (file) { \ + int fd = fileno_unlocked(file); \ + if (fd >= 0) FdFileCreate(thr, pc, fd); \ + } + +#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ + if (file) { \ + int fd = fileno_unlocked(file); \ + if (fd >= 0) FdClose(thr, pc, fd); \ + } + #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd) @@ -2411,10 +2366,6 @@ void InitializeInterceptors() { TSAN_INTERCEPT(recv); TSAN_INTERCEPT(unlink); - TSAN_INTERCEPT(fopen); - TSAN_INTERCEPT(fopen64); - TSAN_INTERCEPT(freopen); - TSAN_INTERCEPT(freopen64); TSAN_INTERCEPT(tmpfile); TSAN_INTERCEPT(tmpfile64); TSAN_INTERCEPT(fclose); diff --git a/test/msan/getc_unlocked.c b/test/msan/getc_unlocked.c new file mode 100644 index 000000000..805806ffb --- /dev/null +++ b/test/msan/getc_unlocked.c @@ -0,0 +1,32 @@ +// RUN: %clangxx_msan -DGETC -m64 -O0 -g -xc++ %s -o %t && %t +// RUN: %clangxx_msan -DGETC -m64 -O3 -g -xc++ %s -o %t && %t +// RUN: %clang_msan -DGETC -m64 -O0 -g %s -o %t && %t +// RUN: %clang_msan -DGETC -m64 -O3 -g %s -o %t && %t + +// RUN: %clangxx_msan -DGETCHAR -m64 -O0 -g -xc++ %s -o %t && %t +// RUN: %clangxx_msan -DGETCHAR -m64 -O3 -g -xc++ %s -o %t && %t +// RUN: %clang_msan -DGETCHAR -m64 -O0 -g %s -o %t && %t +// RUN: %clang_msan -DGETCHAR -m64 -O3 -g %s -o %t && %t + +#include <assert.h> +#include <stdio.h> +#include <unistd.h> + +int main() { + FILE *stream = fopen("/dev/zero", "r"); + flockfile (stream); + int c; +#if defined(GETCHAR) + int res = dup2(fileno(stream), 0); + assert(res == 0); + c = getchar_unlocked(); +#elif defined(GETC) + c = getc_unlocked (stream); +#endif + funlockfile (stream); + if (c == EOF) + return 1; + printf("%c\n", (char)c); + fclose(stream); + return 0; +} diff --git a/test/msan/open_memstream.cc b/test/msan/open_memstream.cc new file mode 100644 index 000000000..af3f795d9 --- /dev/null +++ b/test/msan/open_memstream.cc @@ -0,0 +1,18 @@ +// RUN: %clangxx_msan -m64 -O0 -g -xc++ %s -o %t && %t +// RUN: %clangxx_msan -m64 -O3 -g -xc++ %s -o %t && %t + +#include <stdio.h> +#include <stdlib.h> + +int main(void) { + char *buf; + size_t buf_len = 42; + FILE *fp = open_memstream(&buf, &buf_len); + fprintf(fp, "hello"); + fflush(fp); + printf("buf_len = %zu\n", buf_len); + for (int j = 0; j < buf_len; j++) { + printf("buf[%d] = %c\n", j, buf[j]); + } + return 0; +} |