[sanitizer] Intercept a bunch of stdio calls.

Add move fopen/freopen interceptors from TSan to common.

llvm-svn: 207224
This commit is contained in:
Evgeniy Stepanov 2014-04-25 13:26:21 +00:00
parent d0f841ce4a
commit f3d5d119a8
9 changed files with 289 additions and 67 deletions

View File

@ -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;
/**/

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}