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
26int main() MAYBE_NONBLOCKING {
27 const pid_t pid = fork();
28
29 if (pid == 0) {
30 char *args[] = {"/bin/ls", nullptr};
31 execve(path: args[0], argv: args, envp: nullptr);
32 perror(s: "execve failed");
33 return 1;
34 } else if (pid > 0) {
35 int status;
36 waitpid(pid: pid, stat_loc: &status, options: 0);
37 usleep(useconds: 1);
38 } else {
39 perror(s: "fork failed");
40 return 1;
41 }
42
43 printf(format: "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

source code of compiler-rt/test/rtsan/fork_exec.cpp