diff options
Diffstat (limited to 'compiler-rt/test/asan/TestCases/Windows/dll_control_c.cpp')
-rw-r--r-- | compiler-rt/test/asan/TestCases/Windows/dll_control_c.cpp | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_control_c.cpp b/compiler-rt/test/asan/TestCases/Windows/dll_control_c.cpp new file mode 100644 index 00000000000..e30276325db --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Windows/dll_control_c.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_cl_asan -Od %p/dll_host.cpp -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; +} |