• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // RUN: %clang_cl_asan -O0 %p/dll_host.cc -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 
CrashOnProcessDetach()12 static void __declspec(noinline) CrashOnProcessDetach() {
13   printf("CrashOnProcessDetach\n");
14   fflush(stdout);
15   *static_cast<volatile int *>(0) = 0x356;
16 }
17 
18 bool g_is_child = false;
19 
DllMain(PVOID h,DWORD reason,PVOID reserved)20 BOOL 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 
run_child()34 static void run_child() {
35   // Send this process group Ctrl+C. That should only be this process.
36   printf("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("unexpected execution after interrupt\n");
41   fflush(stdout);
42   exit(0x42);
43 }
44 
ignore_control_c(DWORD ctrl_type)45 static int WINAPI ignore_control_c(DWORD ctrl_type) {
46   // Don't interrupt the parent.
47   return ctrl_type == CTRL_C_EVENT;
48 }
49 
run_parent()50 static 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("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 
test_function()120 extern "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