diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 6c0ff3d30e6438..7d43b4094b7d75 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1873,14 +1873,12 @@ int Driver::ExecuteCompilation( C.CleanupFileMap(C.getFailureResultFiles(), JA, true); } -#if LLVM_ON_UNIX - // llvm/lib/Support/Unix/Signals.inc will exit with a special return code + // llvm/lib/Support/*/Signals.inc will exit with a special return code // for SIGPIPE. Do not print diagnostics for this case. if (CommandRes == EX_IOERR) { Res = CommandRes; continue; } -#endif // Print extra information about abnormal failures, if possible. // diff --git a/llvm/include/llvm/Support/ExitCodes.h b/llvm/include/llvm/Support/ExitCodes.h index b9041f5557d52d..4eb5dedc688bc3 100644 --- a/llvm/include/llvm/Support/ExitCodes.h +++ b/llvm/include/llvm/Support/ExitCodes.h @@ -20,9 +20,9 @@ #if HAVE_SYSEXITS_H #include -#elif __MVS__ -// does not exist on z/OS. The only value used in LLVM is -// EX_IOERR, which is used to signal a special error condition (broken pipe). +#elif __MVS__ || defined(_WIN32) +// does not exist on z/OS and Windows. The only value used in LLVM +// is EX_IOERR, which is used to signal a special error condition (broken pipe). // Define the macro with its usual value from BSD systems, which is chosen to // not clash with more standard exit codes like 1. #define EX_IOERR 74 diff --git a/llvm/include/llvm/Support/Signals.h b/llvm/include/llvm/Support/Signals.h index 937e0572d4a725..70749ce30184a7 100644 --- a/llvm/include/llvm/Support/Signals.h +++ b/llvm/include/llvm/Support/Signals.h @@ -102,14 +102,17 @@ namespace sys { /// functions. A null handler pointer disables the current installed /// function. Note also that the handler may be executed on a /// different thread on some platforms. - /// - /// This is a no-op on Windows. void SetOneShotPipeSignalFunction(void (*Handler)()); - /// On Unix systems, this function exits with an "IO error" exit code. - /// This is a no-op on Windows. + /// On Unix systems and Windows, this function exits with an "IO error" exit + /// code. void DefaultOneShotPipeSignalHandler(); +#ifdef _WIN32 + /// Windows does not support signals and this handler must be called manually. + void CallOneShotPipeSignalHandler(); +#endif + /// This function does the following: /// - clean up any temporary files registered with RemoveFileOnSignal() /// - dump the callstack from the exception context diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc index ba93afe0803b43..4bf699f2bccf04 100644 --- a/llvm/lib/Support/Windows/Signals.inc +++ b/llvm/lib/Support/Windows/Signals.inc @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ExitCodes.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" @@ -204,6 +205,9 @@ static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; +/// The function to call on "SIGPIPE" (one-time use only). +static std::atomic OneShotPipeSignalFunction(nullptr); + // Windows creates a new thread to execute the console handler when an event // (such as CTRL/C) occurs. This causes concurrency issues with the above // globals which this critical section addresses. @@ -575,11 +579,16 @@ void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { } void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { - // Unimplemented. + OneShotPipeSignalFunction.exchange(Handler); } void llvm::sys::DefaultOneShotPipeSignalHandler() { - // Unimplemented. + llvm::sys::Process::Exit(EX_IOERR, /*NoCleanup=*/true); +} + +void llvm::sys::CallOneShotPipeSignalHandler() { + if (auto OldOneShotPipeFunction = OneShotPipeSignalFunction.exchange(nullptr)) + OldOneShotPipeFunction(); } /// Add a function to be called when a signal is delivered to the process. The @@ -816,7 +825,15 @@ WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { } void sys::CleanupOnSignal(uintptr_t Context) { - LLVMUnhandledExceptionFilter((LPEXCEPTION_POINTERS)Context); + LPEXCEPTION_POINTERS EP = (LPEXCEPTION_POINTERS)Context; + // Broken pipe is not a crash. + // + // 0xE0000000 is combined with the return code in the exception raised in + // CrashRecoveryContext::HandleExit(). + int RetCode = (int)EP->ExceptionRecord->ExceptionCode; + if (RetCode == (0xE0000000 | EX_IOERR)) + return; + LLVMUnhandledExceptionFilter(EP); } static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp index 8943c4478c7f20..7b9b8b2f53fbaa 100644 --- a/llvm/lib/Support/raw_ostream.cpp +++ b/llvm/lib/Support/raw_ostream.cpp @@ -56,6 +56,7 @@ #ifdef _WIN32 #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/Windows/WindowsSupport.h" #endif @@ -775,6 +776,15 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { ) continue; +#ifdef _WIN32 + // Windows equivalents of SIGPIPE/EPIPE. + DWORD WinLastError = GetLastError(); + if (WinLastError == ERROR_BROKEN_PIPE || + (WinLastError == ERROR_NO_DATA && errno == EINVAL)) { + llvm::sys::CallOneShotPipeSignalHandler(); + errno = EPIPE; + } +#endif // Otherwise it's a non-recoverable error. Note it and quit. error_detected(std::error_code(errno, std::generic_category())); break;