1// RUN: %clangxx_asan -g -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
15int 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
75extern char **environ;
76#else
77#include <crt_externs.h> // _NSGetEnviron
78#endif
79
80int spawn_child(char **argv) {
81 setenv(name: "CRASH_FOR_TEST", value: "1", replace: 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: &pid, path: argv[0], file_actions: nullptr, attrp: nullptr, argv: argv, envp: envp);
91 if (err) {
92 printf(format: "posix_spawn failed: %d\n", err);
93 fflush(stdout);
94 exit(status: 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: pid, stat_loc: &status, options: 0);
102 } while (wait_result_pid == -1 && errno == EINTR);
103
104 if (wait_result_pid != pid || !WIFEXITED(status)) {
105 printf(format: "error in waitpid\n");
106 fflush(stdout);
107 exit(status: 1);
108 }
109
110 // Return the exit status.
111 return WEXITSTATUS(status);
112}
113#endif
114
115int main(int argc, char **argv) {
116 int r = 0;
117 if (getenv(name: "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(format: "got expected 42 exit code\n");
126 fflush(stdout);
127 }
128 }
129 return r;
130}
131

source code of compiler-rt/test/asan/TestCases/exitcode.cpp