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