1d21b3d34SFangrui Song // Test that chained origins are fork-safe. 2d21b3d34SFangrui Song // Run a number of threads that create new chained origins, then fork 3d21b3d34SFangrui Song // and verify that origin reads do not deadlock in the child process. 4d21b3d34SFangrui Song 5d21b3d34SFangrui Song // RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -O3 %s -o %t 6*643a2080SHarini0924 // RUN: env MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t 2>&1 | FileCheck %s 7d21b3d34SFangrui Song 8d21b3d34SFangrui Song // Fun fact: if test output is redirected to a file (as opposed to 9d21b3d34SFangrui Song // being piped directly to FileCheck), we may lose some "done"s due to 10d21b3d34SFangrui Song // a kernel bug: 11d21b3d34SFangrui Song // https://lkml.org/lkml/2014/2/17/324 12d21b3d34SFangrui Song 13d21b3d34SFangrui Song // Flaky on PPC64. 14d21b3d34SFangrui Song // UNSUPPORTED: powerpc64-target-arch 15d21b3d34SFangrui Song // UNSUPPORTED: powerpc64le-target-arch 16d21b3d34SFangrui Song 17d21b3d34SFangrui Song // Sometimes hangs 1802012a78SPaul Robinson // UNSUPPORTED: target={{.*netbsd.*}} 19d21b3d34SFangrui Song 20d21b3d34SFangrui Song #include <pthread.h> 21d21b3d34SFangrui Song #include <unistd.h> 22d21b3d34SFangrui Song #include <stdio.h> 23d21b3d34SFangrui Song #include <stdlib.h> 24d21b3d34SFangrui Song #include <sys/types.h> 25d21b3d34SFangrui Song #include <sys/wait.h> 26d21b3d34SFangrui Song #include <sys/time.h> 27d21b3d34SFangrui Song #include <signal.h> 28d21b3d34SFangrui Song #include <errno.h> 29d21b3d34SFangrui Song 30d21b3d34SFangrui Song #include <sanitizer/msan_interface.h> 31d21b3d34SFangrui Song 32d21b3d34SFangrui Song int done; 33d21b3d34SFangrui Song 34d21b3d34SFangrui Song void copy_uninit_thread2() { 35d21b3d34SFangrui Song volatile int x; 36d21b3d34SFangrui Song volatile int v; 37d21b3d34SFangrui Song while (true) { 38d21b3d34SFangrui Song v = x; 39d21b3d34SFangrui Song x = v; 40d21b3d34SFangrui Song if (__atomic_load_n(&done, __ATOMIC_RELAXED)) 41d21b3d34SFangrui Song return; 42d21b3d34SFangrui Song } 43d21b3d34SFangrui Song } 44d21b3d34SFangrui Song 45d21b3d34SFangrui Song void copy_uninit_thread1(int level) { 46d21b3d34SFangrui Song if (!level) 47d21b3d34SFangrui Song copy_uninit_thread2(); 48d21b3d34SFangrui Song else 49d21b3d34SFangrui Song copy_uninit_thread1(level - 1); 50d21b3d34SFangrui Song } 51d21b3d34SFangrui Song 52d21b3d34SFangrui Song void *copy_uninit_thread(void *id) { 53d21b3d34SFangrui Song copy_uninit_thread1((long)id); 54d21b3d34SFangrui Song return 0; 55d21b3d34SFangrui Song } 56d21b3d34SFangrui Song 57d21b3d34SFangrui Song // Run through stackdepot in the child process. 58d21b3d34SFangrui Song // If any of the hash table cells are locked, this may deadlock. 59d21b3d34SFangrui Song void child() { 60d21b3d34SFangrui Song volatile int x; 61d21b3d34SFangrui Song volatile int v; 62d21b3d34SFangrui Song for (int i = 0; i < 10000; ++i) { 63d21b3d34SFangrui Song v = x; 64d21b3d34SFangrui Song x = v; 65d21b3d34SFangrui Song } 66d21b3d34SFangrui Song write(2, "done\n", 5); 67d21b3d34SFangrui Song } 68d21b3d34SFangrui Song 69d21b3d34SFangrui Song void test() { 70d21b3d34SFangrui Song const int kThreads = 10; 71d21b3d34SFangrui Song pthread_t t[kThreads]; 72d21b3d34SFangrui Song for (int i = 0; i < kThreads; ++i) 73d21b3d34SFangrui Song pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i); 74d21b3d34SFangrui Song usleep(100000); 75d21b3d34SFangrui Song pid_t pid = fork(); 76d21b3d34SFangrui Song if (pid) { 77d21b3d34SFangrui Song // parent 78d21b3d34SFangrui Song __atomic_store_n(&done, 1, __ATOMIC_RELAXED); 79d21b3d34SFangrui Song pid_t p; 80d21b3d34SFangrui Song while ((p = wait(NULL)) == -1) { } 81d21b3d34SFangrui Song } else { 82d21b3d34SFangrui Song // child 83d21b3d34SFangrui Song child(); 84d21b3d34SFangrui Song } 85d21b3d34SFangrui Song } 86d21b3d34SFangrui Song 87d21b3d34SFangrui Song int main() { 88d21b3d34SFangrui Song const int kChildren = 20; 89d21b3d34SFangrui Song for (int i = 0; i < kChildren; ++i) { 90d21b3d34SFangrui Song pid_t pid = fork(); 91d21b3d34SFangrui Song if (pid) { 92d21b3d34SFangrui Song // parent 93d21b3d34SFangrui Song } else { 94d21b3d34SFangrui Song test(); 95d21b3d34SFangrui Song exit(0); 96d21b3d34SFangrui Song } 97d21b3d34SFangrui Song } 98d21b3d34SFangrui Song 99d21b3d34SFangrui Song for (int i = 0; i < kChildren; ++i) { 100d21b3d34SFangrui Song pid_t p; 101d21b3d34SFangrui Song while ((p = wait(NULL)) == -1) { } 102d21b3d34SFangrui Song } 103d21b3d34SFangrui Song 104d21b3d34SFangrui Song return 0; 105d21b3d34SFangrui Song } 106d21b3d34SFangrui Song 107d21b3d34SFangrui Song // Expect 20 (== kChildren) "done" messages. 108d21b3d34SFangrui Song // CHECK: done 109d21b3d34SFangrui Song // CHECK: done 110d21b3d34SFangrui Song // CHECK: done 111d21b3d34SFangrui Song // CHECK: done 112d21b3d34SFangrui Song // CHECK: done 113d21b3d34SFangrui Song // CHECK: done 114d21b3d34SFangrui Song // CHECK: done 115d21b3d34SFangrui Song // CHECK: done 116d21b3d34SFangrui Song // CHECK: done 117d21b3d34SFangrui Song // CHECK: done 118d21b3d34SFangrui Song // CHECK: done 119d21b3d34SFangrui Song // CHECK: done 120d21b3d34SFangrui Song // CHECK: done 121d21b3d34SFangrui Song // CHECK: done 122d21b3d34SFangrui Song // CHECK: done 123d21b3d34SFangrui Song // CHECK: done 124d21b3d34SFangrui Song // CHECK: done 125d21b3d34SFangrui Song // CHECK: done 126d21b3d34SFangrui Song // CHECK: done 127d21b3d34SFangrui Song // CHECK: done 128