aganea created this revision.
aganea added reviewers: rnk, hans, hubert.reinterpretcast, daltenty.
Herald added subscribers: llvm-commits, cfe-commits, hiraditya.
Herald added projects: clang, LLVM.
As reported here: https://reviews.llvm.org/D69825#1916865 and in PR45164, in
case of a compiler crash, Clang now reports a second crash related to
TimerGroups. The crash is caused by the TimerGroup's internal linked list which
still points to already freed stack frames, which were unwind by `longjmp()`
(or SEH on Windows) after the first compiler crash.
There's a second crash, not seen in PR45164, which happens when `llvm_shutdown`
is called: the static `DefaultTimerGroup` object is destroyed which causes more
iterating through the TimerGroups.
With this patch, we now 'steal' the `TimeGroup` instance from
`DefaultTimerGroup` and prevent any further iteration of the timers after the
initial crash.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D76099
Files:
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
Index: llvm/lib/Support/Timer.cpp
===================================================================
--- llvm/lib/Support/Timer.cpp
+++ llvm/lib/Support/Timer.cpp
@@ -442,3 +442,7 @@
void TimerGroup::ConstructTimerLists() {
(void)*NamedGroupedTimers;
}
+
+std::unique_ptr<TimerGroup> TimerGroup::aquireDefaultGroup() {
+ return std::unique_ptr<TimerGroup>(DefaultTimerGroup.claim());
+}
Index: llvm/include/llvm/Support/Timer.h
===================================================================
--- llvm/include/llvm/Support/Timer.h
+++ llvm/include/llvm/Support/Timer.h
@@ -230,6 +230,11 @@
/// 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);
Index: llvm/include/llvm/Support/ManagedStatic.h
===================================================================
--- llvm/include/llvm/Support/ManagedStatic.h
+++ llvm/include/llvm/Support/ManagedStatic.h
@@ -102,6 +102,12 @@
}
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.
Index: clang/tools/driver/driver.cpp
===================================================================
--- clang/tools/driver/driver.cpp
+++ 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 @@
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 @@
// 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 @@
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.
Index: clang/lib/Lex/Pragma.cpp
===================================================================
--- clang/lib/Lex/Pragma.cpp
+++ 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 @@
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")) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits