Skip to content

Commit 0d9218e

Browse files
committed
[Windows][LLVM] Elide PrettyStackTrace output for usage errors
LLVM’s `reportFatalUsageError`, introduced recently, may emit a stack trace and bug report prompt due to the `PrettyStackTrace` signal handler (initialized via `InitLLVM`). On Windows, this occurs when `sys::RunInterruptHandlers()` is invoked from `reportFatalUsageError`. This behavior is misleading for usage errors. For example, one of Sony’s customers reported a bug after specifying an invalid LTO cache directory - a clear usage error - because the toolchain output included a stack trace and instructions to file a bug report. This patch suppresses `PrettyStackTrace` output for usage errors by passing a flag to the signal handlers, indicating when the error should not trigger crash-style diagnostics. To test this, LTO cache directory errors have been updated to use `reportFatalUsageError` and the existing Linux-specific test has been replaced with a Windows-only test case that additionally verifies no crash-style diagnostics are emitted. LLVM Issue: #140953 Internal Tracker: TOOLCHAIN-17744
1 parent 3a86e0b commit 0d9218e

File tree

17 files changed

+69
-47
lines changed

17 files changed

+69
-47
lines changed

clang/tools/clang-repl/ClangRepl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static void LLVMErrorHandler(void *UserData, const char *Message,
5555

5656
// Run the interrupt handlers to make sure any special cleanups get done, in
5757
// particular that we remove files registered with RemoveFileOnSignal.
58-
llvm::sys::RunInterruptHandlers();
58+
llvm::sys::RunInterruptHandlers(/*IsUsageError=*/false);
5959

6060
// We cannot recover from llvm errors. When reporting a fatal error, exit
6161
// with status 70 to generate crash diagnostics. For BSD systems this is

clang/tools/driver/cc1_main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static void LLVMErrorHandler(void *UserData, const char *Message,
7272

7373
// Run the interrupt handlers to make sure any special cleanups get done, in
7474
// particular that we remove files registered with RemoveFileOnSignal.
75-
llvm::sys::RunInterruptHandlers();
75+
llvm::sys::RunInterruptHandlers(/*IsUsageError=*/false);
7676

7777
// We cannot recover from llvm errors. When reporting a fatal error, exit
7878
// with status 70 to generate crash diagnostics. For BSD systems this is

lld/test/COFF/lto-cache-errors.ll

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
1-
; REQUIRES: x86, non-root-user
2-
;; Not supported on windows since we use permissions to deny the creation
3-
; UNSUPPORTED: system-windows
1+
;; The output is OS specific, so make this test specific to Windows.
2+
; REQUIRES: x86, system-windows
43

54
; RUN: opt -module-hash -module-summary %s -o %t.o
65
; RUN: opt -module-hash -module-summary %p/Inputs/lto-cache.ll -o %t2.o
76
; RUN: rm -Rf %t.cache && mkdir %t.cache
8-
; RUN: chmod 444 %t.cache
97

10-
;; Check emit warnings when we can't create the cache dir
11-
; RUN: not --crash lld-link /lldltocache:%t.cache/nonexistant/ /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s
12-
; CHECK: LLVM ERROR: can't create cache directory {{.*}}/nonexistant/: Permission denied
8+
; Use a 261-character path component which filesystems will fail to create. Use
9+
; a response file to allow breaking up the long path into 50-character chunks.
10+
; RUN: echo -n "/lldltocache:%t.cache/" > %t_rsp
11+
; RUN: echo -n "01234567890123456789012345678901234567890123456789" >> %t_rsp
12+
; RUN: echo -n "01234567890123456789012345678901234567890123456789" >> %t_rsp
13+
; RUN: echo -n "01234567890123456789012345678901234567890123456789" >> %t_rsp
14+
; RUN: echo -n "01234567890123456789012345678901234567890123456789" >> %t_rsp
15+
; RUN: echo -n "01234567890123456789012345678901234567890123456789" >> %t_rsp
16+
; RUN: echo -n "01234567890/bob/" >> %t_rsp
17+
18+
;; Check fatal usage error emitted when the cache dir can't be created.
19+
; RUN: not lld-link @%t_rsp /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s \
20+
; RUN: --ignore-case --implicit-check-not=bug --implicit-check-not=crash
21+
; CHECK: LLVM ERROR: can't create cache directory {{.*}}/bob/: {{.*(invalid argument)|(too long)}}
1322

1423
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
1524
target triple = "x86_64-pc-windows-msvc"

llvm/include/llvm/Passes/StandardInstrumentations.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ class PrintCrashIRInstrumentation {
589589
// The crash reporter that will report on a crash.
590590
static PrintCrashIRInstrumentation *CrashReporter;
591591
// Crash handler registered when print-on-crash is specified.
592-
static void SignalHandler(void *);
592+
static void SignalHandler(void *, bool);
593593
};
594594

595595
/// This class provides an interface to register all the standard pass

llvm/include/llvm/Support/Error.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,8 @@ template <class T> class [[nodiscard]] Expected {
742742
/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
743743
/// instead.
744744
[[noreturn]] LLVM_ABI void report_fatal_error(Error Err,
745-
bool gen_crash_diag = true);
745+
bool GenCrashDiag = true,
746+
bool IsUsageError = false);
746747

747748
/// Report a fatal error that indicates a bug in LLVM.
748749
/// See ErrorHandling.h for details.

llvm/include/llvm/Support/ErrorHandling.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,14 @@ struct ScopedFatalErrorHandler {
6161
/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
6262
/// instead.
6363
[[noreturn]] LLVM_ABI void report_fatal_error(const char *reason,
64-
bool gen_crash_diag = true);
64+
bool gen_crash_diag = true,
65+
bool is_usage_error = false);
6566
[[noreturn]] LLVM_ABI void report_fatal_error(StringRef reason,
66-
bool gen_crash_diag = true);
67+
bool gen_crash_diag = true,
68+
bool is_usage_error = false);
6769
[[noreturn]] LLVM_ABI void report_fatal_error(const Twine &reason,
68-
bool gen_crash_diag = true);
70+
bool gen_crash_diag = true,
71+
bool is_usage_error = false);
6972

7073
/// Report a fatal error that likely indicates a bug in LLVM. It serves a
7174
/// similar purpose as an assertion, but is always enabled, regardless of the

llvm/include/llvm/Support/Signals.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace sys {
2626

2727
/// This function runs all the registered interrupt handlers, including the
2828
/// removal of files registered by RemoveFileOnSignal.
29-
LLVM_ABI void RunInterruptHandlers();
29+
LLVM_ABI void RunInterruptHandlers(bool IsUsageError);
3030

3131
/// This function registers signal handlers to ensure that if a signal gets
3232
/// delivered that the named file is removed.
@@ -58,9 +58,9 @@ LLVM_ABI void DisableSystemDialogsOnCrash();
5858
LLVM_ABI void PrintStackTrace(raw_ostream &OS, int Depth = 0);
5959

6060
// Run all registered signal handlers.
61-
LLVM_ABI void RunSignalHandlers();
61+
LLVM_ABI void RunSignalHandlers(bool IsUsageError);
6262

63-
using SignalHandlerCallback = void (*)(void *);
63+
using SignalHandlerCallback = void (*)(void *, bool);
6464

6565
/// Add a function to be called when an abort/kill signal is delivered to the
6666
/// process. The handler can have a cookie passed to it to identify what

llvm/lib/LTO/LTOBackend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ static void codegen(const Config &Conf, TargetMachine *TM,
435435
Expected<std::unique_ptr<CachedFileStream>> StreamOrErr =
436436
AddStream(Task, Mod.getModuleIdentifier());
437437
if (Error Err = StreamOrErr.takeError())
438-
report_fatal_error(std::move(Err));
438+
reportFatalUsageError(std::move(Err));
439439
std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;
440440
TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName;
441441

llvm/lib/Passes/StandardInstrumentations.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2468,7 +2468,7 @@ void PrintCrashIRInstrumentation::reportCrashIR() {
24682468
}
24692469
}
24702470

2471-
void PrintCrashIRInstrumentation::SignalHandler(void *) {
2471+
void PrintCrashIRInstrumentation::SignalHandler(void *, bool) {
24722472
// Called by signal handlers so do not lock here
24732473
// Is the PrintCrashIRInstrumentation still alive?
24742474
if (!CrashReporter)

llvm/lib/Support/Debug.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ void llvm::initDebugOptions() {
148148
}
149149

150150
// Signal handlers - dump debug output on termination.
151-
static void debug_user_sig_handler(void *Cookie) {
151+
static void debug_user_sig_handler(void *Cookie, bool /*IsUsageError*/) {
152152
// This is a bit sneaky. Since this is under #ifndef NDEBUG, we
153153
// know that debug mode is enabled and dbgs() really is a
154154
// circular_raw_ostream. If NDEBUG is defined, then dbgs() ==

0 commit comments

Comments
 (0)