Skip to content

Commit 23b762f

Browse files
committed
[LLVM][Windows] Elide PrettyStackTrace output for usage errors
On Windows, LLVM’s `reportFatalUsageError` may emit a stack trace and bug report prompt due to the `PrettyStackTrace` signal handler, initialized via `InitLLVM`. This occurs when `sys::RunInterruptHandlers()` is called from `reportFatalUsageError`. This behavior is misleading for usage errors. For example, one of Sony’s customers filed a bug after specifying an invalid LTO cache directory - a clear usage error - because the toolchain output included a stack trace and instructions to report a bug. This patch suppresses `PrettyStackTrace` output for usage errors by adding a flag to `sys::RunInterruptHandlers()` to indicate whether signal handlers should be executed. To test this, the existing Linux-specific LTO cache directory test has been replaced with a Windows-only test case that also verifies no crash-style diagnostics are emitted. LLVM Issue: #140953 Internal Tracker: TOOLCHAIN-17744
1 parent b4d2e50 commit 23b762f

File tree

11 files changed

+43
-24
lines changed

11 files changed

+43
-24
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(/*ExecuteSignalHandlers=*/true);
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(/*ExecuteSignalHandlers=*/true);
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: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
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 this test is limited 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 fatal usage error emitted when the cache dir can't be created.
11-
; RUN: not 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 that typical filesystems will reject.
9+
;; Use a response file to break 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 that a fatal usage error is emitted when the cache dir can't be created.
19+
; The --implicit-check-not arguments verify that no crash-style output is shown.
20+
; RUN: not lld-link @%t_rsp /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s \
21+
; RUN: --ignore-case --implicit-check-not=bug --implicit-check-not=crash
22+
23+
; CHECK: LLVM ERROR: can't create cache directory {{.*}}/bob/: invalid argument
1324

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

llvm/docs/ReleaseNotes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ Changes to LLVM infrastructure
8080
* Added the support for ``fmaximum`` and ``fminimum`` in ``atomicrmw`` instruction. The
8181
comparison is expected to match the behavior of ``llvm.maximum.*`` and
8282
``llvm.minimum.*`` respectively.
83+
* On Windows, fatal usage errors no longer produce crash-style diagnostics
84+
such as stack traces or bug report prompts.
8385

8486
Changes to building LLVM
8587
------------------------

llvm/include/llvm/Support/Error.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ template <class T> class [[nodiscard]] Expected {
744744
/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
745745
/// instead.
746746
[[noreturn]] LLVM_ABI void report_fatal_error(Error Err,
747-
bool gen_crash_diag = true);
747+
bool GenCrashDiag = true);
748748

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

llvm/include/llvm/Support/Signals.h

Lines changed: 1 addition & 1 deletion
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 ExecuteSignalHandlers);
3030

3131
/// This function registers signal handlers to ensure that if a signal gets
3232
/// delivered that the named file is removed.

llvm/lib/Support/Error.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
177177
void reportFatalInternalError(Error Err) {
178178
report_fatal_error(std::move(Err), /*GenCrashDiag=*/true);
179179
}
180+
180181
void reportFatalUsageError(Error Err) {
181182
report_fatal_error(std::move(Err), /*GenCrashDiag=*/false);
182183
}

llvm/lib/Support/ErrorHandling.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
118118
// If we reached here, we are failing ungracefully. Run the interrupt handlers
119119
// to make sure any special cleanups get done, in particular that we remove
120120
// files registered with RemoveFileOnSignal.
121-
sys::RunInterruptHandlers();
121+
sys::RunInterruptHandlers(GenCrashDiag);
122122

123123
if (GenCrashDiag)
124124
abort();
@@ -127,22 +127,27 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
127127
}
128128

129129
void llvm::reportFatalInternalError(const char *reason) {
130-
report_fatal_error(reason, /*GenCrashDiag=*/true);
130+
report_fatal_error(reason, /*gen_crash_diag=*/true);
131131
}
132+
132133
void llvm::reportFatalInternalError(StringRef reason) {
133-
report_fatal_error(reason, /*GenCrashDiag=*/true);
134+
report_fatal_error(reason, /*gen_crash_diag=*/true);
134135
}
136+
135137
void llvm::reportFatalInternalError(const Twine &reason) {
136-
report_fatal_error(reason, /*GenCrashDiag=*/true);
138+
report_fatal_error(reason, /*gen_crash_diag=*/true);
137139
}
140+
138141
void llvm::reportFatalUsageError(const char *reason) {
139-
report_fatal_error(reason, /*GenCrashDiag=*/false);
142+
report_fatal_error(reason, /*gen_crash_diag=*/false);
140143
}
144+
141145
void llvm::reportFatalUsageError(StringRef reason) {
142-
report_fatal_error(reason, /*GenCrashDiag=*/false);
146+
report_fatal_error(reason, /*gen_crash_diag=*/false);
143147
}
148+
144149
void llvm::reportFatalUsageError(const Twine &reason) {
145-
report_fatal_error(reason, /*GenCrashDiag=*/false);
150+
report_fatal_error(reason, /*gen_crash_diag=*/false);
146151
}
147152

148153
void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,

llvm/lib/Support/Windows/Signals.inc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -634,13 +634,13 @@ static void Cleanup(bool ExecuteSignalHandlers) {
634634
LeaveCriticalSection(&CriticalSection);
635635
}
636636

637-
void llvm::sys::RunInterruptHandlers() {
637+
void llvm::sys::RunInterruptHandlers(bool ExecuteSignalHandlers) {
638638
// The interrupt handler may be called from an interrupt, but it may also be
639639
// called manually (such as the case of report_fatal_error with no registered
640640
// error handler). We must ensure that the critical section is properly
641641
// initialized.
642642
InitializeThreading();
643-
Cleanup(true);
643+
Cleanup(ExecuteSignalHandlers);
644644
}
645645

646646
/// Find the Windows Registry Key for a given location.
@@ -847,7 +847,7 @@ void sys::CleanupOnSignal(uintptr_t Context) {
847847
}
848848

849849
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
850-
Cleanup(true);
850+
Cleanup(/*ExecuteSignalHandlers=*/true);
851851

852852
// Write out the exception code.
853853
if (ep && ep->ExceptionRecord)
@@ -887,7 +887,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
887887
// This function is only ever called when a CTRL-C or similar control signal
888888
// is fired. Killing a process in this way is normal, so don't trigger the
889889
// signal handlers.
890-
Cleanup(false);
890+
Cleanup(/*ExecuteSignalHandlers=*/false);
891891

892892
// If an interrupt function has been set, go and run one it; otherwise,
893893
// the process dies.

llvm/lib/TableGen/Error.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ static void PrintMessage(ArrayRef<SMLoc> Loc, SourceMgr::DiagKind Kind,
4343
// Run file cleanup handlers and then exit fatally (with non-zero exit code).
4444
[[noreturn]] inline static void fatal_exit() {
4545
// The following call runs the file cleanup handlers.
46-
sys::RunInterruptHandlers();
46+
sys::RunInterruptHandlers(/*ExecuteSignalHandlers=*/true);
4747
std::exit(1);
4848
}
4949

mlir/tools/mlir-tblgen/OpFormatGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3836,7 +3836,7 @@ void mlir::tblgen::generateOpFormat(const Operator &constOp, OpClass &opClass,
38363836
// Exit the process if format errors are treated as fatal.
38373837
if (formatErrorIsFatal) {
38383838
// Invoke the interrupt handlers to run the file cleanup handlers.
3839-
llvm::sys::RunInterruptHandlers();
3839+
llvm::sys::RunInterruptHandlers(/*ExecuteSignalHandlers=*/true);
38403840
std::exit(1);
38413841
}
38423842
return;

0 commit comments

Comments
 (0)