Fix nested CrashRecoveryContexts with LLVM_ENABLE_THREADS=OFF, allow them.

libclang uses a CrashRecoveryContext, and building a module does too. If a
module gets built through libclang, nested CrashRecoveryContexts are used.  They
work fine with threads as things are stored in ThreadLocal variables, but in
LLVM_ENABLE_THREADS=OFF builds the two recovery contexts would write to the
same globals.

To fix, keep active CrashRecoveryContextImpls in a list and have the global
point to the innermost one, and do something similar for
tlIsRecoveringFromCrash.

Necessary (but not sufficient) for PR11974 and PR20325

http://reviews.llvm.org/D11770

llvm-svn: 244251
This commit is contained in:
Nico Weber 2015-08-06 19:21:25 +00:00
parent 242ca930e8
commit 28dc4171e9
2 changed files with 14 additions and 8 deletions

View File

@ -39,8 +39,6 @@ class CrashRecoveryContextCleanup;
/// ///
/// ... no crash was detected ... /// ... no crash was detected ...
/// } /// }
///
/// Crash recovery contexts may not be nested.
class CrashRecoveryContext { class CrashRecoveryContext {
void *Impl; void *Impl;
CrashRecoveryContextCleanup *head; CrashRecoveryContextCleanup *head;

View File

@ -24,6 +24,8 @@ static ManagedStatic<
sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext; sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
struct CrashRecoveryContextImpl { struct CrashRecoveryContextImpl {
const CrashRecoveryContextImpl *Next;
CrashRecoveryContext *CRC; CrashRecoveryContext *CRC;
std::string Backtrace; std::string Backtrace;
::jmp_buf JumpBuffer; ::jmp_buf JumpBuffer;
@ -34,21 +36,26 @@ public:
CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
Failed(false), Failed(false),
SwitchedThread(false) { SwitchedThread(false) {
Next = CurrentContext->get();
CurrentContext->set(this); CurrentContext->set(this);
} }
~CrashRecoveryContextImpl() { ~CrashRecoveryContextImpl() {
if (!SwitchedThread) if (!SwitchedThread)
CurrentContext->erase(); CurrentContext->set(Next);
} }
/// \brief Called when the separate crash-recovery thread was finished, to /// \brief Called when the separate crash-recovery thread was finished, to
/// indicate that we don't need to clear the thread-local CurrentContext. /// indicate that we don't need to clear the thread-local CurrentContext.
void setSwitchedThread() { SwitchedThread = true; } void setSwitchedThread() {
#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
SwitchedThread = true;
#endif
}
void HandleCrash() { void HandleCrash() {
// Eliminate the current context entry, to avoid re-entering in case the // Eliminate the current context entry, to avoid re-entering in case the
// cleanup code crashes. // cleanup code crashes.
CurrentContext->erase(); CurrentContext->set(Next);
assert(!Failed && "Crash recovery context already failed!"); assert(!Failed && "Crash recovery context already failed!");
Failed = true; Failed = true;
@ -65,7 +72,7 @@ public:
static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex; static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex;
static bool gCrashRecoveryEnabled = false; static bool gCrashRecoveryEnabled = false;
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> > static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
tlIsRecoveringFromCrash; tlIsRecoveringFromCrash;
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
@ -73,7 +80,8 @@ CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
CrashRecoveryContext::~CrashRecoveryContext() { CrashRecoveryContext::~CrashRecoveryContext() {
// Reclaim registered resources. // Reclaim registered resources.
CrashRecoveryContextCleanup *i = head; CrashRecoveryContextCleanup *i = head;
tlIsRecoveringFromCrash->set(head); const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get();
tlIsRecoveringFromCrash->set(this);
while (i) { while (i) {
CrashRecoveryContextCleanup *tmp = i; CrashRecoveryContextCleanup *tmp = i;
i = tmp->next; i = tmp->next;
@ -81,7 +89,7 @@ CrashRecoveryContext::~CrashRecoveryContext() {
tmp->recoverResources(); tmp->recoverResources();
delete tmp; delete tmp;
} }
tlIsRecoveringFromCrash->erase(); tlIsRecoveringFromCrash->set(PC);
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
delete CRCI; delete CRCI;