1 // RUN: %clang -O0 %s -o %t && %env_tool_opts=die_after_fork=0 %run %t 2 3 // The test uses pthread barriers which are not available on Darwin. 4 // UNSUPPORTED: darwin 5 6 // FIXME: It probably hangs on this platform. 7 // UNSUPPORTED: ppc 8 9 // FIXME: False stack overflow report 10 // UNSUPPORTED: android && asan 11 12 // FIXME: Requires `FutexWait` implementation. See __asan::InstallAtForkHandler. 13 // UNSUPPORTED: target={{.*solaris.*}} 14 // UNSUPPORTED: target={{.*netbsd.*}} 15 // UNSUPPORTED: target={{.*apple.*}} 16 17 // Forking in multithread environment is unsupported. However we already have 18 // some workarounds, and will add more, so this is the test. 19 // The test try to check two things: 20 // 1. Internal mutexes used by `inparent` thread do not deadlock `inchild` 21 // thread. 22 // 2. Stack poisoned by `inparent` is not poisoned in `inchild` thread. 23 24 // Stack tagging is unsupported. 25 // UNSUPPORTED: hwasan-aliasing 26 27 #include <assert.h> 28 #include <pthread.h> 29 #include <stdint.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <sys/types.h> 33 #include <sys/wait.h> 34 #include <unistd.h> 35 36 #include "sanitizer_common/sanitizer_specific.h" 37 38 static const size_t kBufferSize = 8192; 39 40 pthread_barrier_t bar; 41 42 // Without appropriate workarounds this code can cause the forked process to 43 // start with locked internal mutexes. 44 void ShouldNotDeadlock() { 45 // Don't bother with leaks, we try to trigger allocator or lsan deadlock. 46 __lsan_disable(); 47 void *volatile p = malloc(10); 48 __lsan_do_recoverable_leak_check(); 49 // Allocator still in broken state, `free` may report errors. 50 // free(p); 51 __lsan_enable(); 52 } 53 54 // Prevent stack buffer cleanup by instrumentation. 55 #define NOSAN __attribute__((no_sanitize("address", "hwaddress", "memory"))) 56 57 NOSAN static void *inparent(void *arg) { 58 char t[kBufferSize]; 59 make_mem_bad(t, sizeof(t)); 60 61 pthread_barrier_wait(&bar); 62 63 for (;;) 64 ShouldNotDeadlock(); 65 66 return 0; 67 } 68 69 NOSAN static void *inchild(void *arg) { 70 char t[kBufferSize]; 71 check_mem_is_good(t, sizeof(t)); 72 ShouldNotDeadlock(); 73 return 0; 74 } 75 76 int main(void) { 77 #if __has_feature(hwaddress_sanitizer) 78 __hwasan_enable_allocator_tagging(); 79 #endif 80 81 pid_t pid; 82 83 pthread_barrier_init(&bar, NULL, 2); 84 pthread_t thread_id; 85 while (pthread_create(&thread_id, 0, &inparent, 0) != 0) { 86 } 87 pthread_barrier_wait(&bar); 88 89 pid = fork(); 90 switch (pid) { 91 case -1: 92 perror("fork"); 93 return -1; 94 case 0: 95 ShouldNotDeadlock(); 96 while (pthread_create(&thread_id, 0, &inchild, 0) != 0) { 97 } 98 pthread_join(thread_id, NULL); 99 _exit(0); 100 break; 101 default: { 102 int status; 103 pid_t child = waitpid(pid, &status, /*options=*/0); 104 assert(pid == child); 105 assert(WIFEXITED(status)); 106 assert(WEXITSTATUS(status) == 0); 107 break; 108 } 109 } 110 111 return 0; 112 } 113