diff options
-rw-r--r-- | lib/asan/asan_interceptors.cc | 13 | ||||
-rw-r--r-- | lib/lsan/lsan_common.cc | 16 | ||||
-rw-r--r-- | lib/lsan/lsan_common.h | 10 | ||||
-rw-r--r-- | lib/lsan/lsan_interceptors.cc | 11 | ||||
-rw-r--r-- | test/lsan/TestCases/disabler_in_tsd_destructor.c | 2 | ||||
-rw-r--r-- | test/lsan/TestCases/high_allocator_contention.cc | 3 |
6 files changed, 45 insertions, 10 deletions
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index d9a0c71a0..712b6b92d 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -21,6 +21,7 @@ #include "asan_stack.h" #include "asan_stats.h" #include "asan_suppressions.h" +#include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" #if SANITIZER_POSIX @@ -242,7 +243,17 @@ INTERCEPTOR(int, pthread_create, void *thread, ThreadStartParam param; atomic_store(¶m.t, 0, memory_order_relaxed); atomic_store(¶m.is_registered, 0, memory_order_relaxed); - int result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); + int result; + { + // Ignore all allocations made by pthread_create: thread stack/TLS may be + // stored by pthread for future reuse even after thread destruction, and + // the linked list it's stored in doesn't even hold valid pointers to the + // objects, the latter are calculated by obscure pointer arithmetic. +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif + result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); + } if (result == 0) { u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a7eab15b8..0385c37ac 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -34,6 +34,14 @@ BlockingMutex global_mutex(LINKER_INITIALIZED); THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } +void DisableInThisThread() { disable_counter++; } +void EnableInThisThread() { + if (!disable_counter && common_flags()->detect_leaks) { + Report("Unmatched call to __lsan_enable().\n"); + Die(); + } + disable_counter--; +} Flags lsan_flags; @@ -695,18 +703,14 @@ void __lsan_unregister_root_region(const void *begin, uptr size) { SANITIZER_INTERFACE_ATTRIBUTE void __lsan_disable() { #if CAN_SANITIZE_LEAKS - __lsan::disable_counter++; + __lsan::DisableInThisThread(); #endif } SANITIZER_INTERFACE_ATTRIBUTE void __lsan_enable() { #if CAN_SANITIZE_LEAKS - if (!__lsan::disable_counter && common_flags()->detect_leaks) { - Report("Unmatched call to __lsan_enable().\n"); - Die(); - } - __lsan::disable_counter--; + __lsan::EnableInThisThread(); #endif } diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index e09151e8c..890ce6562 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -119,6 +119,16 @@ void InitCommonLsan(); void DoLeakCheck(); bool DisabledInThisThread(); +// Used to implement __lsan::ScopedDisabler. +void DisableInThisThread(); +void EnableInThisThread(); +// Can be used to ignore memory allocated by an intercepted +// function. +struct ScopedInterceptorDisabler { + ScopedInterceptorDisabler() { DisableInThisThread(); } + ~ScopedInterceptorDisabler() { EnableInThisThread(); } +}; + // Special case for "new T[0]" where T is a type with DTOR. // new T[0] will allocate one word for the array size (0) and store a pointer // to the end of allocated chunk. diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 5921e06ab..28f1786ed 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -23,6 +23,7 @@ #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" +#include "lsan_common.h" #include "lsan_thread.h" using namespace __lsan; @@ -241,7 +242,15 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, p.callback = callback; p.param = param; atomic_store(&p.tid, 0, memory_order_relaxed); - int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); + int res; + { + // Ignore all allocations made by pthread_create: thread stack/TLS may be + // stored by pthread for future reuse even after thread destruction, and + // the linked list it's stored in doesn't even hold valid pointers to the + // objects, the latter are calculated by obscure pointer arithmetic. + ScopedInterceptorDisabler disabler; + res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); + } if (res == 0) { int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached); CHECK_NE(tid, 0); diff --git a/test/lsan/TestCases/disabler_in_tsd_destructor.c b/test/lsan/TestCases/disabler_in_tsd_destructor.c index 982fb899e..4a3a7ac14 100644 --- a/test/lsan/TestCases/disabler_in_tsd_destructor.c +++ b/test/lsan/TestCases/disabler_in_tsd_destructor.c @@ -1,5 +1,5 @@ // Regression test. Disabler should not depend on TSD validity. -// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1" +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1:use_ld_allocations=0" // RUN: %clang_lsan %s -o %t // RUN: LSAN_OPTIONS=$LSAN_BASE %run %t diff --git a/test/lsan/TestCases/high_allocator_contention.cc b/test/lsan/TestCases/high_allocator_contention.cc index 2543897bc..f423fd48c 100644 --- a/test/lsan/TestCases/high_allocator_contention.cc +++ b/test/lsan/TestCases/high_allocator_contention.cc @@ -1,7 +1,8 @@ // A benchmark that executes malloc/free pairs in parallel. // Usage: ./a.out number_of_threads total_number_of_allocations +// RUN: LSAN_BASE="use_ld_allocations=0" // RUN: %clangxx_lsan %s -o %t -// RUN: %run %t 5 1000000 2>&1 +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 5 1000000 2>&1 #include <assert.h> #include <pthread.h> #include <stdlib.h> |