diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2014-05-13 08:36:31 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2014-05-13 08:36:31 +0000 |
commit | cad7f30c4a24a2aaa81fac9e986d34bd6316b295 (patch) | |
tree | 5d3959a86918f49ba72b19ebdc0ead68922c02f3 /lib | |
parent | 50926f626de44bf11819b86e0f39240159c1e66d (diff) |
[msan] Better open_memstream support.
Move fflush and fclose interceptors to sanitizer_common.
Use a metadata map to keep information about the external locations
that must be updated when the file is written to.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@208676 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sanitizer_common/sanitizer_addrhashmap.h | 35 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 116 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_interceptors.h | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.h | 4 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 26 |
5 files changed, 150 insertions, 35 deletions
diff --git a/lib/sanitizer_common/sanitizer_addrhashmap.h b/lib/sanitizer_common/sanitizer_addrhashmap.h index c50fb1e33..e09192643 100644 --- a/lib/sanitizer_common/sanitizer_addrhashmap.h +++ b/lib/sanitizer_common/sanitizer_addrhashmap.h @@ -17,6 +17,7 @@ #include "sanitizer_common.h" #include "sanitizer_mutex.h" #include "sanitizer_atomic.h" +#include "sanitizer_allocator_internal.h" namespace __sanitizer { @@ -66,9 +67,12 @@ class AddrHashMap { class Handle { public: - Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove = false); + Handle(AddrHashMap<T, kSize> *map, uptr addr); + Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove); + Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create); + ~Handle(); - T *operator -> (); + T *operator->(); bool created() const; bool exists() const; @@ -81,6 +85,7 @@ class AddrHashMap { uptr addidx_; bool created_; bool remove_; + bool create_; }; private: @@ -93,11 +98,31 @@ class AddrHashMap { }; template<typename T, uptr kSize> +AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) { + map_ = map; + addr_ = addr; + remove_ = false; + create_ = true; + map_->acquire(this); +} + +template<typename T, uptr kSize> AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove) { map_ = map; addr_ = addr; remove_ = remove; + create_ = true; + map_->acquire(this); +} + +template<typename T, uptr kSize> +AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr, + bool remove, bool create) { + map_ = map; + addr_ = addr; + remove_ = remove; + create_ = create; map_->acquire(this); } @@ -106,8 +131,8 @@ AddrHashMap<T, kSize>::Handle::~Handle() { map_->release(this); } -template<typename T, uptr kSize> -T *AddrHashMap<T, kSize>::Handle::operator -> () { +template <typename T, uptr kSize> +T *AddrHashMap<T, kSize>::Handle::operator->() { return &cell_->val; } @@ -207,7 +232,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) { } // The element does not exist, no need to create it if we want to remove. - if (h->remove_) { + if (h->remove_ || !h->create_) { b->mtx.Unlock(); return; } diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 2ff721820..31ec78bff 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -28,6 +28,8 @@ // COMMON_INTERCEPTOR_HANDLE_RECVMSG //===----------------------------------------------------------------------===// #include "interception/interception.h" +#include "sanitizer_addrhashmap.h" +#include "sanitizer_placement_new.h" #include "sanitizer_platform_interceptors.h" #include "sanitizer_tls_get_addr.h" @@ -73,6 +75,52 @@ #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {} #endif +struct FileMetadata { + // For open_memstream(). + char **addr; + SIZE_T *size; +}; + +struct CommonInterceptorMetadata { + enum { + CIMT_INVALID = 0, + CIMT_FILE + } type; + union { + FileMetadata file; + }; +}; + +typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap; + +static MetadataHashMap *interceptor_metadata_map; + +static void SetInterceptorMetadata(__sanitizer_FILE *addr, + const FileMetadata &file) { + MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr); + CHECK(h.created()); + h->type = CommonInterceptorMetadata::CIMT_FILE; + h->file = file; +} + +static const FileMetadata *GetInterceptorMetadata(__sanitizer_FILE *addr) { + MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, + /* remove */ false, + /* create */ false); + if (h.exists()) { + CHECK(!h.created()); + CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE); + return &h->file; + } else { + return 0; + } +} + +static void DeleteInterceptorMetadata(void *addr) { + MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true); + CHECK(h.exists()); +} + #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -624,6 +672,14 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) { #define INIT_STRPTIME #endif +void update_FILE(__sanitizer_FILE *fp) { +#if SANITIZER_HAS_STRUCT_FILE + const FileMetadata *m = GetInterceptorMetadata(fp); + if (m) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); +#endif // SANITIZER_HAS_STRUCT_FILE +} + #if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF #include "sanitizer_common_interceptors_format.inc" @@ -789,7 +845,8 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) INTERCEPTOR(int, vprintf, const char *format, va_list ap) VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap) -INTERCEPTOR(int, vfprintf, void *stream, const char *format, va_list ap) +INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format, + va_list ap) VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap) INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format, @@ -806,8 +863,8 @@ VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap) INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap) VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap) -INTERCEPTOR(int, __isoc99_vfprintf, void *stream, const char *format, - va_list ap) +INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream, + const char *format, va_list ap) VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap) INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format, @@ -824,7 +881,7 @@ VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format, INTERCEPTOR(int, printf, const char *format, ...) FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format) -INTERCEPTOR(int, fprintf, void *stream, const char *format, ...) +INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...) FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format) INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT @@ -840,7 +897,8 @@ FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format) INTERCEPTOR(int, __isoc99_printf, const char *format, ...) FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format) -INTERCEPTOR(int, __isoc99_fprintf, void *stream, const char *format, ...) +INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format, + ...) FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format) INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...) @@ -3729,10 +3787,12 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp, #if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \ SANITIZER_INTERCEPT_OPEN_MEMSTREAM void unpoison_file(__sanitizer_FILE *fp) { +#if SANITIZER_HAS_STRUCT_FILE 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 // SANITIZER_HAS_STRUCT_FILE } #endif @@ -3863,6 +3923,8 @@ INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); unpoison_file(res); + FileMetadata file = {ptr, sizeloc}; + SetInterceptorMetadata(res, file); } return res; } @@ -3875,6 +3937,8 @@ INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr, COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); unpoison_file(res); + FileMetadata file = {(char **)ptr, sizeloc}; + SetInterceptorMetadata(res, file); } return res; } @@ -3937,7 +4001,47 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) { #define INIT_OBSTACK #endif +#if SANITIZER_INTERCEPT_FFLUSH +INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp); + int res = REAL(fflush)(fp); + // FIXME: handle fp == NULL + if (fp) { + const FileMetadata *m = GetInterceptorMetadata(fp); + if (m) COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); + } + return res; +} +#define INIT_FFLUSH COMMON_INTERCEPT_FUNCTION(fflush); +#else +#define INIT_FFLUSH +#endif + +#if SANITIZER_INTERCEPT_FCLOSE +INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp); + int res = REAL(fclose)(fp); + if (fp) { + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + const FileMetadata *m = GetInterceptorMetadata(fp); + if (m) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); + DeleteInterceptorMetadata(fp); + } + } + return res; +} +#define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose); +#else +#define INIT_FCLOSE +#endif + static void InitializeCommonInterceptors() { + static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; + interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); + INIT_TEXTDOMAIN; INIT_STRCMP; INIT_STRNCMP; @@ -4072,4 +4176,6 @@ static void InitializeCommonInterceptors() { INIT_FOPEN; INIT_OPEN_MEMSTREAM; INIT_OBSTACK; + INIT_FFLUSH; + INIT_FCLOSE; } diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index d8c25874d..62c71faf7 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -197,8 +197,10 @@ #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_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index cfe0d9946..d83ec8c81 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -661,6 +661,10 @@ namespace __sanitizer { __sanitizer_FILE *_chain; int _fileno; }; +# define SANITIZER_HAS_STRUCT_FILE 1 +#else + typedef void __sanitizer_FILE; +# define SANITIZER_HAS_STRUCT_FILE 0 #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 5c7e80652..8cfd80ba5 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -53,6 +53,7 @@ extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); // REAL(sigfillset) defined in common interceptors. DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set) +DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) extern "C" void *pthread_self(); extern "C" void _exit(int status); extern "C" int *__errno_location(); @@ -62,7 +63,7 @@ extern "C" void *__libc_calloc(uptr size, uptr n); extern "C" void *__libc_realloc(void *ptr, uptr size); extern "C" void __libc_free(void *ptr); extern "C" int mallopt(int param, int value); -extern void *stdout, *stderr; +extern __sanitizer_FILE *stdout, *stderr; const int PTHREAD_MUTEX_RECURSIVE = 1; const int PTHREAD_MUTEX_RECURSIVE_NP = 1; const int EINVAL = 22; @@ -1621,19 +1622,6 @@ TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { return res; } -TSAN_INTERCEPTOR(int, fclose, void *stream) { - // libc file streams can call user-supplied functions, see fopencookie. - { - SCOPED_TSAN_INTERCEPTOR(fclose, stream); - if (stream) { - int fd = fileno_unlocked(stream); - if (fd >= 0) - FdClose(thr, pc, fd); - } - } - return REAL(fclose)(stream); -} - TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { // libc file streams can call user-supplied functions, see fopencookie. { @@ -1652,14 +1640,6 @@ TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { return REAL(fwrite)(p, size, nmemb, f); } -TSAN_INTERCEPTOR(int, fflush, void *stream) { - // libc file streams can call user-supplied functions, see fopencookie. - { - SCOPED_TSAN_INTERCEPTOR(fflush, stream); - } - return REAL(fflush)(stream); -} - TSAN_INTERCEPTOR(void, abort, int fake) { SCOPED_TSAN_INTERCEPTOR(abort, fake); REAL(fflush)(0); @@ -2367,10 +2347,8 @@ void InitializeInterceptors() { TSAN_INTERCEPT(unlink); TSAN_INTERCEPT(tmpfile); TSAN_INTERCEPT(tmpfile64); - TSAN_INTERCEPT(fclose); TSAN_INTERCEPT(fread); TSAN_INTERCEPT(fwrite); - TSAN_INTERCEPT(fflush); TSAN_INTERCEPT(abort); TSAN_INTERCEPT(puts); TSAN_INTERCEPT(rmdir); |