1 // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2 // REQUIRES: linux
3 #include "test.h"
4 
5 #include <pthread.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 
count_memory_mappings()9 long count_memory_mappings() {
10   pid_t my_pid = getpid();
11   char proc_file_name[128];
12   snprintf(proc_file_name, sizeof(proc_file_name), "/proc/%d/maps", my_pid);
13 
14   FILE *proc_file = fopen(proc_file_name, "r");
15   long line_count = 0;
16   int c;
17   do {
18     c = fgetc(proc_file);
19     if (c == '\n') {
20       line_count++;
21     }
22   } while (c != EOF);
23   fclose(proc_file);
24 
25   return line_count;
26 }
27 
fiber_iteration()28 void fiber_iteration() {
29   void *orig_fiber = __tsan_get_current_fiber();
30   void *fiber = __tsan_create_fiber(0);
31 
32   pthread_mutex_t mutex;
33   pthread_mutex_init(&mutex, NULL);
34 
35   // Running some code on the fiber that triggers handling of pending signals.
36   __tsan_switch_to_fiber(fiber, 0);
37   pthread_mutex_lock(&mutex);
38   pthread_mutex_unlock(&mutex);
39   __tsan_switch_to_fiber(orig_fiber, 0);
40 
41   // We expect the fiber to clean up all resources (here the sigcontext) when destroyed.
42   __tsan_destroy_fiber(fiber);
43 }
44 
45 // Magic-Number for some warmup iterations,
46 // as tsan maps some memory for the first runs.
47 const size_t num_warmup = 100;
48 
main()49 int main() {
50   for (size_t i = 0; i < num_warmup; i++) {
51     fiber_iteration();
52   }
53 
54   long memory_mappings_before = count_memory_mappings();
55   fiber_iteration();
56   fiber_iteration();
57   long memory_mappings_after = count_memory_mappings();
58 
59   // Is there a better way to detect a resource  leak in the
60   // ThreadState object? (i.e. a mmap not being freed)
61   if (memory_mappings_before == memory_mappings_after) {
62     fprintf(stderr, "PASS\n");
63   } else {
64     fprintf(stderr, "FAILED\n");
65   }
66 
67   return 0;
68 }
69 
70 // CHECK-NOT: WARNING: ThreadSanitizer:
71 // CHECK: PASS
72