diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -476,6 +476,15 @@ return res; } +INTERCEPTOR(int, pthread_detach, void *th) { + ENSURE_LSAN_INITED; + int tid = ThreadTid((uptr)th); + int res = REAL(pthread_detach)(th); + if (res == 0) + ThreadDetach(tid); + return res; +} + INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; REAL(_exit)(status); @@ -508,6 +517,7 @@ LSAN_MAYBE_INTERCEPT_MALLINFO; LSAN_MAYBE_INTERCEPT_MALLOPT; INTERCEPT_FUNCTION(pthread_create); + INTERCEPT_FUNCTION(pthread_detach); INTERCEPT_FUNCTION(pthread_join); INTERCEPT_FUNCTION(_exit); diff --git a/compiler-rt/lib/lsan/lsan_thread.h b/compiler-rt/lib/lsan/lsan_thread.h --- a/compiler-rt/lib/lsan/lsan_thread.h +++ b/compiler-rt/lib/lsan/lsan_thread.h @@ -46,6 +46,7 @@ u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg = nullptr); void ThreadFinish(); +void ThreadDetach(u32 tid); void ThreadJoin(u32 tid); u32 ThreadTid(uptr uid); diff --git a/compiler-rt/lib/lsan/lsan_thread.cpp b/compiler-rt/lib/lsan/lsan_thread.cpp --- a/compiler-rt/lib/lsan/lsan_thread.cpp +++ b/compiler-rt/lib/lsan/lsan_thread.cpp @@ -83,6 +83,11 @@ return thread_registry->FindThread(FindThreadByUid, (void *)uid); } +void ThreadDetach(u32 tid) { + CHECK_NE(tid, kInvalidTid); + thread_registry->DetachThread(tid, /* arg */ nullptr); +} + void ThreadJoin(u32 tid) { CHECK_NE(tid, kInvalidTid); thread_registry->JoinThread(tid, /* arg */ nullptr); diff --git a/compiler-rt/test/lsan/TestCases/many_threads_detach.cpp b/compiler-rt/test/lsan/TestCases/many_threads_detach.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/lsan/TestCases/many_threads_detach.cpp @@ -0,0 +1,23 @@ +// Test that threads are reused. +// RUN: %clangxx_lsan %s -o %t -lpthread && %run %t + +#include +#include + +// Number of threads to create. This value is greater than kMaxThreads in +// lsan_thread.cpp so that we can test that thread contexts are not being +// reused. +static const size_t kTestThreads = 10000; + +void *null_func(void *args) { + return NULL; +} + +int main(void) { + for (size_t i = 0; i < kTestThreads; i++) { + pthread_t thread; + pthread_create(&thread, NULL, null_func, NULL); + pthread_detach(thread); + } + return 0; +}