131 lines · cpp
1// RUN: %clang_cl_asan -Od %p/../dll_host.cpp -Fe%t2// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll3// RUNX: %run %t %t.dll 2>&1 | FileCheck %s4 5// Check that ASan does not CHECK fail when SEH is used around a crash from a6// 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("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 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 line77 nullptr, // Process handle not inheritable78 nullptr, // Thread handle not inheritable79 TRUE, // Set handle inheritance to TRUE80 flags, // Flags to give the child a console81 nullptr, // Use parent's environment block82 nullptr, // Use parent's starting directory83 &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 else106 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_DETACH116// CHECK: CrashOnProcessDetach117// CHECK: caught crash118// CHECK: child quit with STATUS_CONTROL_C_EXIT119 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