Author: Xing Xue
Date: 2026-02-18T13:52:07-05:00
New Revision: 15488a7f78ce7b9ae3c06b031134e5cb339b335c

URL: 
https://github.com/llvm/llvm-project/commit/15488a7f78ce7b9ae3c06b031134e5cb339b335c
DIFF: 
https://github.com/llvm/llvm-project/commit/15488a7f78ce7b9ae3c06b031134e5cb339b335c.diff

LOG: [LLVM][CLANG] Update signal-handling behavior to comply with POSIX 
(#169340)

The POSIX standard
[POSIX.1-2024](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap01.html#tag_18)
specifies how the utility reacts to signals as follows. This includes
clang when invoke through a invocation such as
[c17](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/c17.html)
```
ASYNCHRONOUS EVENTS

    The ASYNCHRONOUS EVENTS section lists how the utility reacts to such events 
as signals and what signals are caught.

    Default Behavior: When this section is listed as "Default.", or it refers 
to "the standard action" for any signal, it means that the action taken as a 
result of the signal shall be as follows:

        If the action inherited from the invoking process, according to the 
rules of inheritance of signal actions defined in the System Interfaces volume 
of POSIX.1-2024, is for the signal to be ignored, the utility shall ignore the 
signal.
        If the action inherited from the invoking process, according to the 
rules of inheritance of signal actions defined in System Interfaces volume of 
POSIX.1-2024, is the default signal action, the result of the utility's 
execution shall be as if the default signal action had been taken.

    When the required action is for the signal to terminate the utility, the 
utility may catch the signal, perform some additional processing (such as 
deleting temporary files), restore the default signal action, and resignal 
itself.
```
This PR updates the LLVM/Clang’s behavior accordingly by not installing
a signal handler when the inherited disposition is `SIG_IGN`, and by
ensuring that the exit code reflects the terminating signal number,
resignaling after the signal is handled. Additionally, test cases have
been updated to expect failures due to signals/crashes rather than
regular errors.


[<signal.h>](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html)
specifies the default action of signals.

Added: 
    

Modified: 
    clang/lib/Driver/Driver.cpp
    clang/test/Driver/crash-diagnostics-dir-3.c
    clang/test/Driver/crash-diagnostics-dir.c
    clang/test/Driver/crash-ir-repro.cpp
    clang/test/Driver/crash-report-clang-cl.cpp
    clang/test/Driver/crash-report-header.h
    clang/test/Driver/crash-report-spaces.c
    clang/test/Driver/crash-report-with-asserts.c
    clang/test/Driver/crash-report.cpp
    clang/test/Driver/emit-reproducer.c
    clang/test/Driver/lit.local.cfg
    clang/test/Driver/output-file-cleanup.c
    clang/tools/driver/driver.cpp
    llvm/cmake/modules/AddLLVM.cmake
    llvm/cmake/modules/llvm-driver-template.cpp.in
    llvm/include/llvm/Support/CrashRecoveryContext.h
    llvm/include/llvm/Support/InitLLVM.h
    llvm/include/llvm/Support/Signals.h
    llvm/lib/Support/CrashRecoveryContext.cpp
    llvm/lib/Support/InitLLVM.cpp
    llvm/lib/Support/Unix/Signals.inc
    llvm/lib/Support/Windows/Signals.inc

Removed: 
    


################################################################################
diff  --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index d7d744d1770b6..1f3f66bf37c4a 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2318,7 +2318,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/test/Driver/crash-diagnostics-dir-3.c 
b/clang/test/Driver/crash-diagnostics-dir-3.c
index a91bc48d7e462..63a5efc853a4c 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_opt 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..9a8299bffe005 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_opt %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 217d5ed421bdb..1a2000ad1279f 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_opt %clang -S -DCRASH %s -o %t.ll 2>&1 | FileCheck %s
 
 // TODO(boomanaiden154): This test case causes clang to raise a signal when
 // running under ubsan, but not in normal build configurations. This should

diff  --git a/clang/test/Driver/crash-report-clang-cl.cpp 
b/clang/test/Driver/crash-report-clang-cl.cpp
index 963c3b6d0ab03..f61b94626f584 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_opt %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..6d5156537126d 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_opt 
%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..b5fbb59683fc0 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_opt 
%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..278860a9158e4 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_opt %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_opt %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..c431940bf9ea1 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_opt %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_opt %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..6fd1735ee8549 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_opt %clang -DFATAL @%t.rsp -gen-reproducer=off    2>&1 | 
FileCheck %s --check-prefix=NOT
+// RUN: not %crash_opt %clang -DFATAL @%t.rsp -fno-crash-diagnostics 2>&1 | 
FileCheck %s --check-prefix=NOT
+// RUN: not %crash_opt %clang -DFATAL @%t.rsp                        2>&1 | 
FileCheck %s
+// RUN: not %crash_opt %clang -DFATAL @%t.rsp -gen-reproducer=crash  2>&1 | 
FileCheck %s
+// RUN: not %crash_opt %clang -DFATAL @%t.rsp -gen-reproducer=error  2>&1 | 
FileCheck %s
+// RUN: not %crash_opt %clang -DFATAL @%t.rsp -gen-reproducer=always 2>&1 | 
FileCheck %s
+// RUN: not %crash_opt %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/lit.local.cfg b/clang/test/Driver/lit.local.cfg
index 6370e9f92d89b..a47d0de90d763 100644
--- a/clang/test/Driver/lit.local.cfg
+++ b/clang/test/Driver/lit.local.cfg
@@ -1,4 +1,5 @@
 from lit.llvm import llvm_config
+import sys
 
 config.suffixes = [
     ".c",
@@ -27,6 +28,12 @@ config.substitutions.insert(
     0, ("%clang_cc1", """*** Do not use 'clang -cc1' in Driver tests. ***""")
 )
 
+is_windows = sys.platform.startswith("win")
+if is_windows:
+    config.substitutions.append(('%crash_opt', ''))
+else:
+    config.substitutions.append(('%crash_opt', '--crash'))
+
 # Remove harmful environmental variables for clang Driver tests.
 # Some might be useful for other tests so they are only removed here.
 driver_overwrite_env_vars = [

diff  --git a/clang/test/Driver/output-file-cleanup.c 
b/clang/test/Driver/output-file-cleanup.c
index 3628df8192652..432ff640656e7 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_opt %clang -S -DCRASH -o %t.s -MMD -MF %t.d %s
 // RUN: test ! -f %t.s
 // RUN: test ! -f %t.d
 

diff  --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 490136961ebc6..e6cabcc7eb530 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;
@@ -378,7 +381,7 @@ int clang_main(int Argc, char **Argv, const 
llvm::ToolContext &ToolContext) {
   if (!UseNewCC1Process) {
     TheDriver.CC1Main = ExecuteCC1WithContext;
     // Ensure the CC1Command actually catches cc1 crashes
-    llvm::CrashRecoveryContext::Enable();
+    llvm::CrashRecoveryContext::Enable(true);
   }
 
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
@@ -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/cmake/modules/AddLLVM.cmake 
b/llvm/cmake/modules/AddLLVM.cmake
index d938214f9d0df..81aaf6034cca7 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -1004,6 +1004,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, 
/*NeedsPOSIXUtilitySignalHandling=*/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@_main(int argc, char **, const llvm::ToolContext &);
 
 int main(int argc, char **argv) {
-  llvm::InitLLVM X(argc, argv);
+  llvm::InitLLVM X(argc, argv@INITLLVM_ARGS@);
   return @TOOL_NAME@_main(argc, argv, {argv[0], nullptr, false});
 }

diff  --git a/llvm/include/llvm/Support/CrashRecoveryContext.h 
b/llvm/include/llvm/Support/CrashRecoveryContext.h
index ffee81dd24587..4abd2d0eedcde 100644
--- a/llvm/include/llvm/Support/CrashRecoveryContext.h
+++ b/llvm/include/llvm/Support/CrashRecoveryContext.h
@@ -60,7 +60,7 @@ class CrashRecoveryContext {
   LLVM_ABI void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
 
   /// Enable crash recovery.
-  LLVM_ABI static void Enable();
+  LLVM_ABI static void Enable(bool NeedsPOSIXUtilitySignalHandling = false);
 
   /// Disable crash recovery.
   LLVM_ABI static void Disable();

diff  --git a/llvm/include/llvm/Support/InitLLVM.h 
b/llvm/include/llvm/Support/InitLLVM.h
index 748f5d8aa6aea..4d513bfd576bb 100644
--- a/llvm/include/llvm/Support/InitLLVM.h
+++ b/llvm/include/llvm/Support/InitLLVM.h
@@ -36,10 +36,13 @@ 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 NeedsPOSIXUtilitySignalHandling = false);
+  InitLLVM(int &Argc, char **&Argv, bool InstallPipeSignalExitHandler = true,
+           bool NeedsPOSIXUtilitySignalHandling = false)
       : InitLLVM(Argc, const_cast<const char **&>(Argv),
-                 InstallPipeSignalExitHandler) {}
+                 InstallPipeSignalExitHandler,
+                 NeedsPOSIXUtilitySignalHandling) {}
 
   LLVM_ABI ~InitLLVM();
 

diff  --git a/llvm/include/llvm/Support/Signals.h 
b/llvm/include/llvm/Support/Signals.h
index 21b425fffef53..d9bff20b85393 100644
--- a/llvm/include/llvm/Support/Signals.h
+++ b/llvm/include/llvm/Support/Signals.h
@@ -99,8 +99,12 @@ 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);
+/// instance of the handler it is. The NeedsPOSIXUtilitySignalHandling
+/// argument indicates whether POSIX signal handling semantics are followed,
+/// so that the signal handler resignals itself to terminate after handling
+/// the signal.
+LLVM_ABI void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie,
+                               bool NeedsPOSIXUtilitySignalHandling = 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/CrashRecoveryContext.cpp 
b/llvm/lib/Support/CrashRecoveryContext.cpp
index fc30d421506a6..fb9f2ec333a7b 100644
--- a/llvm/lib/Support/CrashRecoveryContext.cpp
+++ b/llvm/lib/Support/CrashRecoveryContext.cpp
@@ -92,7 +92,8 @@ static LLVM_THREAD_LOCAL const CrashRecoveryContext 
*IsRecoveringFromCrash;
 
 } // namespace
 
-static void installExceptionOrSignalHandlers();
+static void
+installExceptionOrSignalHandlers(bool NeedsPOSIXUtilitySignalHandling);
 static void uninstallExceptionOrSignalHandlers();
 
 CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() = default;
@@ -137,13 +138,13 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
   return CRCI->CRC;
 }
 
-void CrashRecoveryContext::Enable() {
+void CrashRecoveryContext::Enable(bool NeedsPOSIXUtilitySignalHandling) {
   std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
   // FIXME: Shouldn't this be a refcount or something?
   if (gCrashRecoveryEnabled)
     return;
   gCrashRecoveryEnabled = true;
-  installExceptionOrSignalHandlers();
+  installExceptionOrSignalHandlers(NeedsPOSIXUtilitySignalHandling);
 }
 
 void CrashRecoveryContext::Disable() {
@@ -193,7 +194,8 @@ 
CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
 // catches exceptions if they would bubble out from the stack frame with __try 
/
 // __except.
 
-static void installExceptionOrSignalHandlers() {}
+static void
+installExceptionOrSignalHandlers(bool NeedsPOSIXUtilitySignalHandling) {}
 static void uninstallExceptionOrSignalHandlers() {}
 
 // We need this function because the call to GetExceptionInformation() can only
@@ -309,7 +311,8 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS 
ExceptionInfo)
 // non-NULL, valid VEH handles, or NULL.
 static LLVM_THREAD_LOCAL const void* sCurrentExceptionHandle;
 
-static void installExceptionOrSignalHandlers() {
+static void
+installExceptionOrSignalHandlers(bool NeedsPOSIXUtilitySignalHandling) {
   // We can set up vectored exception handling now.  We will install our
   // handler as the front of the list, though there's no assurances that
   // it will remain at the front (another call could install itself before
@@ -390,7 +393,8 @@ static void CrashRecoverySignalHandler(int Signal) {
     const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal);
 }
 
-static void installExceptionOrSignalHandlers() {
+static void
+installExceptionOrSignalHandlers(bool NeedsPOSIXUtilitySignalHandling) {
   // Setup the signal handler.
   struct sigaction Handler;
   Handler.sa_handler = CrashRecoverySignalHandler;
@@ -398,7 +402,14 @@ static void installExceptionOrSignalHandlers() {
   sigemptyset(&Handler.sa_mask);
 
   for (unsigned i = 0; i != NumSignals; ++i) {
-    sigaction(Signals[i], &Handler, &PrevActions[i]);
+    if (NeedsPOSIXUtilitySignalHandling) {
+      // Don't install the new handler if the signal disposition is SIG_IGN.
+      struct sigaction act;
+      if (sigaction(Signals[i], NULL, &act) == 0 && act.sa_handler != SIG_IGN)
+        sigaction(Signals[i], &Handler, &PrevActions[i]);
+    } else {
+      sigaction(Signals[i], &Handler, &PrevActions[i]);
+    }
   }
 }
 

diff  --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index b90f4e0714458..797c5d35bec35 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 NeedsPOSIXUtilitySignalHandling) {
 #ifndef NDEBUG
   static std::atomic<bool> Initialized{false};
   assert(!Initialized && "InitLLVM was already initialized!");
@@ -81,7 +82,12 @@ 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,
+                        NeedsPOSIXUtilitySignalHandling);
+#endif
 
   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 56ad4fc504153..e861240189617 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -84,8 +84,10 @@
 
 using namespace llvm;
 
-static void SignalHandler(int Sig, siginfo_t *Info, void *);
+static void SignalHandler(int Sig, siginfo_t *Info, void *Context);
+static void SignalHandlerTerminate(int Sig, siginfo_t *Info, void *Context);
 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 +294,8 @@ static void CreateSigAltStack() {
 static void CreateSigAltStack() {}
 #endif
 
-static void RegisterHandlers() { // Not signal-safe.
+static void RegisterHandlers(
+    bool NeedsPOSIXUtilitySignalHandling = 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.
@@ -317,18 +320,34 @@ static void RegisterHandlers() { // Not signal-safe.
 
     switch (Kind) {
     case SignalKind::IsKill:
-      NewHandler.sa_sigaction = SignalHandler;
+      if (NeedsPOSIXUtilitySignalHandling)
+        // If POSIX signal-handling semantics are followed, the signal handler
+        // resignal itself to terminate after handling the signal.
+        NewHandler.sa_sigaction = SignalHandlerTerminate;
+      else
+        NewHandler.sa_sigaction = SignalHandler;
       NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK | 
SA_SIGINFO;
       break;
     case SignalKind::IsInfo:
-      NewHandler.sa_handler = InfoSignalHandler;
+      if (NeedsPOSIXUtilitySignalHandling)
+        // If POSIX signal-handling semantics are followed, 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;
     }
     sigemptyset(&NewHandler.sa_mask);
 
-    // Install the new handler, save the old one in RegisteredSignalInfo.
-    sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
+    if (NeedsPOSIXUtilitySignalHandling) {
+      // 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)
+        sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
+    } else {
+      sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
+    }
     RegisteredSignalInfo[Index].SigNo = Signal;
     ++NumRegisteredSignals;
   };
@@ -377,7 +396,7 @@ void sys::CleanupOnSignal(uintptr_t Context) {
 }
 
 // The signal handler that runs.
-static void SignalHandler(int Sig, siginfo_t *Info, void *) {
+static void SignalHandler(int Sig, siginfo_t *Info, void *Context) {
   // Restore the signal behavior to default, so that the program actually
   // crashes when we return and the signal reissues.  This also ensures that if
   // we crash in our signal handler that the program will terminate immediately
@@ -437,12 +456,30 @@ static void SignalHandler(int Sig, siginfo_t *Info, void 
*) {
 #endif
 }
 
+static void SignalHandlerTerminate(int Sig, siginfo_t *Info, void *Context) {
+  SignalHandler(Sig, Info, Context);
+
+  // 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.
+}
+
 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();
+    raise(Sig);
+  }
+}
+
 void sys::RunInterruptHandlers() {
   // Let's not interfere with stack trace symbolication and friends.
   auto BypassSandbox = sandbox::scopedDisable();
@@ -488,10 +525,11 @@ 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) { // Signal-safe.
+void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, void 
*Cookie,
+                                 bool NeedsPOSIXUtilitySignalHandling) {
+  // Signal-safe.
   insertSignalHandler(FnPtr, Cookie);
-  RegisterHandlers();
+  RegisterHandlers(NeedsPOSIXUtilitySignalHandling);
 }
 
 #if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) &&                            
\

diff  --git a/llvm/lib/Support/Windows/Signals.inc 
b/llvm/lib/Support/Windows/Signals.inc
index eec112e5a80f5..7e6799befb983 100644
--- a/llvm/lib/Support/Windows/Signals.inc
+++ b/llvm/lib/Support/Windows/Signals.inc
@@ -549,8 +549,8 @@ void llvm::sys::CallOneShotPipeSignalHandler() {
 /// 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) {
+void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, void 
*Cookie,
+                                 bool NeedsPOSIXUtilitySignalHandling) {
   insertSignalHandler(FnPtr, Cookie);
   RegisterHandler();
   LeaveCriticalSection(&CriticalSection);


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to