1 // RUN: %clangxx -fsanitize=realtime -DIS_NONBLOCKING=1 %s -o %t 2 // RUN: %env_rtsan_opts="halt_on_error=true" not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HALT 3 // RUN: %env_rtsan_opts="halt_on_error=false" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOHALT 4 5 // RUN: %clangxx -fsanitize=realtime -DIS_NONBLOCKING=0 %s -o %t 6 // RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-OK 7 // RUN: %env_rtsan_opts="halt_on_error=false" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-OK 8 9 // UNSUPPORTED: ios 10 11 // Intent: Ensure fork/exec dies when realtime and survives otherwise 12 // This behavior is difficult to test in a gtest, because the process is 13 // wiped away with exec. 14 15 #include <stdio.h> 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <unistd.h> 19 20 #if IS_NONBLOCKING 21 # define MAYBE_NONBLOCKING [[clang::nonblocking]] 22 #else 23 # define MAYBE_NONBLOCKING 24 #endif 25 26 int main() MAYBE_NONBLOCKING { 27 const pid_t pid = fork(); 28 29 if (pid == 0) { 30 char *args[] = {"/bin/ls", nullptr}; 31 execve(args[0], args, nullptr); 32 perror("execve failed"); 33 return 1; 34 } else if (pid > 0) { 35 int status; 36 waitpid(pid, &status, 0); 37 usleep(1); 38 } else { 39 perror("fork failed"); 40 return 1; 41 } 42 43 printf("fork/exec succeeded\n"); 44 return 0; 45 } 46 47 // CHECK-NOHALT: Intercepted call to {{.*}} `fork` {{.*}} 48 // CHECK-NOHALT: Intercepted call to {{.*}} `execve` {{.*}} 49 50 // usleep checks that rtsan is still enabled in the parent process 51 // See note in our interceptors file for why we don't look for `wait` 52 // CHECK-NOHALT: Intercepted call to {{.*}} `usleep` {{.*}} 53 54 // CHECK-NOHALT: fork/exec succeeded 55 56 // CHECK-HALT: ==ERROR: RealtimeSanitizer: unsafe-library-call 57 // CHECK-HALT-NEXT: Intercepted call to {{.*}} `fork` {{.*}} 58 59 // CHECK-OK: fork/exec succeeded 60