1 | // RUN: %clangxx %s -g -DSHARED_LIB -shared -o %t_shared_lib.dylib |
2 | // RUN: %clangxx %s -g -USHARED_LIB -o %t_loader |
3 | // RUN: %env_tool_opts=verbosity=3 %run %t_loader %t_shared_lib.dylib > %t_loader_output.txt 2>&1 |
4 | // RUN: FileCheck -input-file=%t_loader_output.txt %s |
5 | // RUN: FileCheck -check-prefix=CHECK-STACKTRACE -input-file=%t_loader_output.txt %s |
6 | // rdar://problem/61793759 and rdar://problem/62126022. |
7 | // UNSUPPORTED: lsan |
8 | |
9 | #include <stdio.h> |
10 | |
11 | #ifdef SHARED_LIB |
12 | #include <sanitizer/common_interface_defs.h> |
13 | |
14 | extern "C" void PrintStack() { |
15 | fprintf(stderr, "Calling __sanitizer_print_stack_trace\n" ); |
16 | // CHECK-STACKTRACE: #0{{( *0x.* *in *)?}} __sanitizer_print_stack_trace |
17 | // CHECK-STACKTRACE: #1{{( *0x.* *in *)?}} PrintStack {{.*}}print-stack-trace-in-code-loaded-after-fork.cpp:[[@LINE+1]] |
18 | __sanitizer_print_stack_trace(); |
19 | } |
20 | #else |
21 | #include <assert.h> |
22 | #include <dlfcn.h> |
23 | #include <stdlib.h> |
24 | #include <sys/wait.h> |
25 | #include <unistd.h> |
26 | |
27 | typedef void (*PrintStackFnPtrTy)(void); |
28 | |
29 | int main(int argc, char **argv) { |
30 | assert(argc == 2); |
31 | pid_t pid = fork(); |
32 | if (pid != 0) { |
33 | // Parent |
34 | pid_t parent_pid = getpid(); |
35 | fprintf(stderr, format: "parent: %d\n" , parent_pid); |
36 | int status = 0; |
37 | pid_t child = waitpid(pid: pid, stat_loc: &status, /*options=*/0); |
38 | assert(pid == child); |
39 | bool clean_exit = WIFEXITED(status) && WEXITSTATUS(status) == 0; |
40 | return !clean_exit; |
41 | } |
42 | // Child. |
43 | pid = getpid(); |
44 | // CHECK: child: [[CHILD_PID:[0-9]+]] |
45 | fprintf(stderr, format: "child: %d\n" , pid); |
46 | // We load new code into the child process that isn't loaded into the parent. |
47 | // When we symbolize in `PrintStack` if the symbolizer is told to symbolize |
48 | // the parent (an old bug) rather than the child then symbolization will |
49 | // fail. |
50 | const char *library_to_load = argv[1]; |
51 | void *handle = dlopen(file: library_to_load, RTLD_NOW | RTLD_LOCAL); |
52 | assert(handle); |
53 | PrintStackFnPtrTy PrintStackFnPtr = (PrintStackFnPtrTy)dlsym(handle: handle, name: "PrintStack" ); |
54 | assert(PrintStackFnPtr); |
55 | // Check that the symbolizer is told examine the child process. |
56 | // CHECK: Launching Symbolizer process: {{.+}}atos -p [[CHILD_PID]] |
57 | // CHECK-STACKTRACE: #2{{( *0x.* *in *)?}} main {{.*}}print-stack-trace-in-code-loaded-after-fork.cpp:[[@LINE+1]] |
58 | PrintStackFnPtr(); |
59 | return 0; |
60 | } |
61 | |
62 | #endif |
63 | |