131 lines
4.0 KiB
C++
131 lines
4.0 KiB
C++
|
// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
|
||
|
// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll
|
||
|
// RUNX: %run %t %t.dll 2>&1 | FileCheck %s
|
||
|
|
||
|
// Check that ASan does not CHECK fail when SEH is used around a crash from a
|
||
|
// thread injected by control C.
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <windows.h>
|
||
|
|
||
|
static void __declspec(noinline) CrashOnProcessDetach() {
|
||
|
printf("CrashOnProcessDetach\n");
|
||
|
fflush(stdout);
|
||
|
*static_cast<volatile int *>(0) = 0x356;
|
||
|
}
|
||
|
|
||
|
bool g_is_child = false;
|
||
|
|
||
|
BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) {
|
||
|
if (reason == DLL_PROCESS_DETACH && g_is_child) {
|
||
|
printf("in DllMain DLL_PROCESS_DETACH\n");
|
||
|
fflush(stdout);
|
||
|
__try {
|
||
|
CrashOnProcessDetach();
|
||
|
} __except (1) {
|
||
|
printf("caught crash\n");
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static void run_child() {
|
||
|
// Send this process group Ctrl+C. That should only be this process.
|
||
|
printf("GenerateConsoleCtrlEvent\n");
|
||
|
fflush(stdout);
|
||
|
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||
|
Sleep(10 * 1000); // Wait 10 seconds, and the process should die.
|
||
|
printf("unexpected execution after interrupt\n");
|
||
|
fflush(stdout);
|
||
|
exit(0x42);
|
||
|
}
|
||
|
|
||
|
static int WINAPI ignore_control_c(DWORD ctrl_type) {
|
||
|
// Don't interrupt the parent.
|
||
|
return ctrl_type == CTRL_C_EVENT;
|
||
|
}
|
||
|
|
||
|
static int run_parent() {
|
||
|
// Set an environment variable to tell the child process to interrupt itself.
|
||
|
if (!SetEnvironmentVariableW(L"DO_CONTROL_C", L"1")) {
|
||
|
printf("SetEnvironmentVariableW failed (0x%8lx).\n", GetLastError());
|
||
|
fflush(stdout);
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
// Launch a new process using the current executable with a new console.
|
||
|
// Ctrl-C events are console-wide, so we need a new console.
|
||
|
STARTUPINFOW si;
|
||
|
memset(&si, 0, sizeof(si));
|
||
|
si.cb = sizeof(si);
|
||
|
// Hides the new console window that we are creating.
|
||
|
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||
|
si.wShowWindow = SW_HIDE;
|
||
|
// Ensures that stdout still goes to the parent despite the new console.
|
||
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
||
|
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||
|
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||
|
|
||
|
PROCESS_INFORMATION pi;
|
||
|
memset(&pi, 0, sizeof(pi));
|
||
|
int flags = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE;
|
||
|
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
|
||
|
flags, // Flags to give the child a console
|
||
|
nullptr, // Use parent's environment block
|
||
|
nullptr, // Use parent's starting directory
|
||
|
&si, &pi)) {
|
||
|
printf("CreateProcess failed (0x%08lx).\n", GetLastError());
|
||
|
fflush(stdout);
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
// Wait until child process exits.
|
||
|
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) {
|
||
|
printf("WaitForSingleObject failed (0x%08lx).\n", GetLastError());
|
||
|
fflush(stdout);
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
// Get the exit code. It should be the one for ctrl-c events.
|
||
|
DWORD rc;
|
||
|
if (!GetExitCodeProcess(pi.hProcess, &rc)) {
|
||
|
printf("GetExitCodeProcess failed (0x%08lx).\n", GetLastError());
|
||
|
fflush(stdout);
|
||
|
return 2;
|
||
|
}
|
||
|
if (rc == STATUS_CONTROL_C_EXIT)
|
||
|
printf("child quit with STATUS_CONTROL_C_EXIT\n");
|
||
|
else
|
||
|
printf("unexpected exit code: 0x%08lx\n", rc);
|
||
|
fflush(stdout);
|
||
|
|
||
|
// Close process and thread handles.
|
||
|
CloseHandle(pi.hProcess);
|
||
|
CloseHandle(pi.hThread);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// CHECK: in DllMain DLL_PROCESS_DETACH
|
||
|
// CHECK: CrashOnProcessDetach
|
||
|
// CHECK: caught crash
|
||
|
// CHECK: child quit with STATUS_CONTROL_C_EXIT
|
||
|
|
||
|
extern "C" int __declspec(dllexport) test_function() {
|
||
|
wchar_t buf[260];
|
||
|
int len = GetEnvironmentVariableW(L"DO_CONTROL_C", buf, 260);
|
||
|
if (len > 0) {
|
||
|
g_is_child = true;
|
||
|
run_child();
|
||
|
} else {
|
||
|
exit(run_parent());
|
||
|
}
|
||
|
return 0;
|
||
|
}
|