From faace365088a2a3a4cb1050a9facfc34a7a56577 Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Tue, 11 Feb 2020 10:17:15 -0500 Subject: [PATCH] [Clang][Driver] After default -fintegrated-cc1, make llvm::report_fatal_error() generate preprocessed source + reproducer.sh again. Added a test for #pragma clang __debug llvm_fatal_error to test for the original issue. Added llvm::sys::Process::Exit() and replaced ::exit() in places where it was appropriate. This new function would call the current CrashRecoveryContext if one is running on the same thread; or call ::exit() otherwise. Fixes PR44705. Differential Revision: https://reviews.llvm.org/D73742 --- clang/test/Driver/crash-report.c | 8 +++++ clang/tools/driver/cc1_main.cpp | 3 +- clang/tools/driver/cc1as_main.cpp | 3 +- .../llvm/Support/CrashRecoveryContext.h | 5 ++++ llvm/include/llvm/Support/Process.h | 6 ++++ llvm/lib/Support/CrashRecoveryContext.cpp | 30 +++++++++++++++---- llvm/lib/Support/ErrorHandling.cpp | 3 +- llvm/lib/Support/Process.cpp | 10 ++++++- 8 files changed, 59 insertions(+), 9 deletions(-) diff --git a/clang/test/Driver/crash-report.c b/clang/test/Driver/crash-report.c index 3a77a21c62b4..ceb16cb6e18a 100644 --- a/clang/test/Driver/crash-report.c +++ b/clang/test/Driver/crash-report.c @@ -21,12 +21,20 @@ // RUN: cat %t/crash-report-*.c | FileCheck --check-prefix=CHECKSRC %s // RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s +// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \ +// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \ +// RUN: not %clang %s @%t.rsp -DFATAL 2>&1 | FileCheck %s +// RUN: cat %t/crash-report-*.c | FileCheck --check-prefix=CHECKSRC %s +// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s + // REQUIRES: crash-recovery #ifdef PARSER #pragma clang __debug parser_crash #elif CRASH #pragma clang __debug crash +#elif FATAL +#pragma clang __debug llvm_fatal_error #endif // CHECK: Preprocessed source(s) and associated run script(s) are located at: diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index b551e9f4cf82..6d1a67f2a4fa 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -69,7 +70,7 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message, // We cannot recover from llvm errors. When reporting a fatal error, exit // with status 70 to generate crash diagnostics. For BSD systems this is // defined as an internal software error. Otherwise, exit with status 1. - exit(GenCrashDiag ? 70 : 1); + llvm::sys::Process::Exit(GenCrashDiag ? 70 : 1); } #ifdef CLANG_HAVE_RLIMITS diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index ce390b9f3b17..110f1dc70223 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -46,6 +46,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" @@ -555,7 +556,7 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message, Diags.Report(diag::err_fe_error_backend) << Message; // We cannot recover from llvm errors. - exit(1); + sys::Process::Exit(1); } int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { diff --git a/llvm/include/llvm/Support/CrashRecoveryContext.h b/llvm/include/llvm/Support/CrashRecoveryContext.h index beeb855c7c58..61a1bd405a4d 100644 --- a/llvm/include/llvm/Support/CrashRecoveryContext.h +++ b/llvm/include/llvm/Support/CrashRecoveryContext.h @@ -97,6 +97,11 @@ public: return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize); } + /// Explicitly trigger a crash recovery in the current process, and + /// return failure from RunSafely(). This function does not return. + LLVM_ATTRIBUTE_NORETURN + void HandleExit(int RetCode); + /// In case of a crash, this is the crash identifier. int RetCode = 0; diff --git a/llvm/include/llvm/Support/Process.h b/llvm/include/llvm/Support/Process.h index 9444e165e142..bb5c33dfb38d 100644 --- a/llvm/include/llvm/Support/Process.h +++ b/llvm/include/llvm/Support/Process.h @@ -201,6 +201,12 @@ public: /// Get the result of a process wide random number generator. The /// generator will be automatically seeded in non-deterministic fashion. static unsigned GetRandomNumber(); + + /// Equivalent to ::exit(), except when running inside a CrashRecoveryContext. + /// In that case, the control flow will resume after RunSafely(), like for a + /// crash, rather than exiting the current process. + LLVM_ATTRIBUTE_NORETURN + static void Exit(int RetCode); }; } diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index 0cc2d4059fe9..f708da773f4c 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -14,9 +14,6 @@ #include "llvm/Support/ThreadLocal.h" #include #include -#ifdef _WIN32 -#include // for GetExceptionInformation -#endif #if LLVM_ON_UNIX #include // EX_IOERR #endif @@ -178,6 +175,9 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { } #if defined(_MSC_VER) + +#include // for GetExceptionInformation + // If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way // better than VEH. Vectored exception handling catches all exceptions happening // on the thread with installed exception handlers, so it can interfere with @@ -203,6 +203,8 @@ static int ExceptionFilter(_EXCEPTION_POINTERS *Except) { } int RetCode = (int)Except->ExceptionRecord->ExceptionCode; + if ((RetCode & 0xF0000000) == 0xE0000000) + RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit // Handle the crash const_cast(CRCI)->HandleCrash( @@ -280,10 +282,13 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) // TODO: We can capture the stack backtrace here and store it on the // implementation if we so choose. + int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode; + if ((RetCode & 0xF0000000) == 0xE0000000) + RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit + // Handle the crash const_cast(CRCI)->HandleCrash( - (int)ExceptionInfo->ExceptionRecord->ExceptionCode, - reinterpret_cast(ExceptionInfo)); + RetCode, reinterpret_cast(ExceptionInfo)); // Note that we don't actually get here because HandleCrash calls // longjmp, which means the HandleCrash function never returns. @@ -416,6 +421,21 @@ bool CrashRecoveryContext::RunSafely(function_ref Fn) { #endif // !_MSC_VER +LLVM_ATTRIBUTE_NORETURN +void CrashRecoveryContext::HandleExit(int RetCode) { +#if defined(_WIN32) + // SEH and VEH + ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL); +#else + // On Unix we don't need to raise an exception, we go directly to + // HandleCrash(), then longjmp will unwind the stack for us. + CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl; + assert(CRCI && "Crash recovery context never initialized!"); + CRCI->HandleCrash(RetCode, 0 /*no sig num*/); +#endif + llvm_unreachable("Most likely setjmp wasn't called!"); +} + // FIXME: Portability. static void setThreadBackgroundPriority() { #ifdef __APPLE__ diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp index 0f13f7a536f1..a9463024c420 100644 --- a/llvm/lib/Support/ErrorHandling.cpp +++ b/llvm/lib/Support/ErrorHandling.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" #include "llvm/Support/WindowsError.h" @@ -122,7 +123,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) { // files registered with RemoveFileOnSignal. sys::RunInterruptHandlers(); - exit(1); + sys::Process::Exit(1); } void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler, diff --git a/llvm/lib/Support/Process.cpp b/llvm/lib/Support/Process.cpp index 0b2d41bcdeca..9e6e233b26ac 100644 --- a/llvm/lib/Support/Process.cpp +++ b/llvm/lib/Support/Process.cpp @@ -13,8 +13,9 @@ #include "llvm/Support/Process.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Config/llvm-config.h" #include "llvm/Config/config.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -88,6 +89,13 @@ static bool coreFilesPrevented = !LLVM_ENABLE_CRASH_DUMPS; bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; } +LLVM_ATTRIBUTE_NORETURN +void Process::Exit(int RetCode) { + if (CrashRecoveryContext *CRC = CrashRecoveryContext::GetCurrent()) + CRC->HandleExit(RetCode); + ::exit(RetCode); +} + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Process.inc"