Commit 92f7aebe authored by Alexandre Ganea's avatar Alexandre Ganea Committed by Hans Wennborg
Browse files

[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 28ad9fc2)
parent d9bd6e3c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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")) {
+15 −7
Original line number Diff line number Diff line
@@ -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 (!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.
+6 −0
Original line number Diff line number Diff line
@@ -102,6 +102,12 @@ public:
  }

  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.
+5 −0
Original line number Diff line number Diff line
@@ -230,6 +230,11 @@ public:
  /// 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);
+4 −0
Original line number Diff line number Diff line
@@ -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());
}