diff options
Diffstat (limited to 'llvm/lib/Support')
| -rw-r--r-- | llvm/lib/Support/CRC.cpp | 10 | ||||
| -rw-r--r-- | llvm/lib/Support/CrashRecoveryContext.cpp | 89 | ||||
| -rw-r--r-- | llvm/lib/Support/ErrorHandling.cpp | 3 | ||||
| -rw-r--r-- | llvm/lib/Support/Process.cpp | 10 | ||||
| -rw-r--r-- | llvm/lib/Support/Windows/Signals.inc | 8 | 
5 files changed, 86 insertions, 34 deletions
| diff --git a/llvm/lib/Support/CRC.cpp b/llvm/lib/Support/CRC.cpp index a3dba1a3aa10..2bc668beed32 100644 --- a/llvm/lib/Support/CRC.cpp +++ b/llvm/lib/Support/CRC.cpp @@ -85,7 +85,15 @@ uint32_t llvm::crc32(uint32_t CRC, ArrayRef<uint8_t> Data) {  #include <zlib.h>  uint32_t llvm::crc32(uint32_t CRC, ArrayRef<uint8_t> Data) { -  return ::crc32(CRC, (const Bytef *)Data.data(), Data.size()); +  // Zlib's crc32() only takes a 32-bit length, so we have to iterate for larger +  // sizes. One could use crc32_z() instead, but that's a recent (2017) addition +  // and may not be available on all systems. +  do { +    ArrayRef<uint8_t> Slice = Data.take_front(UINT32_MAX); +    CRC = ::crc32(CRC, (const Bytef *)Slice.data(), (uInt)Slice.size()); +    Data = Data.drop_front(Slice.size()); +  } while (Data.size() > 0); +  return CRC;  }  #endif diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index b9031f52375c..356835609830 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -14,9 +14,6 @@  #include "llvm/Support/ThreadLocal.h"  #include <mutex>  #include <setjmp.h> -#ifdef _WIN32 -#include <excpt.h> // for GetExceptionInformation -#endif  #if LLVM_ON_UNIX  #include <sysexits.h> // EX_IOERR  #endif @@ -41,11 +38,11 @@ struct CrashRecoveryContextImpl {    ::jmp_buf JumpBuffer;    volatile unsigned Failed : 1;    unsigned SwitchedThread : 1; +  unsigned ValidJumpBuffer : 1;  public: -  CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), -                                                        Failed(false), -                                                        SwitchedThread(false) { +  CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept +      : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {      Next = CurrentContext->get();      CurrentContext->set(this);    } @@ -80,10 +77,13 @@ public:      CRC->RetCode = RetCode;      // Jump back to the RunSafely we were called under. -    longjmp(JumpBuffer, 1); +    if (ValidJumpBuffer) +      longjmp(JumpBuffer, 1); + +    // Otherwise let the caller decide of the outcome of the crash. Currently +    // this occurs when using SEH on Windows with MSVC or clang-cl.    }  }; -  }  static ManagedStatic<std::mutex> gCrashRecoveryContextMutex; @@ -175,6 +175,9 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {  }  #if defined(_MSC_VER) + +#include <windows.h> // 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 @@ -188,30 +191,45 @@ static void uninstallExceptionOrSignalHandlers() {}  // We need this function because the call to GetExceptionInformation() can only  // occur inside the __except evaluation block -static int ExceptionFilter(bool DumpStackAndCleanup, -                           _EXCEPTION_POINTERS *Except) { -  if (DumpStackAndCleanup) -    sys::CleanupOnSignal((uintptr_t)Except); -  return EXCEPTION_EXECUTE_HANDLER; -} +static int ExceptionFilter(_EXCEPTION_POINTERS *Except) { +  // Lookup the current thread local recovery object. +  const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); -static bool InvokeFunctionCall(function_ref<void()> Fn, -                               bool DumpStackAndCleanup, int &RetCode) { -  __try { -    Fn(); -  } __except (ExceptionFilter(DumpStackAndCleanup, GetExceptionInformation())) { -    RetCode = GetExceptionCode(); -    return false; +  if (!CRCI) { +    // Something has gone horribly wrong, so let's just tell everyone +    // to keep searching +    CrashRecoveryContext::Disable(); +    return EXCEPTION_CONTINUE_SEARCH;    } -  return true; + +  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<CrashRecoveryContextImpl *>(CRCI)->HandleCrash( +      RetCode, reinterpret_cast<uintptr_t>(Except)); + +  return EXCEPTION_EXECUTE_HANDLER;  } +#if defined(__clang__) && defined(_M_IX86) +// Work around PR44697. +__attribute__((optnone)) +#endif  bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {    if (!gCrashRecoveryEnabled) {      Fn();      return true;    } -  return InvokeFunctionCall(Fn, DumpStackAndCleanupOnFailure, RetCode); +  assert(!Impl && "Crash recovery context already initialized!"); +  Impl = new CrashRecoveryContextImpl(this); +  __try { +    Fn(); +  } __except (ExceptionFilter(GetExceptionInformation())) { +    return false; +  } +  return true;  }  #else // !_MSC_VER @@ -264,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<CrashRecoveryContextImpl *>(CRCI)->HandleCrash( -      (int)ExceptionInfo->ExceptionRecord->ExceptionCode, -      reinterpret_cast<uintptr_t>(ExceptionInfo)); +      RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));    // Note that we don't actually get here because HandleCrash calls    // longjmp, which means the HandleCrash function never returns. @@ -388,6 +409,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {      CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);      Impl = CRCI; +    CRCI->ValidJumpBuffer = true;      if (setjmp(CRCI->JumpBuffer) != 0) {        return false;      } @@ -399,12 +421,19 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {  #endif // !_MSC_VER -void CrashRecoveryContext::HandleCrash() { -  CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; +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!"); -  // As per convention, -2 indicates a crash or timeout as opposed to failure to -  // execute (see llvm/include/llvm/Support/Program.h) -  CRCI->HandleCrash(-2, 0); +  CRCI->HandleCrash(RetCode, 0 /*no sig num*/); +#endif +  llvm_unreachable("Most likely setjmp wasn't called!");  }  // FIXME: Portability. 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 5b6471008159..509512f643d3 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" diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc index 8b525f1bd4ac..09e19ae41f1a 100644 --- a/llvm/lib/Support/Windows/Signals.inc +++ b/llvm/lib/Support/Windows/Signals.inc @@ -820,7 +820,13 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {                     << "\n";    } -  LocalPrintStackTrace(llvm::errs(), ep ? ep->ContextRecord : nullptr); +  // Stack unwinding appears to modify the context. Copy it to preserve the +  // caller's context. +  CONTEXT ContextCopy; +  if (ep) +    memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); + +  LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr);    return EXCEPTION_EXECUTE_HANDLER;  } | 
