blob: 276934fe2116ee839ac90ebdd3e6b5c908dad635 [file] [log] [blame]
Reid Kleckner2a2bc722016-11-11 17:51:51 +00001// RUN: %clangxx_asan -g %stdcxx11 -Wno-deprecated-declarations %s -o %t
Reid Kleckner359fafe2016-11-11 18:11:33 +00002// RUN: %env_asan_opts=exitcode=42 %run %t | FileCheck %s
Reid Kleckner2a2bc722016-11-11 17:51:51 +00003
Reid Klecknercb03ef92016-11-11 23:23:33 +00004// Android doesn't have spawn.h or posix_spawn.
5// UNSUPPORTED: android
6
Reid Kleckner2a2bc722016-11-11 17:51:51 +00007// 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__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
65#define USE_NSGETENVIRON 1
66#else
67#define USE_NSGETENVIRON 0
68#endif
69
70#if !USE_NSGETENVIRON
71extern char **environ;
72#else
73#include <crt_externs.h> // _NSGetEnviron
74#endif
75
76int spawn_child(char **argv) {
77 setenv("CRASH_FOR_TEST", "1", 1);
78
79#if !USE_NSGETENVIRON
80 char **envp = environ;
81#else
82 char **envp = *_NSGetEnviron();
83#endif
84
85 pid_t pid;
86 int err = posix_spawn(&pid, argv[0], nullptr, nullptr, argv, envp);
87 if (err) {
88 printf("posix_spawn failed: %d\n", err);
89 fflush(stdout);
90 exit(1);
91 }
92
93 // Wait until the child exits.
94 int status;
95 pid_t wait_result_pid;
96 do {
97 wait_result_pid = waitpid(pid, &status, 0);
98 } while (wait_result_pid == -1 && errno == EINTR);
99
100 if (wait_result_pid != pid || !WIFEXITED(status)) {
101 printf("error in waitpid\n");
102 fflush(stdout);
103 exit(1);
104 }
105
106 // Return the exit status.
107 return WEXITSTATUS(status);
108}
109#endif
110
111int main(int argc, char **argv) {
112 int r = 0;
113 if (getenv("CRASH_FOR_TEST")) {
114 // Generate an asan report to test ASAN_OPTIONS=exitcode=42
115 int *p = new int;
116 delete p;
117 r = *p;
118 } else {
119 int exit_code = spawn_child(argv);
120 if (exit_code == 42) {
121 printf("got expected 42 exit code\n");
122 fflush(stdout);
123 }
124 }
125 return r;
126}