[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