44 lines · c
1// RUN: %clang_scudo %s -o %t2// RUN: %run %t 2>&13 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 thread11// local destructors are called, via __libc_thread_freeres. This might involve12// 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 up14// initializing some thread specific data that would never be destroyed15// properly, while still being deallocated when the TLS goes away. As a result,16// a program could SEGV, usually in17// __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly18// linked list links would refer to a now unmapped memory area.19 20// This test reproduces those circumstances. Success means executing without21// a segmentation fault.22 23const int kNumThreads = 16;24pthread_t tid[kNumThreads];25 26void *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 35int 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