From e94e0984dfd22ede6211080d1f3e47138f1ea857 Mon Sep 17 00:00:00 2001 From: Filip Pizlo Date: Fri, 13 Sep 2013 22:59:47 +0000 Subject: [PATCH] Make PrettyStackTraceEntry use ManagedStatic for its ThreadLocal. This was somewhat tricky because ~PrettyStackTraceEntry() may run after llvm_shutdown() has been called. This is rare and only happens for a common idiom used in the main() functions of command-line tools. This works around the idiom by skipping the stack clean-up if the PrettyStackTraceHead ManagedStatic is not constructed (i.e. llvm_shutdown() has been called). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190730 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/ManagedStatic.h | 1 - lib/Support/PrettyStackTrace.cpp | 28 ++++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/llvm/Support/ManagedStatic.h b/include/llvm/Support/ManagedStatic.h index 4171d1bec8d..5587618d11b 100644 --- a/include/llvm/Support/ManagedStatic.h +++ b/include/llvm/Support/ManagedStatic.h @@ -99,7 +99,6 @@ public: /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. void llvm_shutdown(); - /// llvm_shutdown_obj - This is a simple helper class that calls /// llvm_shutdown() when it is destroyed. struct llvm_shutdown_obj { diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index 23ee5ab105a..315008ae810 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" #include "llvm/Support/Watchdog.h" @@ -30,8 +31,7 @@ namespace llvm { bool DisablePrettyStackTrace = false; } -// FIXME: This should be thread local when llvm supports threads. -static sys::ThreadLocal PrettyStackTraceHead; +static ManagedStatic > PrettyStackTraceHead; static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ unsigned NextID = 0; @@ -49,12 +49,12 @@ static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ /// PrintCurStackTrace - Print the current stack trace to the specified stream. static void PrintCurStackTrace(raw_ostream &OS) { // Don't print an empty trace. - if (PrettyStackTraceHead.get() == 0) return; + if (PrettyStackTraceHead->get() == 0) return; // If there are pretty stack frames registered, walk and emit them. OS << "Stack dump:\n"; - PrintStack(PrettyStackTraceHead.get(), OS); + PrintStack(PrettyStackTraceHead->get(), OS); OS.flush(); } @@ -114,14 +114,26 @@ PrettyStackTraceEntry::PrettyStackTraceEntry() { (void)HandlerRegistered; // Link ourselves. - NextEntry = PrettyStackTraceHead.get(); - PrettyStackTraceHead.set(this); + NextEntry = PrettyStackTraceHead->get(); + PrettyStackTraceHead->set(this); } PrettyStackTraceEntry::~PrettyStackTraceEntry() { - assert(PrettyStackTraceHead.get() == this && + // Do nothing if PrettyStackTraceHead is uninitialized. This can only happen + // if a shutdown occurred after we created the PrettyStackTraceEntry. That + // does occur in the following idiom: + // + // PrettyStackTraceProgram X(...); + // llvm_shutdown_obj Y; + // + // Without this check, we may end up removing ourselves from the stack trace + // after PrettyStackTraceHead has already been destroyed. + if (!PrettyStackTraceHead.isConstructed()) + return; + + assert(PrettyStackTraceHead->get() == this && "Pretty stack trace entry destruction is out of order"); - PrettyStackTraceHead.set(getNextEntry()); + PrettyStackTraceHead->set(getNextEntry()); } void PrettyStackTraceString::print(raw_ostream &OS) const {