llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-compiler-rt-sanitizer Author: Vitaly Buka (vitalybuka) <details> <summary>Changes</summary> When a detached thread calls dlsym for a missing symbol, glibc allocates a dl_action_result buffer stored in TLS (__libc_dlerror_result) and frees it during __libc_thread_freeres(), which runs after __nptl_deallocate_tsd(). Because the sanitizer's TSD destructor unregisters the thread during __nptl_deallocate_tsd(), LSan stops scanning that thread's TLS before __libc_thread_freeres() runs, relying on the default *dlerror* suppression or reporting a false positive leak when _dlerror_run is not symbolized. Assisted-by: Gemini --- Full diff: https://github.com/llvm/llvm-project/pull/228929.diff 1 Files Affected: - (added) compiler-rt/test/lsan/TestCases/Linux/detached_thread_dlsym.c (+60) ``````````diff diff --git a/compiler-rt/test/lsan/TestCases/Linux/detached_thread_dlsym.c b/compiler-rt/test/lsan/TestCases/Linux/detached_thread_dlsym.c new file mode 100644 index 0000000000000..374ae1dfc30e8 --- /dev/null +++ b/compiler-rt/test/lsan/TestCases/Linux/detached_thread_dlsym.c @@ -0,0 +1,60 @@ +// Test that TLS allocations (such as glibc's internal dlerror buffer from a +// failed dlsym call, freed in __libc_thread_freeres) on a dying detached +// thread are not falsely reported as leaks if leak checking runs after the +// sanitizer's TSD destructor has executed. +// +// RUN: %clang_lsan %s -ldl -pthread -o %t && %run %t + +#define _GNU_SOURCE +#include <assert.h> +#include <dlfcn.h> +#include <limits.h> +#include <pthread.h> +#include <stdatomic.h> +#include <stdint.h> +#include <unistd.h> + +static pthread_key_t key; +static atomic_int ready = 0; + +static void key_destructor(void *arg) { + uintptr_t iter = (uintptr_t)arg; + if (iter > 1) { + int res = pthread_setspecific(key, (void *)(iter - 1)); + assert(res == 0); + return; + } + // On the last iteration (PTHREAD_DESTRUCTOR_ITERATIONS), the sanitizer's TSD + // destructor (registered earlier with a lower key index) has already run, + // while glibc's __libc_thread_freeres() has not yet freed the dlerror buffer. + atomic_store(&ready, 1); + sleep(10); +} + +static void *thread_func(void *arg) { + dlsym(RTLD_DEFAULT, "nonexistent_symbol_12345"); + int res = pthread_setspecific(key, (void *)PTHREAD_DESTRUCTOR_ITERATIONS); + assert(res == 0); + return NULL; +} + +int main(void) { + int res = pthread_key_create(&key, key_destructor); + assert(res == 0); + + pthread_attr_t attr; + res = pthread_attr_init(&attr); + assert(res == 0); + res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + assert(res == 0); + + pthread_t th; + res = pthread_create(&th, &attr, thread_func, NULL); + assert(res == 0); + pthread_attr_destroy(&attr); + + while (!atomic_load(&ready)) + sched_yield(); + + return 0; +} `````````` </details> https://github.com/llvm/llvm-project/pull/228929 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
