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 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 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 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