[clang] [clang-tools-extra] [llvm] [LLVM][CLANG] Update signal-handling behavior to comply with POSIX (PR #169340)
Xing Xue via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 9 12:30:56 PST 2026
https://github.com/xingxue-ibm updated https://github.com/llvm/llvm-project/pull/169340
>From b9937432c640f3b9755bdc8927bddf4e10b7a8b9 Mon Sep 17 00:00:00 2001
From: Xing Xue <xingxue at outlook.com>
Date: Fri, 21 Nov 2025 15:29:56 -0500
Subject: [PATCH 1/4] Don't install signal handler if the disposition of a
signal is SIG_IGN, resignal after the signal handler handles a signal so the
exit code of the compiler contains the signal number.
---
.../unittests/ThreadCrashReporterTests.cpp | 12 +++++++++
clang/lib/Driver/Driver.cpp | 7 +++++
clang/tools/driver/driver.cpp | 18 ++++++++++++-
llvm/lib/Support/CrashRecoveryContext.cpp | 6 ++++-
llvm/lib/Support/Unix/Signals.inc | 27 ++++++++++++-------
5 files changed, 58 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp b/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp
index 0eb8d472c6702..1c86fcbea4a4b 100644
--- a/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp
@@ -13,6 +13,17 @@
#include <csignal>
#include <string>
+// According to the POSIX specification, if the inherited disposition of a
+// signal is the default action, the behavior of utilitys must be as if the
+// default action had been taken. When the required default action is to
+// terminate the process, such as for SIGUSR1, the utility may catch the
+// signal, perform additional processing, restore the default disposition,
+// and then re-signal itself. This causes the process to terminate as
+// required. Because of this behavior, the crash-reporter test here is not
+// suitable for Unix platforms.
+
+#ifndef LLVM_ON_UNIX
+
namespace clang {
namespace clangd {
@@ -76,3 +87,4 @@ TEST(ThreadCrashReporterTest, All) {
} // namespace
} // namespace clangd
} // namespace clang
+#endif // !LLVM_ON_UNIX
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index eb3f9cbea2845..9ca0bb8cac420 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2300,7 +2300,14 @@ int Driver::ExecuteCompilation(
if (!FailingCommand->getCreator().hasGoodDiagnostics() || CommandRes != 1) {
// FIXME: See FIXME above regarding result code interpretation.
+#if LLVM_ON_UNIX
+ // On Unix, signals are represented by return codes of 128 plus the
+ // signal number. Return code 255 is excluded because some tools,
+ // such as llvm-ifs, exit with code 255 (-1) on failure.
+ if (CommandRes > 128 && CommandRes != 255)
+#else
if (CommandRes < 0)
+#endif
Diag(clang::diag::err_drv_command_signalled)
<< FailingTool.getShortName();
else
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 490136961ebc6..a586494cdc8a9 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -55,6 +55,9 @@
#include <optional>
#include <set>
#include <system_error>
+#if LLVM_ON_UNIX
+#include <signal.h>
+#endif
using namespace clang;
using namespace clang::driver;
@@ -407,6 +410,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
// Pretend the first command failed if ReproStatus is Always.
const Command *FailingCommand = nullptr;
+ int CommandRes = 0;
if (!C->getJobs().empty())
FailingCommand = &*C->getJobs().begin();
if (C && !C->containsError()) {
@@ -414,7 +418,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
for (const auto &P : FailingCommands) {
- int CommandRes = P.first;
+ CommandRes = P.first;
FailingCommand = P.second;
if (!Res)
Res = CommandRes;
@@ -471,6 +475,18 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
Res = 1;
#endif
+#if LLVM_ON_UNIX
+ // On Unix, signals are represented by return codes of 128 plus the signal
+ // number. If the return code indicates it was from a signal handler, raise
+ // the signal so that the exit code includes the signal number, as required
+ // by POSIX. Return code 255 is excluded because some tools, such as
+ // llvm-ifs, exit with code 255 (-1) on failure.
+ if (CommandRes > 128 && CommandRes != 255) {
+ llvm::sys::unregisterHandlers();
+ raise(CommandRes - 128);
+ }
+#endif
+
// If we have multiple failing commands, we return the result of the first
// failing command.
return Res;
diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp
index 1ba0c2383daec..c6bfa4d0245da 100644
--- a/llvm/lib/Support/CrashRecoveryContext.cpp
+++ b/llvm/lib/Support/CrashRecoveryContext.cpp
@@ -398,7 +398,11 @@ static void installExceptionOrSignalHandlers() {
sigemptyset(&Handler.sa_mask);
for (unsigned i = 0; i != NumSignals; ++i) {
- sigaction(Signals[i], &Handler, &PrevActions[i]);
+ struct sigaction act;
+ sigaction(Signals[i], NULL, &act);
+ // Don't install signal handler if the disposition of a signal is SIG_IGN.
+ if (act.sa_handler != SIG_IGN)
+ sigaction(Signals[i], &Handler, &PrevActions[i]);
}
}
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 56ad4fc504153..35ac441d73be8 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -327,8 +327,12 @@ static void RegisterHandlers() { // Not signal-safe.
}
sigemptyset(&NewHandler.sa_mask);
- // Install the new handler, save the old one in RegisteredSignalInfo.
- sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
+ // Install the new handler if the signal disposition isn't SIG_IGN,
+ // save the old one in RegisteredSignalInfo.
+ struct sigaction act;
+ sigaction(Signal, NULL, &act);
+ if (act.sa_handler != SIG_IGN)
+ sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
RegisteredSignalInfo[Index].SigNo = Signal;
++NumRegisteredSignals;
};
@@ -411,14 +415,12 @@ static void SignalHandler(int Sig, siginfo_t *Info, void *) {
// Otherwise if it is a fault (like SEGV) run any handler.
llvm::sys::RunSignalHandlers();
-#ifdef __s390__
- // On S/390, certain signals are delivered with PSW Address pointing to
- // *after* the faulting instruction. Simply returning from the signal
- // handler would continue execution after that point, instead of
- // re-raising the signal. Raise the signal manually in those cases.
- if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
- raise(Sig);
-#endif
+ // Resignal if it is a kill signal so that the exit code contains the
+ // terminating signal number.
+ if (llvm::is_contained(KillSigs, Sig)) {
+ raise(Sig); // Execute the default handler.
+ return;
+ }
#if defined(__linux__)
// Re-raising a signal via `raise` loses the original siginfo. Recent
@@ -441,6 +443,11 @@ static void InfoSignalHandler(int Sig) {
SaveAndRestore SaveErrnoDuringASignalHandler(errno);
if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
CurrentInfoFunction();
+
+ if (Sig == SIGUSR1) {
+ sys::unregisterHandlers();
+ raise(Sig);
+ }
}
void sys::RunInterruptHandlers() {
>From 1a4bdebddf0b19d8dd9467d7afab4faf02086e9c Mon Sep 17 00:00:00 2001
From: Xing Xue <xingxue at outlook.com>
Date: Fri, 9 Jan 2026 12:41:58 -0500
Subject: [PATCH 2/4] Address comments to only change the Clang's behavior
according to the POSIX specification for utilities. Update test cases to
reflect they failed because of signal/crash.
---
.../unittests/ThreadCrashReporterTests.cpp | 12 ------------
clang/test/Driver/crash-diagnostics-dir-3.c | 2 +-
clang/test/Driver/crash-diagnostics-dir.c | 2 +-
clang/test/Driver/crash-ir-repro.cpp | 2 +-
clang/test/Driver/crash-report-clang-cl.cpp | 2 +-
clang/test/Driver/crash-report-header.h | 2 +-
clang/test/Driver/crash-report-spaces.c | 2 +-
clang/test/Driver/crash-report-with-asserts.c | 4 ++--
clang/test/Driver/crash-report.cpp | 4 ++--
clang/test/Driver/emit-reproducer.c | 14 +++++++-------
clang/test/Driver/output-file-cleanup.c | 2 +-
llvm/cmake/modules/AddLLVM.cmake | 7 +++++++
.../cmake/modules/llvm-driver-template.cpp.in | 2 +-
llvm/include/llvm/Support/InitLLVM.h | 8 +++++---
llvm/include/llvm/Support/Signals.h | 2 +-
llvm/lib/Support/InitLLVM.cpp | 5 +++--
llvm/lib/Support/Unix/Signals.inc | 19 +++++++++++++++----
17 files changed, 50 insertions(+), 41 deletions(-)
diff --git a/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp b/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp
index 1c86fcbea4a4b..0eb8d472c6702 100644
--- a/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ThreadCrashReporterTests.cpp
@@ -13,17 +13,6 @@
#include <csignal>
#include <string>
-// According to the POSIX specification, if the inherited disposition of a
-// signal is the default action, the behavior of utilitys must be as if the
-// default action had been taken. When the required default action is to
-// terminate the process, such as for SIGUSR1, the utility may catch the
-// signal, perform additional processing, restore the default disposition,
-// and then re-signal itself. This causes the process to terminate as
-// required. Because of this behavior, the crash-reporter test here is not
-// suitable for Unix platforms.
-
-#ifndef LLVM_ON_UNIX
-
namespace clang {
namespace clangd {
@@ -87,4 +76,3 @@ TEST(ThreadCrashReporterTest, All) {
} // namespace
} // namespace clangd
} // namespace clang
-#endif // !LLVM_ON_UNIX
diff --git a/clang/test/Driver/crash-diagnostics-dir-3.c b/clang/test/Driver/crash-diagnostics-dir-3.c
index a91bc48d7e462..8d22df85abd2f 100644
--- a/clang/test/Driver/crash-diagnostics-dir-3.c
+++ b/clang/test/Driver/crash-diagnostics-dir-3.c
@@ -1,6 +1,6 @@
// RUN: export LSAN_OPTIONS=detect_leaks=0
// RUN: rm -rf %t
-// RUN: not env CLANG_CRASH_DIAGNOSTICS_DIR=%t %clang -c %s -o - 2>&1 | FileCheck %s
+// RUN: not --crash env CLANG_CRASH_DIAGNOSTICS_DIR=%t %clang -c %s -o - 2>&1 | FileCheck %s
#pragma clang __debug parser_crash
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
// CHECK: diagnostic msg: {{.*}}{{/|\\}}crash-diagnostics-dir-3.c.tmp{{(/|\\).*}}.c
diff --git a/clang/test/Driver/crash-diagnostics-dir.c b/clang/test/Driver/crash-diagnostics-dir.c
index 16382eff1cde7..56c77beae7234 100644
--- a/clang/test/Driver/crash-diagnostics-dir.c
+++ b/clang/test/Driver/crash-diagnostics-dir.c
@@ -1,6 +1,6 @@
// RUN: export LSAN_OPTIONS=detect_leaks=0
// RUN: rm -rf %t
-// RUN: not %clang -fcrash-diagnostics-dir=%t -c %s -o - 2>&1 | FileCheck %s
+// RUN: not --crash %clang -fcrash-diagnostics-dir=%t -c %s -o - 2>&1 | FileCheck %s
#pragma clang __debug parser_crash
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
// CHECK: diagnostic msg: {{.*}}{{/|\\}}crash-diagnostics-dir.c.tmp{{(/|\\).*}}.c
diff --git a/clang/test/Driver/crash-ir-repro.cpp b/clang/test/Driver/crash-ir-repro.cpp
index fd97e6f0cce11..16faabe84d29e 100644
--- a/clang/test/Driver/crash-ir-repro.cpp
+++ b/clang/test/Driver/crash-ir-repro.cpp
@@ -1,5 +1,5 @@
// RUN: %clang -S -emit-llvm -o %t.ll %s
-// RUN: not %clang -S -DCRASH %s -o %t.ll 2>&1 | FileCheck %s
+// RUN: not --crash %clang -S -DCRASH %s -o %t.ll 2>&1 | FileCheck %s
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
// CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.cpp
diff --git a/clang/test/Driver/crash-report-clang-cl.cpp b/clang/test/Driver/crash-report-clang-cl.cpp
index 963c3b6d0ab03..3efeb8088db52 100644
--- a/clang/test/Driver/crash-report-clang-cl.cpp
+++ b/clang/test/Driver/crash-report-clang-cl.cpp
@@ -2,7 +2,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: not %clang_cl -fsyntax-only /Brepro /source-charset:utf-8 \
+// RUN: not --crash %clang_cl -fsyntax-only /Brepro /source-charset:utf-8 \
// RUN: -fcrash-diagnostics-dir=%t -- %s 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-clang-cl-*.cpp | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-clang-cl-*.sh | FileCheck --check-prefix=CHECKSH %s
diff --git a/clang/test/Driver/crash-report-header.h b/clang/test/Driver/crash-report-header.h
index 04865a0cc300f..31c71ff625c05 100644
--- a/clang/test/Driver/crash-report-header.h
+++ b/clang/test/Driver/crash-report-header.h
@@ -1,7 +1,7 @@
// RUN: export LSAN_OPTIONS=detect_leaks=0
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 not %clang -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 not --crash %clang -fsyntax-only %s 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-header-*.h | FileCheck --check-prefix=CHECKSRC "%s"
// RUN: cat %t/crash-report-header-*.sh | FileCheck --check-prefix=CHECKSH "%s"
// REQUIRES: crash-recovery
diff --git a/clang/test/Driver/crash-report-spaces.c b/clang/test/Driver/crash-report-spaces.c
index b4d8ac1f57e83..c01c8df0552de 100644
--- a/clang/test/Driver/crash-report-spaces.c
+++ b/clang/test/Driver/crash-report-spaces.c
@@ -2,7 +2,7 @@
// RUN: rm -rf "%t"
// RUN: mkdir "%t"
// RUN: cp "%s" "%t/crash report spaces.c"
-// RUN: env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 not %clang -fsyntax-only "%t/crash report spaces.c" 2>&1 | FileCheck "%s"
+// RUN: env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 not --crash %clang -fsyntax-only "%t/crash report spaces.c" 2>&1 | FileCheck "%s"
// RUN: cat "%t/crash report spaces"-*.c | FileCheck --check-prefix=CHECKSRC "%s"
// RUN: cat "%t/crash report spaces"-*.sh | FileCheck --check-prefix=CHECKSH "%s"
// REQUIRES: crash-recovery
diff --git a/clang/test/Driver/crash-report-with-asserts.c b/clang/test/Driver/crash-report-with-asserts.c
index 686c49f339fb7..0b619d9ec2f46 100644
--- a/clang/test/Driver/crash-report-with-asserts.c
+++ b/clang/test/Driver/crash-report-with-asserts.c
@@ -12,13 +12,13 @@
// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
-// RUN: not %clang %s @%t.rsp -DASSERT 2>&1 | FileCheck %s
+// RUN: not --crash %clang %s @%t.rsp -DASSERT 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-*.c | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
-// RUN: not %clang %s @%t.rsp -DUNREACHABLE 2>&1 | FileCheck %s
+// RUN: not --crash %clang %s @%t.rsp -DUNREACHABLE 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-with-asserts-*.c | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-with-asserts-*.sh | FileCheck --check-prefix=CHECKSH %s
diff --git a/clang/test/Driver/crash-report.cpp b/clang/test/Driver/crash-report.cpp
index 59eee65af57ee..4b5adfc02bff4 100644
--- a/clang/test/Driver/crash-report.cpp
+++ b/clang/test/Driver/crash-report.cpp
@@ -12,13 +12,13 @@
// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
-// RUN: not %clang %s @%t.rsp -DPARSER 2>&1 | FileCheck %s
+// RUN: not --crash %clang %s @%t.rsp -DPARSER 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-*.cpp | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
-// RUN: not %clang %s @%t.rsp -DCRASH 2>&1 | FileCheck %s
+// RUN: not --crash %clang %s @%t.rsp -DCRASH 2>&1 | FileCheck %s
// RUN: cat %t/crash-report-*.cpp | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
diff --git a/clang/test/Driver/emit-reproducer.c b/clang/test/Driver/emit-reproducer.c
index 18e1b4e41b91d..28c585193a7d0 100644
--- a/clang/test/Driver/emit-reproducer.c
+++ b/clang/test/Driver/emit-reproducer.c
@@ -3,13 +3,13 @@
// RUN: echo "%s -fcrash-diagnostics-dir=%t -fsyntax-only" | sed -e 's/\\/\\\\/g' > %t.rsp
-// RUN: not %clang -DFATAL @%t.rsp -gen-reproducer=off 2>&1 | FileCheck %s --check-prefix=NOT
-// RUN: not %clang -DFATAL @%t.rsp -fno-crash-diagnostics 2>&1 | FileCheck %s --check-prefix=NOT
-// RUN: not %clang -DFATAL @%t.rsp 2>&1 | FileCheck %s
-// RUN: not %clang -DFATAL @%t.rsp -gen-reproducer=crash 2>&1 | FileCheck %s
-// RUN: not %clang -DFATAL @%t.rsp -gen-reproducer=error 2>&1 | FileCheck %s
-// RUN: not %clang -DFATAL @%t.rsp -gen-reproducer=always 2>&1 | FileCheck %s
-// RUN: not %clang -DFATAL @%t.rsp -gen-reproducer 2>&1 | FileCheck %s
+// RUN: not --crash %clang -DFATAL @%t.rsp -gen-reproducer=off 2>&1 | FileCheck %s --check-prefix=NOT
+// RUN: not --crash %clang -DFATAL @%t.rsp -fno-crash-diagnostics 2>&1 | FileCheck %s --check-prefix=NOT
+// RUN: not --crash %clang -DFATAL @%t.rsp 2>&1 | FileCheck %s
+// RUN: not --crash %clang -DFATAL @%t.rsp -gen-reproducer=crash 2>&1 | FileCheck %s
+// RUN: not --crash %clang -DFATAL @%t.rsp -gen-reproducer=error 2>&1 | FileCheck %s
+// RUN: not --crash %clang -DFATAL @%t.rsp -gen-reproducer=always 2>&1 | FileCheck %s
+// RUN: not --crash %clang -DFATAL @%t.rsp -gen-reproducer 2>&1 | FileCheck %s
// RUN: not %clang -DERROR @%t.rsp -gen-reproducer=off 2>&1 | FileCheck %s --check-prefix=NOT
// RUN: not %clang -DERROR @%t.rsp -fno-crash-diagnostics 2>&1 | FileCheck %s --check-prefix=NOT
diff --git a/clang/test/Driver/output-file-cleanup.c b/clang/test/Driver/output-file-cleanup.c
index 3628df8192652..b5f548dc0b01a 100644
--- a/clang/test/Driver/output-file-cleanup.c
+++ b/clang/test/Driver/output-file-cleanup.c
@@ -2,7 +2,7 @@
// RUN: rm -f "%t.d" "%t1.s" "%t2.s" "%t3.s" "%t4.s" "%t5.s"
//
// RUN: touch %t.s
-// RUN: not %clang -S -DCRASH -o %t.s -MMD -MF %t.d %s
+// RUN: not --crash %clang -S -DCRASH -o %t.s -MMD -MF %t.d %s
// RUN: test ! -f %t.s
// RUN: test ! -f %t.d
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index d6acb4f984be9..921d90a455078 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -989,6 +989,13 @@ macro(generate_llvm_objects name)
if (ARG_GENERATE_DRIVER)
string(REPLACE "-" "_" TOOL_NAME ${name})
+
+ set(INITLLVM_ARGS "")
+
+ if(${name} STREQUAL "clang")
+ set(INITLLVM_ARGS ", /*InstallPipeSignalExitHandler=*/true, /*IsClangDriver=*/true")
+ endif()
+
foreach(path ${CMAKE_MODULE_PATH})
if(EXISTS ${path}/llvm-driver-template.cpp.in)
configure_file(
diff --git a/llvm/cmake/modules/llvm-driver-template.cpp.in b/llvm/cmake/modules/llvm-driver-template.cpp.in
index 1470ef1f06164..d4c385c8cf412 100644
--- a/llvm/cmake/modules/llvm-driver-template.cpp.in
+++ b/llvm/cmake/modules/llvm-driver-template.cpp.in
@@ -13,6 +13,6 @@
int @TOOL_NAME at _main(int argc, char **, const llvm::ToolContext &);
int main(int argc, char **argv) {
- llvm::InitLLVM X(argc, argv);
+ llvm::InitLLVM X(argc, argv at INITLLVM_ARGS@);
return @TOOL_NAME at _main(argc, argv, {argv[0], nullptr, false});
}
diff --git a/llvm/include/llvm/Support/InitLLVM.h b/llvm/include/llvm/Support/InitLLVM.h
index 748f5d8aa6aea..1473026e2974a 100644
--- a/llvm/include/llvm/Support/InitLLVM.h
+++ b/llvm/include/llvm/Support/InitLLVM.h
@@ -36,10 +36,12 @@ namespace llvm {
class InitLLVM {
public:
LLVM_ABI InitLLVM(int &Argc, const char **&Argv,
- bool InstallPipeSignalExitHandler = true);
- InitLLVM(int &Argc, char **&Argv, bool InstallPipeSignalExitHandler = true)
+ bool InstallPipeSignalExitHandler = true,
+ bool IsClandDriver = false);
+ InitLLVM(int &Argc, char **&Argv, bool InstallPipeSignalExitHandler = true,
+ bool IsClangDriver = false)
: InitLLVM(Argc, const_cast<const char **&>(Argv),
- InstallPipeSignalExitHandler) {}
+ InstallPipeSignalExitHandler, IsClangDriver) {}
LLVM_ABI ~InitLLVM();
diff --git a/llvm/include/llvm/Support/Signals.h b/llvm/include/llvm/Support/Signals.h
index 21b425fffef53..22612a55b3a37 100644
--- a/llvm/include/llvm/Support/Signals.h
+++ b/llvm/include/llvm/Support/Signals.h
@@ -100,7 +100,7 @@ using SignalHandlerCallback = void (*)(void *);
/// Add a function to be called when an abort/kill signal is delivered to the
/// process. The handler can have a cookie passed to it to identify what
/// instance of the handler it is.
-LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie);
+LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie, bool IsClangDriver = false);
/// This function registers a function to be called when the user "interrupts"
/// the program (typically by pressing ctrl-c). When the user interrupts the
diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index b90f4e0714458..248250cc5ddcb 100644
--- a/llvm/lib/Support/InitLLVM.cpp
+++ b/llvm/lib/Support/InitLLVM.cpp
@@ -73,7 +73,8 @@ using namespace llvm;
using namespace llvm::sys;
InitLLVM::InitLLVM(int &Argc, const char **&Argv,
- bool InstallPipeSignalExitHandler) {
+ bool InstallPipeSignalExitHandler,
+ bool IsClangDriver) {
#ifndef NDEBUG
static std::atomic<bool> Initialized{false};
assert(!Initialized && "InitLLVM was already initialized!");
@@ -81,7 +82,7 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
#endif
// Bring stdin/stdout/stderr into a known state.
- sys::AddSignalHandler(CleanupStdHandles, nullptr);
+ sys::AddSignalHandler(CleanupStdHandles, nullptr, IsClangDriver);
if (InstallPipeSignalExitHandler)
// The pipe signal handler must be installed before any other handlers are
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 35ac441d73be8..1d1cc9c915a72 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -86,6 +86,7 @@ using namespace llvm;
static void SignalHandler(int Sig, siginfo_t *Info, void *);
static void InfoSignalHandler(int Sig); // defined below.
+static void InfoSignalHandlerTerminate(int Sig); // defined below.
using SignalHandlerFunctionType = void (*)();
/// The function to call if ctrl-c is pressed.
@@ -292,7 +293,7 @@ static void CreateSigAltStack() {
static void CreateSigAltStack() {}
#endif
-static void RegisterHandlers() { // Not signal-safe.
+static void RegisterHandlers(bool IsClangDriver = false) { // Not signal-safe.
// The mutex prevents other threads from registering handlers while we're
// doing it. We also have to protect the handlers and their count because
// a signal handler could fire while we're registering handlers.
@@ -321,7 +322,12 @@ static void RegisterHandlers() { // Not signal-safe.
NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK | SA_SIGINFO;
break;
case SignalKind::IsInfo:
- NewHandler.sa_handler = InfoSignalHandler;
+ if (IsClangDriver)
+ // If it is the Clang driver the signal handler resignal itself to
+ // terminate after handling the signal.
+ NewHandler.sa_handler = InfoSignalHandlerTerminate;
+ else
+ NewHandler.sa_handler = InfoSignalHandler;
NewHandler.sa_flags = SA_ONSTACK;
break;
}
@@ -443,6 +449,10 @@ static void InfoSignalHandler(int Sig) {
SaveAndRestore SaveErrnoDuringASignalHandler(errno);
if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
CurrentInfoFunction();
+}
+
+static void InfoSignalHandlerTerminate(int Sig) {
+ InfoSignalHandler(Sig);
if (Sig == SIGUSR1) {
sys::unregisterHandlers();
@@ -496,9 +506,10 @@ void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
/// handler can have a cookie passed to it to identify what instance of the
/// handler it is.
void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
- void *Cookie) { // Signal-safe.
+ void *Cookie, bool IsClangDriver) {
+ // Signal-safe.
insertSignalHandler(FnPtr, Cookie);
- RegisterHandlers();
+ RegisterHandlers(IsClangDriver);
}
#if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) && \
>From 81d76ffdcafd2358cab474c0760c5254ffe32956 Mon Sep 17 00:00:00 2001
From: Xing Xue <xingxue at outlook.com>
Date: Fri, 9 Jan 2026 12:52:48 -0500
Subject: [PATCH 3/4] Fix formatting.
---
llvm/include/llvm/Support/InitLLVM.h | 2 +-
llvm/include/llvm/Support/Signals.h | 3 ++-
llvm/lib/Support/InitLLVM.cpp | 3 +--
llvm/lib/Support/Unix/Signals.inc | 6 +++---
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/Support/InitLLVM.h b/llvm/include/llvm/Support/InitLLVM.h
index 1473026e2974a..6859964bd8f22 100644
--- a/llvm/include/llvm/Support/InitLLVM.h
+++ b/llvm/include/llvm/Support/InitLLVM.h
@@ -39,7 +39,7 @@ class InitLLVM {
bool InstallPipeSignalExitHandler = true,
bool IsClandDriver = false);
InitLLVM(int &Argc, char **&Argv, bool InstallPipeSignalExitHandler = true,
- bool IsClangDriver = false)
+ bool IsClangDriver = false)
: InitLLVM(Argc, const_cast<const char **&>(Argv),
InstallPipeSignalExitHandler, IsClangDriver) {}
diff --git a/llvm/include/llvm/Support/Signals.h b/llvm/include/llvm/Support/Signals.h
index 22612a55b3a37..9d8fa97eb50b5 100644
--- a/llvm/include/llvm/Support/Signals.h
+++ b/llvm/include/llvm/Support/Signals.h
@@ -100,7 +100,8 @@ using SignalHandlerCallback = void (*)(void *);
/// Add a function to be called when an abort/kill signal is delivered to the
/// process. The handler can have a cookie passed to it to identify what
/// instance of the handler it is.
-LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie, bool IsClangDriver = false);
+LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie,
+ bool IsClangDriver = false);
/// This function registers a function to be called when the user "interrupts"
/// the program (typically by pressing ctrl-c). When the user interrupts the
diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index 248250cc5ddcb..795e9ab0bcf88 100644
--- a/llvm/lib/Support/InitLLVM.cpp
+++ b/llvm/lib/Support/InitLLVM.cpp
@@ -73,8 +73,7 @@ using namespace llvm;
using namespace llvm::sys;
InitLLVM::InitLLVM(int &Argc, const char **&Argv,
- bool InstallPipeSignalExitHandler,
- bool IsClangDriver) {
+ bool InstallPipeSignalExitHandler, bool IsClangDriver) {
#ifndef NDEBUG
static std::atomic<bool> Initialized{false};
assert(!Initialized && "InitLLVM was already initialized!");
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 1d1cc9c915a72..ad387bc0f0965 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -505,9 +505,9 @@ void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
/// Add a function to be called when a signal is delivered to the process. The
/// handler can have a cookie passed to it to identify what instance of the
/// handler it is.
-void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
- void *Cookie, bool IsClangDriver) {
- // Signal-safe.
+void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, void *Cookie,
+ bool IsClangDriver) {
+ // Signal-safe.
insertSignalHandler(FnPtr, Cookie);
RegisterHandlers(IsClangDriver);
}
>From 0ab850be4f8ea408751a69ca62ea8f565729aece Mon Sep 17 00:00:00 2001
From: Xing Xue <xingxue at outlook.com>
Date: Fri, 9 Jan 2026 15:23:09 -0500
Subject: [PATCH 4/4] Use a different AddSignalHandler signature for Windows.
---
llvm/include/llvm/Support/Signals.h | 8 +++++++-
llvm/lib/Support/InitLLVM.cpp | 4 ++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Support/Signals.h b/llvm/include/llvm/Support/Signals.h
index 9d8fa97eb50b5..7745927dc5258 100644
--- a/llvm/include/llvm/Support/Signals.h
+++ b/llvm/include/llvm/Support/Signals.h
@@ -99,9 +99,15 @@ using SignalHandlerCallback = void (*)(void *);
/// Add a function to be called when an abort/kill signal is delivered to the
/// process. The handler can have a cookie passed to it to identify what
-/// instance of the handler it is.
+/// instance of the handler it is. On Unix systems, the argument IsClangDriver
+/// indicates whether the function is called from a Clang driver so that the
+/// implementation ensures the Clang signal handling complies with POSIX.
+#ifdef _WIN32
+LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie);
+#else
LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie,
bool IsClangDriver = false);
+#endif
/// This function registers a function to be called when the user "interrupts"
/// the program (typically by pressing ctrl-c). When the user interrupts the
diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index 795e9ab0bcf88..2feb0b495d3eb 100644
--- a/llvm/lib/Support/InitLLVM.cpp
+++ b/llvm/lib/Support/InitLLVM.cpp
@@ -81,7 +81,11 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
#endif
// Bring stdin/stdout/stderr into a known state.
+#ifdef _WIN32
+ sys::AddSignalHandler(CleanupStdHandles, nullptr);
+#else
sys::AddSignalHandler(CleanupStdHandles, nullptr, IsClangDriver);
+#endif
if (InstallPipeSignalExitHandler)
// The pipe signal handler must be installed before any other handlers are
More information about the cfe-commits
mailing list