| 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 | |