diff options
author | Kostya Serebryany <kcc@google.com> | 2014-04-04 09:10:58 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@google.com> | 2014-04-04 09:10:58 +0000 |
commit | 8dc0d7f875b37003ce805dfe04c88bee3f02a6b8 (patch) | |
tree | 6d88d3e02c4c9e348ab9cb098d95f317ee6aa909 /lib/sanitizer_common | |
parent | 9b9e4c998fc000f5d5120fb1d9c343ee8479ec38 (diff) | |
download | compiler-rt-8dc0d7f875b37003ce805dfe04c88bee3f02a6b8.tar.gz |
[asan] fix a leak in __tls_get_addr handler; introduce a run-time flag to disable this handler completely; remove a workaround for a bug fixed in glibc
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@205617 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r-- | lib/sanitizer_common/sanitizer_flags.cc | 3 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_flags.h | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_tls_get_addr.cc | 48 |
3 files changed, 31 insertions, 21 deletions
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc index 3d809e739..e44d04f55 100644 --- a/lib/sanitizer_common/sanitizer_flags.cc +++ b/lib/sanitizer_common/sanitizer_flags.cc @@ -53,6 +53,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) { f->clear_shadow_mmap_threshold = 64 * 1024; f->color = "auto"; f->legacy_pthread_cond = false; + f->intercept_tls_get_addr = false; } void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { @@ -115,6 +116,8 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { "Colorize reports: (always|never|auto)."); ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond", "Enables support for dynamic libraries linked with libpthread 2.2.5."); + ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr", + "Intercept __tls_get_addr."); ParseFlag(str, &f->help, "help", "Print the flag descriptions."); // Do a sanity check for certain flags. diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h index 627040173..25dd887a8 100644 --- a/lib/sanitizer_common/sanitizer_flags.h +++ b/lib/sanitizer_common/sanitizer_flags.h @@ -50,6 +50,7 @@ struct CommonFlags { uptr clear_shadow_mmap_threshold; const char *color; bool legacy_pthread_cond; + bool intercept_tls_get_addr; bool help; }; diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index 2f0d3608f..82cd4c075 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -43,30 +43,41 @@ static atomic_uintptr_t number_of_live_dtls; static const uptr kDestroyedThread = -1; +static inline void DTLS_Deallocate(uptr size) { + if (!size) return; + VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", &dtls, size); + UnmapOrDie(dtls.dtv, size * sizeof(DTLS::DTV)); + atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); +} + static inline void DTLS_Resize(uptr new_size) { if (dtls.dtv_size >= new_size) return; new_size = RoundUpToPowerOfTwo(new_size); new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV)); DTLS::DTV *new_dtv = (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize"); - CHECK_LT(atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed), - 1 << 20); - if (dtls.dtv_size) + uptr num_live_dtls = + atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); + VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); + CHECK_LT(num_live_dtls, 1 << 20); + if (dtls.dtv_size) { internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV)); - DTLS_Destroy(); + DTLS_Deallocate(dtls.dtv_size); + } dtls.dtv = new_dtv; dtls.dtv_size = new_size; } void DTLS_Destroy() { - if (!dtls.dtv_size) return; + if (!common_flags()->intercept_tls_get_addr) return; + VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); uptr s = dtls.dtv_size; dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety. - UnmapOrDie(dtls.dtv, s * sizeof(DTLS::DTV)); - atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); + DTLS_Deallocate(s); } void DTLS_on_tls_get_addr(void *arg_void, void *res) { + if (!common_flags()->intercept_tls_get_addr) return; TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void); uptr dso_id = arg->dso_id; if (dtls.dtv_size == kDestroyedThread) return; @@ -75,29 +86,23 @@ void DTLS_on_tls_get_addr(void *arg_void, void *res) { return; uptr tls_size = 0; uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset; - // This function uses the fancy 2147483647 verbosity level, - // because printing in this function crashes with some versions of libstdc++ - // because of the following bug: - // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 - // The bug leads to mis-aligned stack in this function, and subsequently - // SSE instructions in Printf crash. - // But there is a test that searches for printfs from this function. - // The bug can affect any code, so do as less as possible here. - VPrintf(2147483647, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p\n", - arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg); + VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " + "num_live_dtls %zd\n", + arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, + atomic_load(&number_of_live_dtls, memory_order_relaxed)); if (dtls.last_memalign_ptr == tls_beg) { tls_size = dtls.last_memalign_size; - VPrintf(2147483647, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", + VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", tls_beg, tls_size); } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { // We may want to check gnu_get_libc_version(). Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; tls_size = header->size; tls_beg = header->start; - VPrintf(2147483647, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", + VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", tls_beg, tls_size); } else { - VPrintf(2147483647, "__tls_get_addr: Can't guess glibc version\n"); + VPrintf(2, "__tls_get_addr: Can't guess glibc version\n"); // This may happen inside the DTOR of main thread, so just ignore it. tls_size = 0; } @@ -106,7 +111,8 @@ void DTLS_on_tls_get_addr(void *arg_void, void *res) { } void DTLS_on_libc_memalign(void *ptr, uptr size) { - VPrintf(2147483647, "DTLS_on_libc_memalign: %p %p\n", ptr, size); + if (!common_flags()->intercept_tls_get_addr) return; + VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size); dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr); dtls.last_memalign_size = size; } |