diff options
Diffstat (limited to 'lib/Support/CrashRecoveryContext.cpp')
| -rw-r--r-- | lib/Support/CrashRecoveryContext.cpp | 130 | 
1 files changed, 82 insertions, 48 deletions
diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index 98865f5e065e..bd38dd88201f 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -78,6 +78,9 @@ static bool gCrashRecoveryEnabled = false;  static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>         tlIsRecoveringFromCrash; +static void installExceptionOrSignalHandlers(); +static void uninstallExceptionOrSignalHandlers(); +  CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}  CrashRecoveryContext::~CrashRecoveryContext() { @@ -113,6 +116,23 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {    return CRCI->CRC;  } +void CrashRecoveryContext::Enable() { +  sys::ScopedLock L(*gCrashRecoveryContextMutex); +  // FIXME: Shouldn't this be a refcount or something? +  if (gCrashRecoveryEnabled) +    return; +  gCrashRecoveryEnabled = true; +  installExceptionOrSignalHandlers(); +} + +void CrashRecoveryContext::Disable() { +  sys::ScopedLock L(*gCrashRecoveryContextMutex); +  if (!gCrashRecoveryEnabled) +    return; +  gCrashRecoveryEnabled = false; +  uninstallExceptionOrSignalHandlers(); +} +  void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)  {    if (!cleanup) @@ -140,30 +160,70 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {    delete cleanup;  } -#ifdef LLVM_ON_WIN32 +#if defined(_MSC_VER) +// 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 +// internal exception handling of other libraries on that thread. SEH works +// exactly as you would expect normal exception handling to work: it only +// catches exceptions if they would bubble out from the stack frame with __try / +// __except. -#include "Windows/WindowsSupport.h" +static void installExceptionOrSignalHandlers() {} +static void uninstallExceptionOrSignalHandlers() {} -// On Windows, we can make use of vectored exception handling to -// catch most crashing situations.  Note that this does mean -// we will be alerted of exceptions *before* structured exception -// handling has the opportunity to catch it.  But that isn't likely -// to cause problems because nowhere in the project is SEH being -// used. +bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { +  if (!gCrashRecoveryEnabled) { +    Fn(); +    return true; +  } + +  bool Result = true; +  __try { +    Fn(); +  } __except (1) { // Catch any exception. +    Result = false; +  } +  return Result; +} + +#else // !_MSC_VER + +#if defined(LLVM_ON_WIN32) +// This is a non-MSVC compiler, probably mingw gcc or clang without +// -fms-extensions. Use vectored exception handling (VEH). +// +// On Windows, we can make use of vectored exception handling to catch most +// crashing situations.  Note that this does mean we will be alerted of +// exceptions *before* structured exception handling has the opportunity to +// catch it. Unfortunately, this causes problems in practice with other code +// running on threads with LLVM crash recovery contexts, so we would like to +// eventually move away from VEH.  // -// Vectored exception handling is built on top of SEH, and so it -// works on a per-thread basis. +// Vectored works on a per-thread basis, which is an advantage over +// SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have +// any native support for chaining exception handlers, but VEH allows more than +// one.  //  // The vectored exception handler functionality was added in Windows  // XP, so if support for older versions of Windows is required,  // it will have to be added. -// -// If we want to support as far back as Win2k, we could use the -// SetUnhandledExceptionFilter API, but there's a risk of that -// being entirely overwritten (it's not a chain). + +#include "Windows/WindowsSupport.h"  static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)  { +  // DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported +  // compilers and platforms, so we define it manually. +  constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL; +  switch (ExceptionInfo->ExceptionRecord->ExceptionCode) +  { +  case DBG_PRINTEXCEPTION_C: +  case DbgPrintExceptionWideC: +  case 0x406D1388:  // set debugger thread name +    return EXCEPTION_CONTINUE_EXECUTION; +  } +    // Lookup the current thread local recovery object.    const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); @@ -192,14 +252,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)  // non-NULL, valid VEH handles, or NULL.  static sys::ThreadLocal<const void> sCurrentExceptionHandle; -void CrashRecoveryContext::Enable() { -  sys::ScopedLock L(*gCrashRecoveryContextMutex); - -  if (gCrashRecoveryEnabled) -    return; - -  gCrashRecoveryEnabled = true; - +static void installExceptionOrSignalHandlers() {    // We can set up vectored exception handling now.  We will install our    // handler as the front of the list, though there's no assurances that    // it will remain at the front (another call could install itself before @@ -208,14 +261,7 @@ void CrashRecoveryContext::Enable() {    sCurrentExceptionHandle.set(handle);  } -void CrashRecoveryContext::Disable() { -  sys::ScopedLock L(*gCrashRecoveryContextMutex); - -  if (!gCrashRecoveryEnabled) -    return; - -  gCrashRecoveryEnabled = false; - +static void uninstallExceptionOrSignalHandlers() {    PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get());    if (currentHandle) {      // Now we can remove the vectored exception handler from the chain @@ -226,7 +272,7 @@ void CrashRecoveryContext::Disable() {    }  } -#else +#else // !LLVM_ON_WIN32  // Generic POSIX implementation.  // @@ -278,14 +324,7 @@ static void CrashRecoverySignalHandler(int Signal) {      const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();  } -void CrashRecoveryContext::Enable() { -  sys::ScopedLock L(*gCrashRecoveryContextMutex); - -  if (gCrashRecoveryEnabled) -    return; - -  gCrashRecoveryEnabled = true; - +static void installExceptionOrSignalHandlers() {    // Setup the signal handler.    struct sigaction Handler;    Handler.sa_handler = CrashRecoverySignalHandler; @@ -297,20 +336,13 @@ void CrashRecoveryContext::Enable() {    }  } -void CrashRecoveryContext::Disable() { -  sys::ScopedLock L(*gCrashRecoveryContextMutex); - -  if (!gCrashRecoveryEnabled) -    return; - -  gCrashRecoveryEnabled = false; - +static void uninstallExceptionOrSignalHandlers() {    // Restore the previous signal handlers.    for (unsigned i = 0; i != NumSignals; ++i)      sigaction(Signals[i], &PrevActions[i], nullptr);  } -#endif +#endif // !LLVM_ON_WIN32  bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {    // If crash recovery is disabled, do nothing. @@ -328,6 +360,8 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {    return true;  } +#endif // !_MSC_VER +  void CrashRecoveryContext::HandleCrash() {    CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;    assert(CRCI && "Crash recovery context never initialized!");  | 
