• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // RUN: %clang_scudo %s -o %t
2 // RUN: %run %t 2>&1
3 
4 #include <locale.h>
5 #include <pthread.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
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.
19 
20 // This test reproduces those circumstances. Success means executing without
21 // a segmentation fault.
22 
23 const int kNumThreads = 16;
24 pthread_t tid[kNumThreads];
25 
thread_func(void * arg)26 void *thread_func(void *arg) {
27   uintptr_t i = (uintptr_t)arg;
28   if ((i & 1) == 0)
29     free(malloc(16));
30   // Calling strerror_l allows for strerror_thread_freeres to be called.
31   strerror_l(0, LC_GLOBAL_LOCALE);
32   return 0;
33 }
34 
main(int argc,char ** argv)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);
41   }
42   return 0;
43 }
44