[llvm] [Support] Register SIGPIPE handler when the one-shot is set late (PR #208887)
Alex Kuleshov via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 19 08:21:29 PDT 2026
https://github.com/0xAX updated https://github.com/llvm/llvm-project/pull/208887
>From 921241ea04ed06db90a8b63c7a0fd8f5457d589f Mon Sep 17 00:00:00 2001
From: Alexander Kuleshov <kuleshovmail at gmail.com>
Date: Wed, 15 Jul 2026 00:25:20 +0500
Subject: [PATCH] [Support] Register SIGPIPE handler when the one-shot is set
late
On Unix, RegisterHandlers() performs a sigaction() for SIGPIPE only
when a one-shot pipe signal function is set. At the same time,
RegisterHandlers() returned early when any signal handlers were
already registered. As a result, calling SetOneShotPipeSignalFunction()
after another handler had been registered would never install the
SIGPIPE handler, and tools were killed by SIGPIPE instead of exiting
cleanly with EX_IOERR.
This happens in InitLLVM(). It registers the cleanup handler
for stdout/stderr before installing the one-shot pipe function.
This commit updates RegisterHandlers() to handle the case when
handlers are already registered but SIGPIPE is not and the one-shot
pipe function has just been set. Only the SIGPIPE handler is
registered in this case, reusing the POSIX utility signal-handling
semantics from the initial registration rather than the current
caller's value.
---
llvm/lib/Support/InitLLVM.cpp | 11 +++++----
llvm/lib/Support/Unix/Signals.inc | 39 +++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index 797c5d35bec35..fb725f9fdc91e 100644
--- a/llvm/lib/Support/InitLLVM.cpp
+++ b/llvm/lib/Support/InitLLVM.cpp
@@ -90,11 +90,12 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
#endif
if (InstallPipeSignalExitHandler)
- // The pipe signal handler must be installed before any other handlers are
- // registered. This is because the Unix \ref RegisterHandlers function does
- // not perform a sigaction() for SIGPIPE unless a one-shot handler is
- // present, to allow long-lived processes (like lldb) to fully opt-out of
- // llvm's SIGPIPE handling and ignore the signal safely.
+ // The Unix \ref RegisterHandlers function only performs a sigaction() for
+ // SIGPIPE when a one-shot handler is present, so that long-lived processes
+ // (like lldb) can fully opt-out of llvm's SIGPIPE handling and ignore the
+ // signal safely. Installing the one-shot handler registers SIGPIPE even
+ // though other handlers (like CleanupStdHandles above) have already been
+ // registered.
sys::SetOneShotPipeSignalFunction(sys::DefaultOneShotPipeSignalHandler);
// Initialize the stack printer after installing the one-shot pipe signal
// handler, so we can perform a sigaction() for SIGPIPE on Unix if requested.
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 772fa37b004ac..94fbca982006d 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -328,13 +328,13 @@ static void RegisterHandlers(
static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex;
sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex);
- // If the handlers are already registered, we're done.
- if (NumRegisteredSignals.load() != 0)
- return;
-
- // Create an alternate stack for signal handling. This is necessary for us to
- // be able to reliably handle signals due to stack overflow.
- CreateSigAltStack();
+ // Remember NeedsPOSIXUtilitySignalHandling from the first call that
+ // registers the handlers. If a later call registers SIGPIPE (see below), it
+ // must use this saved value, not its own argument, so that SIGPIPE gets the
+ // same handling semantics as all the signals registered before it.
+ static bool POSIXUtilitySignalHandling = false;
+ if (NumRegisteredSignals.load() == 0)
+ POSIXUtilitySignalHandling = NeedsPOSIXUtilitySignalHandling;
enum class SignalKind { IsKill, IsInfo };
auto registerHandler = [&](int Signal, SignalKind Kind) {
@@ -346,7 +346,7 @@ static void RegisterHandlers(
switch (Kind) {
case SignalKind::IsKill:
- if (NeedsPOSIXUtilitySignalHandling)
+ if (POSIXUtilitySignalHandling)
// If POSIX signal-handling semantics are followed, the signal handler
// resignal itself to terminate after handling the signal.
NewHandler.sa_sigaction = SignalHandlerTerminate;
@@ -355,7 +355,7 @@ static void RegisterHandlers(
NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK | SA_SIGINFO;
break;
case SignalKind::IsInfo:
- if (NeedsPOSIXUtilitySignalHandling)
+ if (POSIXUtilitySignalHandling)
// If POSIX signal-handling semantics are followed, the signal handler
// resignal itself to terminate after handling the signal.
NewHandler.sa_handler = InfoSignalHandlerTerminate;
@@ -366,7 +366,7 @@ static void RegisterHandlers(
}
sigemptyset(&NewHandler.sa_mask);
- if (NeedsPOSIXUtilitySignalHandling) {
+ if (POSIXUtilitySignalHandling) {
// Don't install the new handler if the signal disposition is SIG_IGN.
struct sigaction act;
if (sigaction(Signal, NULL, &act) == 0 && act.sa_handler != SIG_IGN)
@@ -378,6 +378,25 @@ static void RegisterHandlers(
++NumRegisteredSignals;
};
+ // If the handlers are already registered, the only work that may remain is
+ // a sigaction() for SIGPIPE, which is skipped until a one-shot pipe signal
+ // function is installed. SetOneShotPipeSignalFunction can be called
+ // after the other handlers have been registered (for example InitLLVM
+ // registers a cleanup handler before it installs the pipe function), so
+ // register SIGPIPE now if it is needed and still missing.
+ if (NumRegisteredSignals.load() != 0) {
+ bool SigPipeRegistered = false;
+ for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i)
+ SigPipeRegistered |= RegisteredSignalInfo[i].SigNo == SIGPIPE;
+ if (OneShotPipeSignalFunction && !SigPipeRegistered)
+ registerHandler(SIGPIPE, SignalKind::IsKill);
+ return;
+ }
+
+ // Create an alternate stack for signal handling. This is necessary for us to
+ // be able to reliably handle signals due to stack overflow.
+ CreateSigAltStack();
+
for (auto S : IntSigs)
registerHandler(S, SignalKind::IsKill);
for (auto S : KillSigs)
More information about the llvm-commits
mailing list