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