Make PrettyStackTraceEntry use ManagedStatic for its ThreadLocal.
authorFilip Pizlo <fpizlo@apple.com>
Fri, 13 Sep 2013 22:59:47 +0000 (22:59 +0000)
committerFilip Pizlo <fpizlo@apple.com>
Fri, 13 Sep 2013 22:59:47 +0000 (22:59 +0000)
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
lib/Support/PrettyStackTrace.cpp

index 4171d1bec8dcee1272aec10dbc5a89a096b171d4..5587618d11bb60028b588fedab463445a088f19b 100644 (file)
@@ -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 {
index 23ee5ab105aec8316f598e42b261f2a4d4297bd2..315008ae810ed04d698ddb58d9cc4af81a805e1e 100644 (file)
@@ -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<const PrettyStackTraceEntry> PrettyStackTraceHead;
+static ManagedStatic<sys::ThreadLocal<const PrettyStackTraceEntry> > 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 {