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 | 9f20c9b17c7da2339efe03782943375063589080 (patch) | |
tree | a364b97639d40710e64a0c918bc292bcd3cf89aa /compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc | |
parent | 85d6a16c46616336c52792e7a490e70ea8b6461e (diff) | |
download | bcm5719-llvm-9f20c9b17c7da2339efe03782943375063589080.tar.gz bcm5719-llvm-9f20c9b17c7da2339efe03782943375063589080.zip |
[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
llvm-svn: 205617
Diffstat (limited to 'compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc')
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc | 48 |
1 files changed, 27 insertions, 21 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc index 2f0d3608f47..82cd4c075ad 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/compiler-rt/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; } |