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_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -O3 %s -o %t 6// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s 7 8// Fun fact: if test output is redirected to a file (as opposed to 9// being piped directly to FileCheck), we may lose some "done"s due to 10// a kernel bug: 11// https://lkml.org/lkml/2014/2/17/324 12 13 14#include <pthread.h> 15#include <unistd.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <sys/types.h> 19#include <sys/wait.h> 20#include <sys/time.h> 21#include <signal.h> 22#include <errno.h> 23 24#include <sanitizer/msan_interface.h> 25 26int done; 27 28void copy_uninit_thread2() { 29 volatile int x; 30 volatile int v; 31 while (true) { 32 v = x; 33 x = v; 34 if (__atomic_load_n(&done, __ATOMIC_RELAXED)) 35 return; 36 } 37} 38 39void copy_uninit_thread1(int level) { 40 if (!level) 41 copy_uninit_thread2(); 42 else 43 copy_uninit_thread1(level - 1); 44} 45 46void *copy_uninit_thread(void *id) { 47 copy_uninit_thread1((long)id); 48 return 0; 49} 50 51// Run through stackdepot in the child process. 52// If any of the hash table cells are locked, this may deadlock. 53void child() { 54 volatile int x; 55 volatile int v; 56 for (int i = 0; i < 10000; ++i) { 57 v = x; 58 x = v; 59 } 60 write(2, "done\n", 5); 61} 62 63void 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_uninit_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 } else { 76 // child 77 child(); 78 } 79} 80 81int main() { 82 const int kChildren = 20; 83 for (int i = 0; i < kChildren; ++i) { 84 pid_t pid = fork(); 85 if (pid) { 86 // parent 87 } else { 88 test(); 89 exit(0); 90 } 91 } 92 93 for (int i = 0; i < kChildren; ++i) { 94 pid_t p; 95 while ((p = wait(NULL)) == -1) { } 96 } 97 98 return 0; 99} 100 101// Expect 20 (== kChildren) "done" messages. 102// CHECK: done 103// CHECK: done 104// CHECK: done 105// CHECK: done 106// CHECK: done 107// CHECK: done 108// CHECK: done 109// CHECK: done 110// CHECK: done 111// CHECK: done 112// CHECK: done 113// CHECK: done 114// CHECK: done 115// CHECK: done 116// CHECK: done 117// CHECK: done 118// CHECK: done 119// CHECK: done 120// CHECK: done 121// CHECK: done 122