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