119a3b374SDaniel Dunbar //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===//
219a3b374SDaniel Dunbar //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
619a3b374SDaniel Dunbar //
719a3b374SDaniel Dunbar //===----------------------------------------------------------------------===//
819a3b374SDaniel Dunbar
919a3b374SDaniel Dunbar #include "llvm/Support/CrashRecoveryContext.h"
10432a3883SNico Weber #include "llvm/Config/llvm-config.h"
11ed0881b2SChandler Carruth #include "llvm/Support/ErrorHandling.h"
12fbbc41f8Sserge-sans-paille #include "llvm/Support/ExitCodes.h"
13f2189bf3SFilip Pizlo #include "llvm/Support/ManagedStatic.h"
14a1f16998SAlexandre Ganea #include "llvm/Support/Signals.h"
15447762daSMichael J. Spencer #include "llvm/Support/ThreadLocal.h"
1648c68a63STim Northover #include "llvm/Support/thread.h"
17928071aeSBenjamin Kramer #include <mutex>
1891d3cfedSDuncan P. N. Exon Smith #include <setjmp.h>
19a1f16998SAlexandre Ganea
2019a3b374SDaniel Dunbar using namespace llvm;
2119a3b374SDaniel Dunbar
2219a3b374SDaniel Dunbar namespace {
2319a3b374SDaniel Dunbar
2419a3b374SDaniel Dunbar struct CrashRecoveryContextImpl;
2519a3b374SDaniel Dunbar
2691d3cfedSDuncan P. N. Exon Smith static ManagedStatic<
27a40ccf62SZachary Turner sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
28af77e22bSDaniel Dunbar
2919a3b374SDaniel Dunbar struct CrashRecoveryContextImpl {
302692811dSNico Weber // When threads are disabled, this links up all active
312692811dSNico Weber // CrashRecoveryContextImpls. When threads are enabled there's one thread
322692811dSNico Weber // per CrashRecoveryContext and CurrentContext is a thread-local, so only one
332692811dSNico Weber // CrashRecoveryContextImpl is active per thread and this is always null.
3428dc4171SNico Weber const CrashRecoveryContextImpl *Next;
3528dc4171SNico Weber
36b30266edSDaniel Dunbar CrashRecoveryContext *CRC;
3719a3b374SDaniel Dunbar ::jmp_buf JumpBuffer;
3819a3b374SDaniel Dunbar volatile unsigned Failed : 1;
39f1d8f52aSArgyrios Kyrtzidis unsigned SwitchedThread : 1;
402a3fa0fcSAlexandre Ganea unsigned ValidJumpBuffer : 1;
4119a3b374SDaniel Dunbar
4219a3b374SDaniel Dunbar public:
CrashRecoveryContextImpl__anond5a59f510111::CrashRecoveryContextImpl43a349c091SReid Kleckner CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
442a3fa0fcSAlexandre Ganea : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {
4528dc4171SNico Weber Next = CurrentContext->get();
46f2189bf3SFilip Pizlo CurrentContext->set(this);
47af77e22bSDaniel Dunbar }
~CrashRecoveryContextImpl__anond5a59f510111::CrashRecoveryContextImpl48af77e22bSDaniel Dunbar ~CrashRecoveryContextImpl() {
49f1d8f52aSArgyrios Kyrtzidis if (!SwitchedThread)
5028dc4171SNico Weber CurrentContext->set(Next);
51af77e22bSDaniel Dunbar }
5219a3b374SDaniel Dunbar
535f8f34e4SAdrian Prantl /// Called when the separate crash-recovery thread was finished, to
54f1d8f52aSArgyrios Kyrtzidis /// indicate that we don't need to clear the thread-local CurrentContext.
setSwitchedThread__anond5a59f510111::CrashRecoveryContextImpl5528dc4171SNico Weber void setSwitchedThread() {
5628dc4171SNico Weber #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
5728dc4171SNico Weber SwitchedThread = true;
5828dc4171SNico Weber #endif
5928dc4171SNico Weber }
60f1d8f52aSArgyrios Kyrtzidis
61a1f16998SAlexandre Ganea // If the function ran by the CrashRecoveryContext crashes or fails, then
62a1f16998SAlexandre Ganea // 'RetCode' represents the returned error code, as if it was returned by a
63a1f16998SAlexandre Ganea // process. 'Context' represents the signal type on Unix; on Windows, it is
64a1f16998SAlexandre Ganea // the ExceptionContext.
HandleCrash__anond5a59f510111::CrashRecoveryContextImpl65a1f16998SAlexandre Ganea void HandleCrash(int RetCode, uintptr_t Context) {
6609b0c789SDaniel Dunbar // Eliminate the current context entry, to avoid re-entering in case the
6709b0c789SDaniel Dunbar // cleanup code crashes.
6828dc4171SNico Weber CurrentContext->set(Next);
6909b0c789SDaniel Dunbar
7019a3b374SDaniel Dunbar assert(!Failed && "Crash recovery context already failed!");
7119a3b374SDaniel Dunbar Failed = true;
7219a3b374SDaniel Dunbar
73a1f16998SAlexandre Ganea if (CRC->DumpStackAndCleanupOnFailure)
74a1f16998SAlexandre Ganea sys::CleanupOnSignal(Context);
75a1f16998SAlexandre Ganea
76a1f16998SAlexandre Ganea CRC->RetCode = RetCode;
7719a3b374SDaniel Dunbar
7819a3b374SDaniel Dunbar // Jump back to the RunSafely we were called under.
792a3fa0fcSAlexandre Ganea if (ValidJumpBuffer)
8019a3b374SDaniel Dunbar longjmp(JumpBuffer, 1);
812a3fa0fcSAlexandre Ganea
822a3fa0fcSAlexandre Ganea // Otherwise let the caller decide of the outcome of the crash. Currently
832a3fa0fcSAlexandre Ganea // this occurs when using SEH on Windows with MSVC or clang-cl.
8419a3b374SDaniel Dunbar }
8519a3b374SDaniel Dunbar };
860164d546SSimon Pilgrim } // namespace
8719a3b374SDaniel Dunbar
88d6503659SJacques Pienaar static ManagedStatic<std::mutex> gCrashRecoveryContextMutex;
89d6503659SJacques Pienaar static bool gCrashRecoveryEnabled = false;
9091d3cfedSDuncan P. N. Exon Smith
9191d3cfedSDuncan P. N. Exon Smith static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
92ab1a242eSTed Kremenek tlIsRecoveringFromCrash;
93ab1a242eSTed Kremenek
94710c1cebSReid Kleckner static void installExceptionOrSignalHandlers();
95710c1cebSReid Kleckner static void uninstallExceptionOrSignalHandlers();
96710c1cebSReid Kleckner
973a3cb929SKazu Hirata CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() = default;
98c44d3cf5STed Kremenek
CrashRecoveryContext()9924f51057SAlexandre Ganea CrashRecoveryContext::CrashRecoveryContext() {
10024f51057SAlexandre Ganea // On Windows, if abort() was previously triggered (and caught by a previous
10124f51057SAlexandre Ganea // CrashRecoveryContext) the Windows CRT removes our installed signal handler,
10224f51057SAlexandre Ganea // so we need to install it again.
10324f51057SAlexandre Ganea sys::DisableSystemDialogsOnCrash();
10424f51057SAlexandre Ganea }
10524f51057SAlexandre Ganea
~CrashRecoveryContext()10619a3b374SDaniel Dunbar CrashRecoveryContext::~CrashRecoveryContext() {
107c44d3cf5STed Kremenek // Reclaim registered resources.
108c44d3cf5STed Kremenek CrashRecoveryContextCleanup *i = head;
10928dc4171SNico Weber const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get();
11028dc4171SNico Weber tlIsRecoveringFromCrash->set(this);
111c44d3cf5STed Kremenek while (i) {
112c44d3cf5STed Kremenek CrashRecoveryContextCleanup *tmp = i;
113c44d3cf5STed Kremenek i = tmp->next;
11432aea2e4STed Kremenek tmp->cleanupFired = true;
115857e5355STed Kremenek tmp->recoverResources();
116c44d3cf5STed Kremenek delete tmp;
117c44d3cf5STed Kremenek }
11828dc4171SNico Weber tlIsRecoveringFromCrash->set(PC);
119c44d3cf5STed Kremenek
12019a3b374SDaniel Dunbar CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
12119a3b374SDaniel Dunbar delete CRCI;
12219a3b374SDaniel Dunbar }
12319a3b374SDaniel Dunbar
isRecoveringFromCrash()124ab1a242eSTed Kremenek bool CrashRecoveryContext::isRecoveringFromCrash() {
125c10719f5SCraig Topper return tlIsRecoveringFromCrash->get() != nullptr;
126ab1a242eSTed Kremenek }
127ab1a242eSTed Kremenek
GetCurrent()128b30266edSDaniel Dunbar CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
129794a0714STed Kremenek if (!gCrashRecoveryEnabled)
130c10719f5SCraig Topper return nullptr;
131794a0714STed Kremenek
132f2189bf3SFilip Pizlo const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
133b30266edSDaniel Dunbar if (!CRCI)
134c10719f5SCraig Topper return nullptr;
135b30266edSDaniel Dunbar
136b30266edSDaniel Dunbar return CRCI->CRC;
137b30266edSDaniel Dunbar }
138b30266edSDaniel Dunbar
Enable()139710c1cebSReid Kleckner void CrashRecoveryContext::Enable() {
140d6503659SJacques Pienaar std::lock_guard<std::mutex> L(*gCrashRecoveryContextMutex);
141d6503659SJacques Pienaar // FIXME: Shouldn't this be a refcount or something?
142710c1cebSReid Kleckner if (gCrashRecoveryEnabled)
143710c1cebSReid Kleckner return;
144710c1cebSReid Kleckner gCrashRecoveryEnabled = true;
145710c1cebSReid Kleckner installExceptionOrSignalHandlers();
146710c1cebSReid Kleckner }
147710c1cebSReid Kleckner
Disable()148710c1cebSReid Kleckner void CrashRecoveryContext::Disable() {
149d6503659SJacques Pienaar std::lock_guard<std::mutex> L(*gCrashRecoveryContextMutex);
150710c1cebSReid Kleckner if (!gCrashRecoveryEnabled)
151710c1cebSReid Kleckner return;
152710c1cebSReid Kleckner gCrashRecoveryEnabled = false;
153710c1cebSReid Kleckner uninstallExceptionOrSignalHandlers();
154710c1cebSReid Kleckner }
155710c1cebSReid Kleckner
registerCleanup(CrashRecoveryContextCleanup * cleanup)156c44d3cf5STed Kremenek void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)
157c44d3cf5STed Kremenek {
158c44d3cf5STed Kremenek if (!cleanup)
159c44d3cf5STed Kremenek return;
160c44d3cf5STed Kremenek if (head)
161c44d3cf5STed Kremenek head->prev = cleanup;
162c44d3cf5STed Kremenek cleanup->next = head;
163c44d3cf5STed Kremenek head = cleanup;
164c44d3cf5STed Kremenek }
165c44d3cf5STed Kremenek
166c44d3cf5STed Kremenek void
unregisterCleanup(CrashRecoveryContextCleanup * cleanup)167c44d3cf5STed Kremenek CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
168c44d3cf5STed Kremenek if (!cleanup)
169c44d3cf5STed Kremenek return;
170c44d3cf5STed Kremenek if (cleanup == head) {
171c44d3cf5STed Kremenek head = cleanup->next;
172c44d3cf5STed Kremenek if (head)
173c10719f5SCraig Topper head->prev = nullptr;
174c44d3cf5STed Kremenek }
175c44d3cf5STed Kremenek else {
176c44d3cf5STed Kremenek cleanup->prev->next = cleanup->next;
177c44d3cf5STed Kremenek if (cleanup->next)
178c44d3cf5STed Kremenek cleanup->next->prev = cleanup->prev;
179c44d3cf5STed Kremenek }
180c44d3cf5STed Kremenek delete cleanup;
181c44d3cf5STed Kremenek }
182c44d3cf5STed Kremenek
183710c1cebSReid Kleckner #if defined(_MSC_VER)
184faace365SAlexandre Ganea
185faace365SAlexandre Ganea #include <windows.h> // for GetExceptionInformation
186faace365SAlexandre Ganea
187710c1cebSReid Kleckner // If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way
188710c1cebSReid Kleckner // better than VEH. Vectored exception handling catches all exceptions happening
189710c1cebSReid Kleckner // on the thread with installed exception handlers, so it can interfere with
190710c1cebSReid Kleckner // internal exception handling of other libraries on that thread. SEH works
191710c1cebSReid Kleckner // exactly as you would expect normal exception handling to work: it only
192710c1cebSReid Kleckner // catches exceptions if they would bubble out from the stack frame with __try /
193710c1cebSReid Kleckner // __except.
194af77e22bSDaniel Dunbar
installExceptionOrSignalHandlers()195710c1cebSReid Kleckner static void installExceptionOrSignalHandlers() {}
uninstallExceptionOrSignalHandlers()196710c1cebSReid Kleckner static void uninstallExceptionOrSignalHandlers() {}
1971eae12ccSNAKAMURA Takumi
198a1f16998SAlexandre Ganea // We need this function because the call to GetExceptionInformation() can only
199a1f16998SAlexandre Ganea // occur inside the __except evaluation block
ExceptionFilter(_EXCEPTION_POINTERS * Except)2002a3fa0fcSAlexandre Ganea static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
2012a3fa0fcSAlexandre Ganea // Lookup the current thread local recovery object.
2022a3fa0fcSAlexandre Ganea const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
2032a3fa0fcSAlexandre Ganea
2042a3fa0fcSAlexandre Ganea if (!CRCI) {
2052a3fa0fcSAlexandre Ganea // Something has gone horribly wrong, so let's just tell everyone
2062a3fa0fcSAlexandre Ganea // to keep searching
2072a3fa0fcSAlexandre Ganea CrashRecoveryContext::Disable();
2082a3fa0fcSAlexandre Ganea return EXCEPTION_CONTINUE_SEARCH;
2092a3fa0fcSAlexandre Ganea }
2102a3fa0fcSAlexandre Ganea
2112a3fa0fcSAlexandre Ganea int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
212faace365SAlexandre Ganea if ((RetCode & 0xF0000000) == 0xE0000000)
213faace365SAlexandre Ganea RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
2142a3fa0fcSAlexandre Ganea
2152a3fa0fcSAlexandre Ganea // Handle the crash
2162a3fa0fcSAlexandre Ganea const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
2172a3fa0fcSAlexandre Ganea RetCode, reinterpret_cast<uintptr_t>(Except));
2182a3fa0fcSAlexandre Ganea
219a1f16998SAlexandre Ganea return EXCEPTION_EXECUTE_HANDLER;
220a1f16998SAlexandre Ganea }
221a1f16998SAlexandre Ganea
22231e07692SHans Wennborg #if defined(__clang__) && defined(_M_IX86)
22331e07692SHans Wennborg // Work around PR44697.
22431e07692SHans Wennborg __attribute__((optnone))
22531e07692SHans Wennborg #endif
RunSafely(function_ref<void ()> Fn)226710c1cebSReid Kleckner bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
227710c1cebSReid Kleckner if (!gCrashRecoveryEnabled) {
228710c1cebSReid Kleckner Fn();
229710c1cebSReid Kleckner return true;
230710c1cebSReid Kleckner }
2312a3fa0fcSAlexandre Ganea assert(!Impl && "Crash recovery context already initialized!");
2322a3fa0fcSAlexandre Ganea Impl = new CrashRecoveryContextImpl(this);
2332a3fa0fcSAlexandre Ganea __try {
2342a3fa0fcSAlexandre Ganea Fn();
2352a3fa0fcSAlexandre Ganea } __except (ExceptionFilter(GetExceptionInformation())) {
2362a3fa0fcSAlexandre Ganea return false;
2372a3fa0fcSAlexandre Ganea }
2382a3fa0fcSAlexandre Ganea return true;
239710c1cebSReid Kleckner }
240710c1cebSReid Kleckner
241710c1cebSReid Kleckner #else // !_MSC_VER
242710c1cebSReid Kleckner
243712e8d29SNico Weber #if defined(_WIN32)
244710c1cebSReid Kleckner // This is a non-MSVC compiler, probably mingw gcc or clang without
245710c1cebSReid Kleckner // -fms-extensions. Use vectored exception handling (VEH).
2461eae12ccSNAKAMURA Takumi //
247710c1cebSReid Kleckner // On Windows, we can make use of vectored exception handling to catch most
248710c1cebSReid Kleckner // crashing situations. Note that this does mean we will be alerted of
249710c1cebSReid Kleckner // exceptions *before* structured exception handling has the opportunity to
250710c1cebSReid Kleckner // catch it. Unfortunately, this causes problems in practice with other code
251710c1cebSReid Kleckner // running on threads with LLVM crash recovery contexts, so we would like to
252710c1cebSReid Kleckner // eventually move away from VEH.
253710c1cebSReid Kleckner //
254710c1cebSReid Kleckner // Vectored works on a per-thread basis, which is an advantage over
255710c1cebSReid Kleckner // SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have
256710c1cebSReid Kleckner // any native support for chaining exception handlers, but VEH allows more than
257710c1cebSReid Kleckner // one.
2581eae12ccSNAKAMURA Takumi //
2591eae12ccSNAKAMURA Takumi // The vectored exception handler functionality was added in Windows
2601eae12ccSNAKAMURA Takumi // XP, so if support for older versions of Windows is required,
2611eae12ccSNAKAMURA Takumi // it will have to be added.
262710c1cebSReid Kleckner
26301f9abbbSHans Wennborg #include "llvm/Support/Windows/WindowsSupport.h"
2641eae12ccSNAKAMURA Takumi
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)26591d3cfedSDuncan P. N. Exon Smith static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
2661eae12ccSNAKAMURA Takumi {
2670daa7074SZachary Turner // DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported
2680daa7074SZachary Turner // compilers and platforms, so we define it manually.
2690daa7074SZachary Turner constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
27013e87f43SZachary Turner switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
27113e87f43SZachary Turner {
27213e87f43SZachary Turner case DBG_PRINTEXCEPTION_C:
2730daa7074SZachary Turner case DbgPrintExceptionWideC:
27413e87f43SZachary Turner case 0x406D1388: // set debugger thread name
27513e87f43SZachary Turner return EXCEPTION_CONTINUE_EXECUTION;
27613e87f43SZachary Turner }
27713e87f43SZachary Turner
2781eae12ccSNAKAMURA Takumi // Lookup the current thread local recovery object.
279f2189bf3SFilip Pizlo const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
2801eae12ccSNAKAMURA Takumi
2811eae12ccSNAKAMURA Takumi if (!CRCI) {
2821eae12ccSNAKAMURA Takumi // Something has gone horribly wrong, so let's just tell everyone
2831eae12ccSNAKAMURA Takumi // to keep searching
2841eae12ccSNAKAMURA Takumi CrashRecoveryContext::Disable();
2851eae12ccSNAKAMURA Takumi return EXCEPTION_CONTINUE_SEARCH;
2861eae12ccSNAKAMURA Takumi }
2871eae12ccSNAKAMURA Takumi
2881eae12ccSNAKAMURA Takumi // TODO: We can capture the stack backtrace here and store it on the
2891eae12ccSNAKAMURA Takumi // implementation if we so choose.
2901eae12ccSNAKAMURA Takumi
291faace365SAlexandre Ganea int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
292faace365SAlexandre Ganea if ((RetCode & 0xF0000000) == 0xE0000000)
293faace365SAlexandre Ganea RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
294faace365SAlexandre Ganea
2951eae12ccSNAKAMURA Takumi // Handle the crash
296a1f16998SAlexandre Ganea const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
297faace365SAlexandre Ganea RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));
2981eae12ccSNAKAMURA Takumi
2991eae12ccSNAKAMURA Takumi // Note that we don't actually get here because HandleCrash calls
3001eae12ccSNAKAMURA Takumi // longjmp, which means the HandleCrash function never returns.
3011eae12ccSNAKAMURA Takumi llvm_unreachable("Handled the crash, should have longjmp'ed out of here");
3021eae12ccSNAKAMURA Takumi }
3031eae12ccSNAKAMURA Takumi
3041eae12ccSNAKAMURA Takumi // Because the Enable and Disable calls are static, it means that
3051eae12ccSNAKAMURA Takumi // there may not actually be an Impl available, or even a current
3061eae12ccSNAKAMURA Takumi // CrashRecoveryContext at all. So we make use of a thread-local
3071eae12ccSNAKAMURA Takumi // exception table. The handles contained in here will either be
3081eae12ccSNAKAMURA Takumi // non-NULL, valid VEH handles, or NULL.
30991d3cfedSDuncan P. N. Exon Smith static sys::ThreadLocal<const void> sCurrentExceptionHandle;
310af77e22bSDaniel Dunbar
installExceptionOrSignalHandlers()311710c1cebSReid Kleckner static void installExceptionOrSignalHandlers() {
3121eae12ccSNAKAMURA Takumi // We can set up vectored exception handling now. We will install our
3131eae12ccSNAKAMURA Takumi // handler as the front of the list, though there's no assurances that
3141eae12ccSNAKAMURA Takumi // it will remain at the front (another call could install itself before
3151eae12ccSNAKAMURA Takumi // our handler). This 1) isn't likely, and 2) shouldn't cause problems.
3161eae12ccSNAKAMURA Takumi PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
3171eae12ccSNAKAMURA Takumi sCurrentExceptionHandle.set(handle);
31819a3b374SDaniel Dunbar }
31919a3b374SDaniel Dunbar
uninstallExceptionOrSignalHandlers()320710c1cebSReid Kleckner static void uninstallExceptionOrSignalHandlers() {
3211eae12ccSNAKAMURA Takumi PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get());
3221eae12ccSNAKAMURA Takumi if (currentHandle) {
3231eae12ccSNAKAMURA Takumi // Now we can remove the vectored exception handler from the chain
3241eae12ccSNAKAMURA Takumi ::RemoveVectoredExceptionHandler(currentHandle);
3251eae12ccSNAKAMURA Takumi
3261eae12ccSNAKAMURA Takumi // Reset the handle in our thread-local set.
3271eae12ccSNAKAMURA Takumi sCurrentExceptionHandle.set(NULL);
3281eae12ccSNAKAMURA Takumi }
32919a3b374SDaniel Dunbar }
33019a3b374SDaniel Dunbar
331712e8d29SNico Weber #else // !_WIN32
332af77e22bSDaniel Dunbar
333af77e22bSDaniel Dunbar // Generic POSIX implementation.
334af77e22bSDaniel Dunbar //
335af77e22bSDaniel Dunbar // This implementation relies on synchronous signals being delivered to the
336af77e22bSDaniel Dunbar // current thread. We use a thread local object to keep track of the active
337af77e22bSDaniel Dunbar // crash recovery context, and install signal handlers to invoke HandleCrash on
338af77e22bSDaniel Dunbar // the active object.
339af77e22bSDaniel Dunbar //
340a483302fSRafael Stahl // This implementation does not attempt to chain signal handlers in any
341af77e22bSDaniel Dunbar // reliable fashion -- if we get a signal outside of a crash recovery context we
342af77e22bSDaniel Dunbar // simply disable crash recovery and raise the signal again.
343af77e22bSDaniel Dunbar
34491d3cfedSDuncan P. N. Exon Smith #include <signal.h>
345af77e22bSDaniel Dunbar
34691d3cfedSDuncan P. N. Exon Smith static const int Signals[] =
34791d3cfedSDuncan P. N. Exon Smith { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
348f15014ffSBenjamin Kramer static const unsigned NumSignals = array_lengthof(Signals);
34991d3cfedSDuncan P. N. Exon Smith static struct sigaction PrevActions[NumSignals];
350af77e22bSDaniel Dunbar
CrashRecoverySignalHandler(int Signal)35191d3cfedSDuncan P. N. Exon Smith static void CrashRecoverySignalHandler(int Signal) {
352af77e22bSDaniel Dunbar // Lookup the current thread local recovery object.
353f2189bf3SFilip Pizlo const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
354af77e22bSDaniel Dunbar
355af77e22bSDaniel Dunbar if (!CRCI) {
356af77e22bSDaniel Dunbar // We didn't find a crash recovery context -- this means either we got a
357af77e22bSDaniel Dunbar // signal on a thread we didn't expect it on, the application got a signal
358af77e22bSDaniel Dunbar // outside of a crash recovery context, or something else went horribly
359af77e22bSDaniel Dunbar // wrong.
360af77e22bSDaniel Dunbar //
361af77e22bSDaniel Dunbar // Disable crash recovery and raise the signal again. The assumption here is
362af77e22bSDaniel Dunbar // that the enclosing application will terminate soon, and we won't want to
363af77e22bSDaniel Dunbar // attempt crash recovery again.
364af77e22bSDaniel Dunbar //
365af77e22bSDaniel Dunbar // This call of Disable isn't thread safe, but it doesn't actually matter.
366af77e22bSDaniel Dunbar CrashRecoveryContext::Disable();
367af77e22bSDaniel Dunbar raise(Signal);
368418e7046SDaniel Dunbar
369418e7046SDaniel Dunbar // The signal will be thrown once the signal mask is restored.
370418e7046SDaniel Dunbar return;
371af77e22bSDaniel Dunbar }
372af77e22bSDaniel Dunbar
373af77e22bSDaniel Dunbar // Unblock the signal we received.
374af77e22bSDaniel Dunbar sigset_t SigMask;
375af77e22bSDaniel Dunbar sigemptyset(&SigMask);
376af77e22bSDaniel Dunbar sigaddset(&SigMask, Signal);
377c10719f5SCraig Topper sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
378af77e22bSDaniel Dunbar
379f5314d15SAlexandre Ganea // Return the same error code as if the program crashed, as mentioned in the
380f5314d15SAlexandre Ganea // section "Exit Status for Commands":
381f5314d15SAlexandre Ganea // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
382f5314d15SAlexandre Ganea int RetCode = 128 + Signal;
383a1f16998SAlexandre Ganea
384a1f16998SAlexandre Ganea // Don't consider a broken pipe as a crash (see clang/lib/Driver/Driver.cpp)
385a1f16998SAlexandre Ganea if (Signal == SIGPIPE)
386a1f16998SAlexandre Ganea RetCode = EX_IOERR;
387a1f16998SAlexandre Ganea
388af77e22bSDaniel Dunbar if (CRCI)
389a1f16998SAlexandre Ganea const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal);
390af77e22bSDaniel Dunbar }
391af77e22bSDaniel Dunbar
installExceptionOrSignalHandlers()392710c1cebSReid Kleckner static void installExceptionOrSignalHandlers() {
393af77e22bSDaniel Dunbar // Setup the signal handler.
394af77e22bSDaniel Dunbar struct sigaction Handler;
395af77e22bSDaniel Dunbar Handler.sa_handler = CrashRecoverySignalHandler;
396af77e22bSDaniel Dunbar Handler.sa_flags = 0;
397af77e22bSDaniel Dunbar sigemptyset(&Handler.sa_mask);
398af77e22bSDaniel Dunbar
399af77e22bSDaniel Dunbar for (unsigned i = 0; i != NumSignals; ++i) {
400c90e82a7SDaniel Dunbar sigaction(Signals[i], &Handler, &PrevActions[i]);
401af77e22bSDaniel Dunbar }
402af77e22bSDaniel Dunbar }
403af77e22bSDaniel Dunbar
uninstallExceptionOrSignalHandlers()404710c1cebSReid Kleckner static void uninstallExceptionOrSignalHandlers() {
405af77e22bSDaniel Dunbar // Restore the previous signal handlers.
406af77e22bSDaniel Dunbar for (unsigned i = 0; i != NumSignals; ++i)
407c10719f5SCraig Topper sigaction(Signals[i], &PrevActions[i], nullptr);
408af77e22bSDaniel Dunbar }
409af77e22bSDaniel Dunbar
410712e8d29SNico Weber #endif // !_WIN32
411af77e22bSDaniel Dunbar
RunSafely(function_ref<void ()> Fn)412c167d656SRichard Smith bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
41319a3b374SDaniel Dunbar // If crash recovery is disabled, do nothing.
41419a3b374SDaniel Dunbar if (gCrashRecoveryEnabled) {
41519a3b374SDaniel Dunbar assert(!Impl && "Crash recovery context already initialized!");
416b30266edSDaniel Dunbar CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
41719a3b374SDaniel Dunbar Impl = CRCI;
41819a3b374SDaniel Dunbar
4192a3fa0fcSAlexandre Ganea CRCI->ValidJumpBuffer = true;
42019a3b374SDaniel Dunbar if (setjmp(CRCI->JumpBuffer) != 0) {
42119a3b374SDaniel Dunbar return false;
42219a3b374SDaniel Dunbar }
42319a3b374SDaniel Dunbar }
42419a3b374SDaniel Dunbar
425c167d656SRichard Smith Fn();
42619a3b374SDaniel Dunbar return true;
42719a3b374SDaniel Dunbar }
42819a3b374SDaniel Dunbar
429710c1cebSReid Kleckner #endif // !_MSC_VER
430710c1cebSReid Kleckner
HandleExit(int RetCode)4316da3d8b1SFangrui Song [[noreturn]] void CrashRecoveryContext::HandleExit(int RetCode) {
432faace365SAlexandre Ganea #if defined(_WIN32)
433faace365SAlexandre Ganea // SEH and VEH
434faace365SAlexandre Ganea ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);
435faace365SAlexandre Ganea #else
436faace365SAlexandre Ganea // On Unix we don't need to raise an exception, we go directly to
437faace365SAlexandre Ganea // HandleCrash(), then longjmp will unwind the stack for us.
438faace365SAlexandre Ganea CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
439faace365SAlexandre Ganea assert(CRCI && "Crash recovery context never initialized!");
440faace365SAlexandre Ganea CRCI->HandleCrash(RetCode, 0 /*no sig num*/);
441faace365SAlexandre Ganea #endif
442faace365SAlexandre Ganea llvm_unreachable("Most likely setjmp wasn't called!");
443faace365SAlexandre Ganea }
444faace365SAlexandre Ganea
isCrash(int RetCode)445*6beb2db7SAlexander Shaposhnikov bool CrashRecoveryContext::isCrash(int RetCode) {
44645b8a741SAlexandre Ganea #if defined(_WIN32)
44745b8a741SAlexandre Ganea // On Windows, the high bits are reserved for kernel return codes. Values
44845b8a741SAlexandre Ganea // starting with 0x80000000 are reserved for "warnings"; values of 0xC0000000
44945b8a741SAlexandre Ganea // and up are for "errors". In practice, both are interpreted as a
45045b8a741SAlexandre Ganea // non-continuable signal.
45145b8a741SAlexandre Ganea unsigned Code = ((unsigned)RetCode & 0xF0000000) >> 28;
45245b8a741SAlexandre Ganea if (Code != 0xC && Code != 8)
45345b8a741SAlexandre Ganea return false;
45445b8a741SAlexandre Ganea #else
45545b8a741SAlexandre Ganea // On Unix, signals are represented by return codes of 128 or higher.
456ec63dfe3SAlexandre Ganea // Exit code 128 is a reserved value and should not be raised as a signal.
45745b8a741SAlexandre Ganea if (RetCode <= 128)
45845b8a741SAlexandre Ganea return false;
459*6beb2db7SAlexander Shaposhnikov #endif
460*6beb2db7SAlexander Shaposhnikov return true;
461*6beb2db7SAlexander Shaposhnikov }
462*6beb2db7SAlexander Shaposhnikov
throwIfCrash(int RetCode)463*6beb2db7SAlexander Shaposhnikov bool CrashRecoveryContext::throwIfCrash(int RetCode) {
464*6beb2db7SAlexander Shaposhnikov if (!isCrash(RetCode))
465*6beb2db7SAlexander Shaposhnikov return false;
466*6beb2db7SAlexander Shaposhnikov #if defined(_WIN32)
467*6beb2db7SAlexander Shaposhnikov ::RaiseException(RetCode, 0, 0, NULL);
468*6beb2db7SAlexander Shaposhnikov #else
46945b8a741SAlexandre Ganea llvm::sys::unregisterHandlers();
47045b8a741SAlexandre Ganea raise(RetCode - 128);
47145b8a741SAlexandre Ganea #endif
47245b8a741SAlexandre Ganea return true;
47345b8a741SAlexandre Ganea }
47445b8a741SAlexandre Ganea
475e9012b03SArgyrios Kyrtzidis // FIXME: Portability.
setThreadBackgroundPriority()47691d3cfedSDuncan P. N. Exon Smith static void setThreadBackgroundPriority() {
477e9012b03SArgyrios Kyrtzidis #ifdef __APPLE__
478e9012b03SArgyrios Kyrtzidis setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
479e9012b03SArgyrios Kyrtzidis #endif
480e9012b03SArgyrios Kyrtzidis }
481e9012b03SArgyrios Kyrtzidis
hasThreadBackgroundPriority()48291d3cfedSDuncan P. N. Exon Smith static bool hasThreadBackgroundPriority() {
483e9012b03SArgyrios Kyrtzidis #ifdef __APPLE__
484e9012b03SArgyrios Kyrtzidis return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
485e9012b03SArgyrios Kyrtzidis #else
486e9012b03SArgyrios Kyrtzidis return false;
487e9012b03SArgyrios Kyrtzidis #endif
488e9012b03SArgyrios Kyrtzidis }
489f4d90ba9SDaniel Dunbar
49091d3cfedSDuncan P. N. Exon Smith namespace {
491f4d90ba9SDaniel Dunbar struct RunSafelyOnThreadInfo {
492c167d656SRichard Smith function_ref<void()> Fn;
493f4d90ba9SDaniel Dunbar CrashRecoveryContext *CRC;
494e9012b03SArgyrios Kyrtzidis bool UseBackgroundPriority;
495f4d90ba9SDaniel Dunbar bool Result;
496f4d90ba9SDaniel Dunbar };
4970164d546SSimon Pilgrim } // namespace
498f4d90ba9SDaniel Dunbar
RunSafelyOnThread_Dispatch(void * UserData)49991d3cfedSDuncan P. N. Exon Smith static void RunSafelyOnThread_Dispatch(void *UserData) {
500f4d90ba9SDaniel Dunbar RunSafelyOnThreadInfo *Info =
501f4d90ba9SDaniel Dunbar reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);
502e9012b03SArgyrios Kyrtzidis
503e9012b03SArgyrios Kyrtzidis if (Info->UseBackgroundPriority)
504e9012b03SArgyrios Kyrtzidis setThreadBackgroundPriority();
505e9012b03SArgyrios Kyrtzidis
506c167d656SRichard Smith Info->Result = Info->CRC->RunSafely(Info->Fn);
507f4d90ba9SDaniel Dunbar }
RunSafelyOnThread(function_ref<void ()> Fn,unsigned RequestedStackSize)508c167d656SRichard Smith bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn,
509f4d90ba9SDaniel Dunbar unsigned RequestedStackSize) {
510e9012b03SArgyrios Kyrtzidis bool UseBackgroundPriority = hasThreadBackgroundPriority();
511e9012b03SArgyrios Kyrtzidis RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };
51248c68a63STim Northover llvm::thread Thread(RequestedStackSize == 0
513a9c3c176SSam McCall ? llvm::None
51448c68a63STim Northover : llvm::Optional<unsigned>(RequestedStackSize),
51548c68a63STim Northover RunSafelyOnThread_Dispatch, &Info);
51648c68a63STim Northover Thread.join();
51748c68a63STim Northover
518f1d8f52aSArgyrios Kyrtzidis if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
519f1d8f52aSArgyrios Kyrtzidis CRC->setSwitchedThread();
520f4d90ba9SDaniel Dunbar return Info.Result;
521f4d90ba9SDaniel Dunbar }
522