summaryrefslogtreecommitdiff
path: root/test/asan/TestCases/exitcode.cc
blob: cb10540999b7d53f5f428c863bb14f61f1f11aca (plain)
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;
}