summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlexey Samsonov <vonosmas@gmail.com>2016-01-16 00:57:25 +0000
committerAlexey Samsonov <vonosmas@gmail.com>2016-01-16 00:57:25 +0000
commit5ae106268eb3099c79114ba306a5bf33d36bd32b (patch)
tree03bc1da15fceb24c7ee288e0892871117cbdd75b /lib
parent4198b77a82619d06267267bc8944a47ef1db9fbe (diff)
[LSan] Ignore all allocations made inside pthread_create.
Thread stack/TLS may be stored by libpthread for future reuse 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. With this change applied, LSan test suite passes with "use_ld_allocations" flag defaulted to "false". It still requires more testing to check if the default can be switched. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@257975 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/asan/asan_interceptors.cc13
-rw-r--r--lib/lsan/lsan_common.cc16
-rw-r--r--lib/lsan/lsan_common.h10
-rw-r--r--lib/lsan/lsan_interceptors.cc11
4 files changed, 42 insertions, 8 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(&param.t, 0, memory_order_relaxed);
atomic_store(&param.is_registered, 0, memory_order_relaxed);
- int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+ 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, &param);
+ }
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);