1// RUN: %clang_cl_asan -Od %p/../dll_host.cpp -Fe%t
2// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll
3// RUNX: %run %t %t.dll 2>&1 | FileCheck %s
4
5// Check that ASan does not CHECK fail when SEH is used around a crash from a
6// thread injected by control C.
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <windows.h>
11
12static void __declspec(noinline) CrashOnProcessDetach() {
13 printf("CrashOnProcessDetach\n");
14 fflush(stdout);
15 *static_cast<volatile int *>(0) = 0x356;
16}
17
18bool g_is_child = false;
19
20BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) {
21 if (reason == DLL_PROCESS_DETACH && g_is_child) {
22 printf("in DllMain DLL_PROCESS_DETACH\n");
23 fflush(stdout);
24 __try {
25 CrashOnProcessDetach();
26 } __except (1) {
27 printf("caught crash\n");
28 fflush(stdout);
29 }
30 }
31 return true;
32}
33
34static void run_child() {
35 // Send this process group Ctrl+C. That should only be this process.
36 printf(format: "GenerateConsoleCtrlEvent\n");
37 fflush(stdout);
38 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
39 Sleep(10 * 1000); // Wait 10 seconds, and the process should die.
40 printf(format: "unexpected execution after interrupt\n");
41 fflush(stdout);
42 exit(status: 0x42);
43}
44
45static int WINAPI ignore_control_c(DWORD ctrl_type) {
46 // Don't interrupt the parent.
47 return ctrl_type == CTRL_C_EVENT;
48}
49
50static int run_parent() {
51 // Set an environment variable to tell the child process to interrupt itself.
52 if (!SetEnvironmentVariableW(L"DO_CONTROL_C", L"1")) {
53 printf("SetEnvironmentVariableW failed (0x%8lx).\n", GetLastError());
54 fflush(stdout);
55 return 2;
56 }
57
58 // Launch a new process using the current executable with a new console.
59 // Ctrl-C events are console-wide, so we need a new console.
60 STARTUPINFOW si;
61 memset(&si, 0, sizeof(si));
62 si.cb = sizeof(si);
63 // Hides the new console window that we are creating.
64 si.dwFlags |= STARTF_USESHOWWINDOW;
65 si.wShowWindow = SW_HIDE;
66 // Ensures that stdout still goes to the parent despite the new console.
67 si.dwFlags |= STARTF_USESTDHANDLES;
68 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
69 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
70 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
71
72 PROCESS_INFORMATION pi;
73 memset(&pi, 0, sizeof(pi));
74 int flags = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE;
75 if (!CreateProcessW(nullptr, // No module name (use command line)
76 GetCommandLineW(), // Command line
77 nullptr, // Process handle not inheritable
78 nullptr, // Thread handle not inheritable
79 TRUE, // Set handle inheritance to TRUE
80 flags, // Flags to give the child a console
81 nullptr, // Use parent's environment block
82 nullptr, // Use parent's starting directory
83 &si, &pi)) {
84 printf("CreateProcess failed (0x%08lx).\n", GetLastError());
85 fflush(stdout);
86 return 2;
87 }
88
89 // Wait until child process exits.
90 if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) {
91 printf("WaitForSingleObject failed (0x%08lx).\n", GetLastError());
92 fflush(stdout);
93 return 2;
94 }
95
96 // Get the exit code. It should be the one for ctrl-c events.
97 DWORD rc;
98 if (!GetExitCodeProcess(pi.hProcess, &rc)) {
99 printf("GetExitCodeProcess failed (0x%08lx).\n", GetLastError());
100 fflush(stdout);
101 return 2;
102 }
103 if (rc == STATUS_CONTROL_C_EXIT)
104 printf(format: "child quit with STATUS_CONTROL_C_EXIT\n");
105 else
106 printf("unexpected exit code: 0x%08lx\n", rc);
107 fflush(stdout);
108
109 // Close process and thread handles.
110 CloseHandle(pi.hProcess);
111 CloseHandle(pi.hThread);
112 return 0;
113}
114
115// CHECK: in DllMain DLL_PROCESS_DETACH
116// CHECK: CrashOnProcessDetach
117// CHECK: caught crash
118// CHECK: child quit with STATUS_CONTROL_C_EXIT
119
120extern "C" int __declspec(dllexport) test_function() {
121 wchar_t buf[260];
122 int len = GetEnvironmentVariableW(L"DO_CONTROL_C", buf, 260);
123 if (len > 0) {
124 g_is_child = true;
125 run_child();
126 } else {
127 exit(run_parent());
128 }
129 return 0;
130}
131

source code of compiler-rt/test/asan/TestCases/Windows/msvc/dll_control_c.cpp