1 // Test that chained origins are fork-safe. 2 // Run a number of threads that create new chained origins, then fork 3 // and verify that origin reads do not deadlock in the child process. 4 // 5 // RUN: %clangxx_dfsan %s -o %t 6 // RUN: %run %t 2>&1 | FileCheck %s 7 // 8 // RUN: %clangxx_dfsan -mllvm -dfsan-track-origins=1 %s -o %t 9 // RUN: env DFSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t 2>&1 | FileCheck %s 10 11 #include <assert.h> 12 #include <errno.h> 13 #include <pthread.h> 14 #include <signal.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <sys/time.h> 18 #include <sys/types.h> 19 #include <sys/wait.h> 20 #include <unistd.h> 21 22 #include <sanitizer/dfsan_interface.h> 23 24 int done; 25 26 void copy_labels_thread2() { 27 volatile int x = 0; 28 volatile int v = 0; 29 dfsan_set_label(8, (void *)&x, sizeof(x)); 30 while (true) { 31 v = x; 32 x = v; 33 if (__atomic_load_n(&done, __ATOMIC_RELAXED)) 34 return; 35 } 36 } 37 38 void copy_labels_thread1(int level) { 39 if (!level) 40 copy_labels_thread2(); 41 else 42 copy_labels_thread1(level - 1); 43 } 44 45 void *copy_labels_thread(void *id) { 46 copy_labels_thread1((long)id); 47 return 0; 48 } 49 50 // Run through stackdepot in the child process. 51 // If any of the hash table cells are locked, this may deadlock. 52 void child() { 53 volatile int x = 0; 54 volatile int v = 0; 55 dfsan_set_label(16, (void *)&x, sizeof(x)); 56 for (int i = 0; i < 10000; ++i) { 57 v = x; 58 x = v; 59 } 60 write(2, "done\n", 5); 61 } 62 63 void test() { 64 const int kThreads = 10; 65 pthread_t t[kThreads]; 66 for (int i = 0; i < kThreads; ++i) 67 pthread_create(&t[i], NULL, copy_labels_thread, (void *)(long)i); 68 usleep(100000); 69 pid_t pid = fork(); 70 if (pid) { 71 // parent 72 __atomic_store_n(&done, 1, __ATOMIC_RELAXED); 73 pid_t p; 74 while ((p = wait(NULL)) == -1) { 75 } 76 } else { 77 // child 78 child(); 79 } 80 } 81 82 int main() { 83 const int kChildren = 20; 84 for (int i = 0; i < kChildren; ++i) { 85 pid_t pid = fork(); 86 assert(dfsan_get_label(pid) == 0); 87 if (pid) { 88 // parent 89 } else { 90 test(); 91 exit(0); 92 } 93 } 94 95 for (int i = 0; i < kChildren; ++i) { 96 pid_t p; 97 while ((p = wait(NULL)) == -1) { 98 } 99 } 100 101 return 0; 102 } 103 104 // Expect 20 (== kChildren) "done" messages. 105 // CHECK-COUNT-20: done 106