// RUN: %clangxx -fsanitize=realtime -DIS_NONBLOCKING=1 %s -o %t // RUN: %env_rtsan_opts="halt_on_error=true" not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HALT // RUN: %env_rtsan_opts="halt_on_error=false" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOHALT // RUN: %clangxx -fsanitize=realtime -DIS_NONBLOCKING=0 %s -o %t // RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-OK // RUN: %env_rtsan_opts="halt_on_error=false" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-OK // UNSUPPORTED: ios // Intent: Ensure fork/exec dies when realtime and survives otherwise // This behavior is difficult to test in a gtest, because the process is // wiped away with exec. #include #include #include #include #if IS_NONBLOCKING # define MAYBE_NONBLOCKING [[clang::nonblocking]] #else # define MAYBE_NONBLOCKING #endif int main() MAYBE_NONBLOCKING { const pid_t pid = fork(); if (pid == 0) { char *args[] = {"/bin/ls", nullptr}; execve(args[0], args, nullptr); perror("execve failed"); return 1; } else if (pid > 0) { int status; waitpid(pid, &status, 0); usleep(1); } else { perror("fork failed"); return 1; } printf("fork/exec succeeded\n"); return 0; } // CHECK-NOHALT: Intercepted call to {{.*}} `fork` {{.*}} // We should also get some other intercepted call. On some systems this // is `execve`, on others, it's a lock to set up `execve`. In either // case, just check that we get a second intercepted call, don't sweat // the name. // CHECK-NOHALT: Intercepted call to {{.*}} // usleep checks that rtsan is still enabled in the parent process // See note in our interceptors file for why we don't look for `wait` // CHECK-NOHALT: Intercepted call to {{.*}} `usleep` {{.*}} // CHECK-NOHALT: fork/exec succeeded // CHECK-HALT: ==ERROR: RealtimeSanitizer: unsafe-library-call // CHECK-HALT-NEXT: Intercepted call to {{.*}} `fork` {{.*}} // CHECK-OK: fork/exec succeeded