Skip to content

Commit 92f7aeb

Browse files
aganeazmodem
authored andcommitted
[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 28ad9fc)
1 parent d9bd6e3 commit 92f7aeb

File tree

5 files changed

+33
-7
lines changed

5 files changed

+33
-7
lines changed

clang/lib/Lex/Pragma.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "llvm/ADT/StringRef.h"
4343
#include "llvm/Support/Compiler.h"
4444
#include "llvm/Support/ErrorHandling.h"
45+
#include "llvm/Support/Timer.h"
4546
#include <algorithm>
4647
#include <cassert>
4748
#include <cstddef>
@@ -1038,6 +1039,8 @@ struct PragmaDebugHandler : public PragmaHandler {
10381039
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
10391040
llvm_unreachable("This is an assertion!");
10401041
} else if (II->isStr("crash")) {
1042+
llvm::Timer T("crash", "pragma crash");
1043+
llvm::TimeRegion R(&T);
10411044
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
10421045
LLVM_BUILTIN_TRAP;
10431046
} else if (II->isStr("parser_crash")) {

clang/tools/driver/driver.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/Option/ArgList.h"
3131
#include "llvm/Option/OptTable.h"
3232
#include "llvm/Option/Option.h"
33+
#include "llvm/Support/BuryPointer.h"
3334
#include "llvm/Support/CommandLine.h"
3435
#include "llvm/Support/CrashRecoveryContext.h"
3536
#include "llvm/Support/ErrorHandling.h"
@@ -491,6 +492,7 @@ int main(int argc_, const char **argv_) {
491492

492493
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
493494
int Res = 1;
495+
bool IsCrash = false;
494496
if (C && !C->containsError()) {
495497
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
496498
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
@@ -517,11 +519,11 @@ int main(int argc_, const char **argv_) {
517519
// If result status is 70, then the driver command reported a fatal error.
518520
// On Windows, abort will return an exit code of 3. In these cases,
519521
// generate additional diagnostic information if possible.
520-
bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
522+
IsCrash = CommandRes < 0 || CommandRes == 70;
521523
#ifdef _WIN32
522-
DiagnoseCrash |= CommandRes == 3;
524+
IsCrash |= CommandRes == 3;
523525
#endif
524-
if (DiagnoseCrash) {
526+
if (IsCrash) {
525527
TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
526528
break;
527529
}
@@ -530,10 +532,16 @@ int main(int argc_, const char **argv_) {
530532

531533
Diags.getClient()->finish();
532534

533-
// If any timers were active but haven't been destroyed yet, print their
534-
// results now. This happens in -disable-free mode.
535-
llvm::TimerGroup::printAll(llvm::errs());
536-
llvm::TimerGroup::clearAll();
535+
if (!UseNewCC1Process && IsCrash) {
536+
// When crashing in -fintegrated-cc1 mode, bury the timer pointers, because
537+
// the internal linked list might point to already released stack frames.
538+
llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup());
539+
} else {
540+
// If any timers were active but haven't been destroyed yet, print their
541+
// results now. This happens in -disable-free mode.
542+
llvm::TimerGroup::printAll(llvm::errs());
543+
llvm::TimerGroup::clearAll();
544+
}
537545

538546
#ifdef _WIN32
539547
// Exit status should not be negative on Win32, unless abnormal termination.

llvm/include/llvm/Support/ManagedStatic.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ class ManagedStatic : public ManagedStaticBase {
102102
}
103103

104104
const C *operator->() const { return &**this; }
105+
106+
// Extract the instance, leaving the ManagedStatic uninitialized. The
107+
// user is then responsible for the lifetime of the returned instance.
108+
C *claim() {
109+
return static_cast<C *>(Ptr.exchange(nullptr));
110+
}
105111
};
106112

107113
/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.

llvm/include/llvm/Support/Timer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ class TimerGroup {
230230
/// used by the Statistic code to influence the construction and destruction
231231
/// order of the global timer lists.
232232
static void ConstructTimerLists();
233+
234+
/// This makes the default group unmanaged, and lets the user manage the
235+
/// group's lifetime.
236+
static std::unique_ptr<TimerGroup> aquireDefaultGroup();
237+
233238
private:
234239
friend class Timer;
235240
friend void PrintStatisticsJSON(raw_ostream &OS);

llvm/lib/Support/Timer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,7 @@ const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
441441
void TimerGroup::ConstructTimerLists() {
442442
(void)*NamedGroupedTimers;
443443
}
444+
445+
std::unique_ptr<TimerGroup> TimerGroup::aquireDefaultGroup() {
446+
return std::unique_ptr<TimerGroup>(DefaultTimerGroup.claim());
447+
}

0 commit comments

Comments
 (0)