1 // RUN: %clang_scudo %s -o %t
10 // Some of glibc's own thread local data is destroyed after a user's thread
11 // local destructors are called, via __libc_thread_freeres. This might involve
12 // calling free, as is the case for strerror_thread_freeres.
13 // If there is no prior heap operation in the thread, this free would end up
14 // initializing some thread specific data that would never be destroyed
15 // properly, while still being deallocated when the TLS goes away. As a result,
16 // a program could SEGV, usually in
17 // __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly
18 // linked list links would refer to a now unmapped memory area.
20 // This test reproduces those circumstances. Success means executing without
21 // a segmentation fault.
23 const int kNumThreads
= 16;
24 pthread_t tid
[kNumThreads
];
26 void *thread_func(void *arg
) {
27 uintptr_t i
= (uintptr_t)arg
;
30 // Calling strerror_l allows for strerror_thread_freeres to be called.
31 strerror_l(0, LC_GLOBAL_LOCALE
);
35 int main(int argc
, char **argv
) {
36 for (uintptr_t j
= 0; j
< 8; j
++) {
37 for (uintptr_t i
= 0; i
< kNumThreads
; i
++)
38 pthread_create(&tid
[i
], 0, thread_func
, (void *)i
);
39 for (uintptr_t i
= 0; i
< kNumThreads
; i
++)
40 pthread_join(tid
[i
], 0);