[llvm-branch-commits] [clang] 92f7aeb - [Clang][Driver] In -fintegrated-cc1 mode, avoid crashing on exit after a compiler crash

Hans Wennborg via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Mar 13 05:51:26 PDT 2020


Author: Alexandre Ganea
Date: 2020-03-13T13:44:42+01:00
New Revision: 92f7aebe2d7e03d7d04b4d2f978482268b63aa7f

URL: https://github.com/llvm/llvm-project/commit/92f7aebe2d7e03d7d04b4d2f978482268b63aa7f
DIFF: https://github.com/llvm/llvm-project/commit/92f7aebe2d7e03d7d04b4d2f978482268b63aa7f.diff

LOG: [Clang][Driver] In -fintegrated-cc1 mode, avoid crashing on exit after a compiler crash

After a crash catched by the CrashRecoveryContext, this patch prevents from accessing dangling pointers in TimerGroup structures before the clang tool exits. Previously, the default TimerGroup had internal linked lists which were still pointing to old Timer or TimerGroup instances, which lived in stack frames released by the CrashRecoveryContext.

Fixes PR45164.

Differential Revision: https://reviews.llvm.org/D76099

(cherry picked from commit 28ad9fc20823678881baa0d723834b88ea9e8e3a)

Added: 
    

Modified: 
    clang/lib/Lex/Pragma.cpp
    clang/tools/driver/driver.cpp
    llvm/include/llvm/Support/ManagedStatic.h
    llvm/include/llvm/Support/Timer.h
    llvm/lib/Support/Timer.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index a8cd18b123b0..57a95815488e 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -42,6 +42,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Timer.h"
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
@@ -1038,6 +1039,8 @@ struct PragmaDebugHandler : public PragmaHandler {
       if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
         llvm_unreachable("This is an assertion!");
     } else if (II->isStr("crash")) {
+      llvm::Timer T("crash", "pragma crash");
+      llvm::TimeRegion R(&T);
       if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
         LLVM_BUILTIN_TRAP;
     } else if (II->isStr("parser_crash")) {

diff  --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 4457e40ff04b..7b3968341cc7 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -30,6 +30,7 @@
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/OptTable.h"
 #include "llvm/Option/Option.h"
+#include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/CrashRecoveryContext.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -491,6 +492,7 @@ int main(int argc_, const char **argv_) {
 
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
   int Res = 1;
+  bool IsCrash = false;
   if (C && !C->containsError()) {
     SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
     Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
@@ -517,11 +519,11 @@ int main(int argc_, const char **argv_) {
       // If result status is 70, then the driver command reported a fatal error.
       // On Windows, abort will return an exit code of 3.  In these cases,
       // generate additional diagnostic information if possible.
-      bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
+      IsCrash = CommandRes < 0 || CommandRes == 70;
 #ifdef _WIN32
-      DiagnoseCrash |= CommandRes == 3;
+      IsCrash |= CommandRes == 3;
 #endif
-      if (DiagnoseCrash) {
+      if (IsCrash) {
         TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
         break;
       }
@@ -530,10 +532,16 @@ int main(int argc_, const char **argv_) {
 
   Diags.getClient()->finish();
 
-  // If any timers were active but haven't been destroyed yet, print their
-  // results now.  This happens in -disable-free mode.
-  llvm::TimerGroup::printAll(llvm::errs());
-  llvm::TimerGroup::clearAll();
+  if (!UseNewCC1Process && IsCrash) {
+    // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because
+    // the internal linked list might point to already released stack frames.
+    llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup());
+  } else {
+    // If any timers were active but haven't been destroyed yet, print their
+    // results now.  This happens in -disable-free mode.
+    llvm::TimerGroup::printAll(llvm::errs());
+    llvm::TimerGroup::clearAll();
+  }
 
 #ifdef _WIN32
   // Exit status should not be negative on Win32, unless abnormal termination.

diff  --git a/llvm/include/llvm/Support/ManagedStatic.h b/llvm/include/llvm/Support/ManagedStatic.h
index e65bb051f181..bbd0d04ed040 100644
--- a/llvm/include/llvm/Support/ManagedStatic.h
+++ b/llvm/include/llvm/Support/ManagedStatic.h
@@ -102,6 +102,12 @@ class ManagedStatic : public ManagedStaticBase {
   }
 
   const C *operator->() const { return &**this; }
+
+  // Extract the instance, leaving the ManagedStatic uninitialized. The
+  // user is then responsible for the lifetime of the returned instance.
+  C *claim() {
+    return static_cast<C *>(Ptr.exchange(nullptr));
+  }
 };
 
 /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.

diff  --git a/llvm/include/llvm/Support/Timer.h b/llvm/include/llvm/Support/Timer.h
index a298ecd90404..045ac448bdb4 100644
--- a/llvm/include/llvm/Support/Timer.h
+++ b/llvm/include/llvm/Support/Timer.h
@@ -230,6 +230,11 @@ class TimerGroup {
   /// used by the Statistic code to influence the construction and destruction
   /// order of the global timer lists.
   static void ConstructTimerLists();
+
+  /// This makes the default group unmanaged, and lets the user manage the
+  /// group's lifetime.
+  static std::unique_ptr<TimerGroup> aquireDefaultGroup();
+
 private:
   friend class Timer;
   friend void PrintStatisticsJSON(raw_ostream &OS);

diff  --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp
index 613d2eaae6d3..2d3d00812826 100644
--- a/llvm/lib/Support/Timer.cpp
+++ b/llvm/lib/Support/Timer.cpp
@@ -441,3 +441,7 @@ const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
 void TimerGroup::ConstructTimerLists() {
   (void)*NamedGroupedTimers;
 }
+
+std::unique_ptr<TimerGroup> TimerGroup::aquireDefaultGroup() {
+  return std::unique_ptr<TimerGroup>(DefaultTimerGroup.claim());
+}


        


More information about the llvm-branch-commits mailing list