1 // RUN: %clangxx_asan -g %stdcxx11 -Wno-deprecated-declarations %s -o %t
2 // RUN: %env_asan_opts=exitcode=42 %run %t | FileCheck %s
3
4 // Android doesn't have spawn.h or posix_spawn.
5 // UNSUPPORTED: android
6
7 // CHECK: got expected 42 exit code
8
9 #include <stdlib.h>
10 #include <stdio.h>
11
12 #ifdef _WIN32
13 #include <windows.h>
14
spawn_child(char ** argv)15 int spawn_child(char **argv) {
16 // Set an environment variable to tell the child process to interrupt
17 // itself.
18 if (!SetEnvironmentVariableW(L"CRASH_FOR_TEST", L"1")) {
19 printf("SetEnvironmentVariableW failed (0x%8lx).\n", GetLastError());
20 fflush(stdout);
21 exit(1);
22 }
23
24 STARTUPINFOW si;
25 memset(&si, 0, sizeof(si));
26 si.cb = sizeof(si);
27
28 PROCESS_INFORMATION pi;
29 memset(&pi, 0, sizeof(pi));
30
31 if (!CreateProcessW(nullptr, // No module name (use command line)
32 GetCommandLineW(), // Command line
33 nullptr, // Process handle not inheritable
34 nullptr, // Thread handle not inheritable
35 TRUE, // Set handle inheritance to TRUE
36 0, // No flags
37 nullptr, // Use parent's environment block
38 nullptr, // Use parent's starting directory
39 &si, &pi)) {
40 printf("CreateProcess failed (0x%08lx).\n", GetLastError());
41 fflush(stdout);
42 exit(1);
43 }
44
45 WaitForSingleObject(pi.hProcess, INFINITE);
46
47 DWORD exit_code;
48 if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
49 printf("GetExitCodeProcess failed (0x%08lx).\n", GetLastError());
50 fflush(stdout);
51 exit(1);
52 }
53
54 CloseHandle(pi.hProcess);
55 CloseHandle(pi.hThread);
56
57 return exit_code;
58 }
59 #else
60 #include <spawn.h>
61 #include <errno.h>
62 #include <sys/wait.h>
63
64 #if defined(__APPLE__)
65 #include <TargetConditionals.h>
66 #endif
67
68 #if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
69 #define USE_NSGETENVIRON 1
70 #else
71 #define USE_NSGETENVIRON 0
72 #endif
73
74 #if !USE_NSGETENVIRON
75 extern char **environ;
76 #else
77 #include <crt_externs.h> // _NSGetEnviron
78 #endif
79
spawn_child(char ** argv)80 int spawn_child(char **argv) {
81 setenv("CRASH_FOR_TEST", "1", 1);
82
83 #if !USE_NSGETENVIRON
84 char **envp = environ;
85 #else
86 char **envp = *_NSGetEnviron();
87 #endif
88
89 pid_t pid;
90 int err = posix_spawn(&pid, argv[0], nullptr, nullptr, argv, envp);
91 if (err) {
92 printf("posix_spawn failed: %d\n", err);
93 fflush(stdout);
94 exit(1);
95 }
96
97 // Wait until the child exits.
98 int status;
99 pid_t wait_result_pid;
100 do {
101 wait_result_pid = waitpid(pid, &status, 0);
102 } while (wait_result_pid == -1 && errno == EINTR);
103
104 if (wait_result_pid != pid || !WIFEXITED(status)) {
105 printf("error in waitpid\n");
106 fflush(stdout);
107 exit(1);
108 }
109
110 // Return the exit status.
111 return WEXITSTATUS(status);
112 }
113 #endif
114
main(int argc,char ** argv)115 int main(int argc, char **argv) {
116 int r = 0;
117 if (getenv("CRASH_FOR_TEST")) {
118 // Generate an asan report to test ASAN_OPTIONS=exitcode=42
119 int *p = new int;
120 delete p;
121 r = *p;
122 } else {
123 int exit_code = spawn_child(argv);
124 if (exit_code == 42) {
125 printf("got expected 42 exit code\n");
126 fflush(stdout);
127 }
128 }
129 return r;
130 }
131