1*882ce178SVitaly Buka // RUN: %clangxx_asan -g -Wno-deprecated-declarations %s -o %t
2673dc3d4SNico Weber // RUN: %env_asan_opts=exitcode=42 %run %t | FileCheck %s
3673dc3d4SNico Weber
4673dc3d4SNico Weber // Android doesn't have spawn.h or posix_spawn.
5673dc3d4SNico Weber // UNSUPPORTED: android
6673dc3d4SNico Weber
7673dc3d4SNico Weber // CHECK: got expected 42 exit code
8673dc3d4SNico Weber
9673dc3d4SNico Weber #include <stdlib.h>
10673dc3d4SNico Weber #include <stdio.h>
11673dc3d4SNico Weber
12673dc3d4SNico Weber #ifdef _WIN32
13673dc3d4SNico Weber #include <windows.h>
14673dc3d4SNico Weber
spawn_child(char ** argv)15673dc3d4SNico Weber int spawn_child(char **argv) {
16673dc3d4SNico Weber // Set an environment variable to tell the child process to interrupt
17673dc3d4SNico Weber // itself.
18673dc3d4SNico Weber if (!SetEnvironmentVariableW(L"CRASH_FOR_TEST", L"1")) {
19673dc3d4SNico Weber printf("SetEnvironmentVariableW failed (0x%8lx).\n", GetLastError());
20673dc3d4SNico Weber fflush(stdout);
21673dc3d4SNico Weber exit(1);
22673dc3d4SNico Weber }
23673dc3d4SNico Weber
24673dc3d4SNico Weber STARTUPINFOW si;
25673dc3d4SNico Weber memset(&si, 0, sizeof(si));
26673dc3d4SNico Weber si.cb = sizeof(si);
27673dc3d4SNico Weber
28673dc3d4SNico Weber PROCESS_INFORMATION pi;
29673dc3d4SNico Weber memset(&pi, 0, sizeof(pi));
30673dc3d4SNico Weber
31673dc3d4SNico Weber if (!CreateProcessW(nullptr, // No module name (use command line)
32673dc3d4SNico Weber GetCommandLineW(), // Command line
33673dc3d4SNico Weber nullptr, // Process handle not inheritable
34673dc3d4SNico Weber nullptr, // Thread handle not inheritable
35673dc3d4SNico Weber TRUE, // Set handle inheritance to TRUE
36673dc3d4SNico Weber 0, // No flags
37673dc3d4SNico Weber nullptr, // Use parent's environment block
38673dc3d4SNico Weber nullptr, // Use parent's starting directory
39673dc3d4SNico Weber &si, &pi)) {
40673dc3d4SNico Weber printf("CreateProcess failed (0x%08lx).\n", GetLastError());
41673dc3d4SNico Weber fflush(stdout);
42673dc3d4SNico Weber exit(1);
43673dc3d4SNico Weber }
44673dc3d4SNico Weber
45673dc3d4SNico Weber WaitForSingleObject(pi.hProcess, INFINITE);
46673dc3d4SNico Weber
47673dc3d4SNico Weber DWORD exit_code;
48673dc3d4SNico Weber if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
49673dc3d4SNico Weber printf("GetExitCodeProcess failed (0x%08lx).\n", GetLastError());
50673dc3d4SNico Weber fflush(stdout);
51673dc3d4SNico Weber exit(1);
52673dc3d4SNico Weber }
53673dc3d4SNico Weber
54673dc3d4SNico Weber CloseHandle(pi.hProcess);
55673dc3d4SNico Weber CloseHandle(pi.hThread);
56673dc3d4SNico Weber
57673dc3d4SNico Weber return exit_code;
58673dc3d4SNico Weber }
59673dc3d4SNico Weber #else
60673dc3d4SNico Weber #include <spawn.h>
61673dc3d4SNico Weber #include <errno.h>
62673dc3d4SNico Weber #include <sys/wait.h>
63673dc3d4SNico Weber
64673dc3d4SNico Weber #if defined(__APPLE__)
65673dc3d4SNico Weber #include <TargetConditionals.h>
66673dc3d4SNico Weber #endif
67673dc3d4SNico Weber
68673dc3d4SNico Weber #if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
69673dc3d4SNico Weber #define USE_NSGETENVIRON 1
70673dc3d4SNico Weber #else
71673dc3d4SNico Weber #define USE_NSGETENVIRON 0
72673dc3d4SNico Weber #endif
73673dc3d4SNico Weber
74673dc3d4SNico Weber #if !USE_NSGETENVIRON
75673dc3d4SNico Weber extern char **environ;
76673dc3d4SNico Weber #else
77673dc3d4SNico Weber #include <crt_externs.h> // _NSGetEnviron
78673dc3d4SNico Weber #endif
79673dc3d4SNico Weber
spawn_child(char ** argv)80673dc3d4SNico Weber int spawn_child(char **argv) {
81673dc3d4SNico Weber setenv("CRASH_FOR_TEST", "1", 1);
82673dc3d4SNico Weber
83673dc3d4SNico Weber #if !USE_NSGETENVIRON
84673dc3d4SNico Weber char **envp = environ;
85673dc3d4SNico Weber #else
86673dc3d4SNico Weber char **envp = *_NSGetEnviron();
87673dc3d4SNico Weber #endif
88673dc3d4SNico Weber
89673dc3d4SNico Weber pid_t pid;
90673dc3d4SNico Weber int err = posix_spawn(&pid, argv[0], nullptr, nullptr, argv, envp);
91673dc3d4SNico Weber if (err) {
92673dc3d4SNico Weber printf("posix_spawn failed: %d\n", err);
93673dc3d4SNico Weber fflush(stdout);
94673dc3d4SNico Weber exit(1);
95673dc3d4SNico Weber }
96673dc3d4SNico Weber
97673dc3d4SNico Weber // Wait until the child exits.
98673dc3d4SNico Weber int status;
99673dc3d4SNico Weber pid_t wait_result_pid;
100673dc3d4SNico Weber do {
101673dc3d4SNico Weber wait_result_pid = waitpid(pid, &status, 0);
102673dc3d4SNico Weber } while (wait_result_pid == -1 && errno == EINTR);
103673dc3d4SNico Weber
104673dc3d4SNico Weber if (wait_result_pid != pid || !WIFEXITED(status)) {
105673dc3d4SNico Weber printf("error in waitpid\n");
106673dc3d4SNico Weber fflush(stdout);
107673dc3d4SNico Weber exit(1);
108673dc3d4SNico Weber }
109673dc3d4SNico Weber
110673dc3d4SNico Weber // Return the exit status.
111673dc3d4SNico Weber return WEXITSTATUS(status);
112673dc3d4SNico Weber }
113673dc3d4SNico Weber #endif
114673dc3d4SNico Weber
main(int argc,char ** argv)115673dc3d4SNico Weber int main(int argc, char **argv) {
116673dc3d4SNico Weber int r = 0;
117673dc3d4SNico Weber if (getenv("CRASH_FOR_TEST")) {
118673dc3d4SNico Weber // Generate an asan report to test ASAN_OPTIONS=exitcode=42
119673dc3d4SNico Weber int *p = new int;
120673dc3d4SNico Weber delete p;
121673dc3d4SNico Weber r = *p;
122673dc3d4SNico Weber } else {
123673dc3d4SNico Weber int exit_code = spawn_child(argv);
124673dc3d4SNico Weber if (exit_code == 42) {
125673dc3d4SNico Weber printf("got expected 42 exit code\n");
126673dc3d4SNico Weber fflush(stdout);
127673dc3d4SNico Weber }
128673dc3d4SNico Weber }
129673dc3d4SNico Weber return r;
130673dc3d4SNico Weber }
131