diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc --- a/llvm/lib/Support/Windows/Signals.inc +++ b/llvm/lib/Support/Windows/Signals.inc @@ -584,7 +584,7 @@ LeaveCriticalSection(&CriticalSection); } -static void Cleanup() { +static void Cleanup(bool ExecuteSignalHandlers) { if (CleanupExecuted) return; @@ -600,7 +600,10 @@ llvm::sys::fs::remove(FilesToRemove->back()); FilesToRemove->pop_back(); } - llvm::sys::RunSignalHandlers(); + + if (ExecuteSignalHandlers) + llvm::sys::RunSignalHandlers(); + LeaveCriticalSection(&CriticalSection); } @@ -610,7 +613,7 @@ // error handler). We must ensure that the critical section is properly // initialized. InitializeThreading(); - Cleanup(); + Cleanup(true); } /// Find the Windows Registry Key for a given location. @@ -803,7 +806,7 @@ } static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { - Cleanup(); + Cleanup(true); // We'll automatically write a Minidump file here to help diagnose // the nasty sorts of crashes that aren't 100% reproducible from a set of @@ -834,7 +837,10 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { // We are running in our very own thread, courtesy of Windows. EnterCriticalSection(&CriticalSection); - Cleanup(); + // This function is only ever called when a CTRL-C or similar control signal + // is fired. Killing a process in this way is normal, so don't trigger the + // signal handlers. + Cleanup(false); // If an interrupt function has been set, go and run one it; otherwise, // the process dies. diff --git a/llvm/test/Support/interrupts.test b/llvm/test/Support/interrupts.test new file mode 100644 --- /dev/null +++ b/llvm/test/Support/interrupts.test @@ -0,0 +1,46 @@ +## Show that SIGINT and similar signals don't cause crash messages to be +## reported. +# RUN: %python %s wrapper llvm-symbolizer 2> %t.err +# RUN: FileCheck %s --input-file=%t.err --allow-empty --implicit-check-not={{.}} + +import os +import signal +import subprocess +import sys +import time + +def run_symbolizer(): + proc = subprocess.Popen([sys.argv[2]], stdout=subprocess.PIPE, stdin=subprocess.PIPE) + # Write then read some output to ensure the process has started fully. + proc.stdin.write('foo\n') + proc.stdin.flush() + proc.stdout.readline() + # Windows handles signals differently. + if os.name == 'nt': + os.kill(0, signal.CTRL_BREAK_EVENT) + else: + proc.send_signal(signal.SIGINT) + +# On Windows, this function spawns the subprocess in its own (hidden) console, +# so that signals do not interfere with the calling test. This isn't necessary +# on other systems. +def run_wrapper(): + args = [sys.executable, __file__, 'symbolizer'] + sys.argv[2:] + if os.name == 'nt': + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(args, + stderr=subprocess.PIPE, + startupinfo=startupinfo, + creationflags=subprocess.CREATE_NEW_CONSOLE) + else: + proc = subprocess.Popen(args, + stderr=subprocess.PIPE) + stderr = proc.communicate()[1] + sys.stderr.write(stderr) + sys.stderr.flush() + +if sys.argv[1] == 'wrapper': + run_wrapper() +else: + run_symbolizer()