Skip to content

[compiler-rt][libFuzzer] Add support for capturing SIGTRAP exits. #149120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

DanBlackwell
Copy link
Contributor

@DanBlackwell DanBlackwell commented Jul 16, 2025

Swift's FatalError raises a SIGTRAP, which currently causes the fuzzer to exit without writing out the crashing input.

rdar://142975522

Swift's FatalError raises a SIGTRAP, which currently causes the fuzzer to exit without writing out the crashing input.
@llvmbot
Copy link
Member

llvmbot commented Jul 16, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Dan Blackwell (DanBlackwell)

Changes

Swift's FatalError raises a SIGTRAP, which currently causes the fuzzer to exit without writing out the crashing input.


Full diff: https://github.com/llvm/llvm-project/pull/149120.diff

7 Files Affected:

  • (modified) compiler-rt/lib/fuzzer/FuzzerDriver.cpp (+1)
  • (modified) compiler-rt/lib/fuzzer/FuzzerFlags.def (+1)
  • (modified) compiler-rt/lib/fuzzer/FuzzerOptions.h (+1)
  • (modified) compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp (+1-1)
  • (modified) compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp (+2)
  • (modified) compiler-rt/test/fuzzer/SimpleTest.cpp (+7)
  • (added) compiler-rt/test/fuzzer/sig-trap.test (+7)
diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
index 40322e231602c..ad3a65aff80e2 100644
--- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
@@ -834,6 +834,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
   Options.HandleInt = Flags.handle_int;
   Options.HandleSegv = Flags.handle_segv;
   Options.HandleTerm = Flags.handle_term;
+  Options.HandleTrap = Flags.handle_trap;
   Options.HandleXfsz = Flags.handle_xfsz;
   Options.HandleUsr1 = Flags.handle_usr1;
   Options.HandleUsr2 = Flags.handle_usr2;
diff --git a/compiler-rt/lib/fuzzer/FuzzerFlags.def b/compiler-rt/lib/fuzzer/FuzzerFlags.def
index b88458a497404..96282b8f72a4f 100644
--- a/compiler-rt/lib/fuzzer/FuzzerFlags.def
+++ b/compiler-rt/lib/fuzzer/FuzzerFlags.def
@@ -152,6 +152,7 @@ FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.")
 FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.")
 FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.")
 FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
+FUZZER_FLAG_INT(handle_trap, 1, "If 1, try to intercept SIGTRAP.")
 FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
 FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
 FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
diff --git a/compiler-rt/lib/fuzzer/FuzzerOptions.h b/compiler-rt/lib/fuzzer/FuzzerOptions.h
index 72e2561061945..6478b63ad6935 100644
--- a/compiler-rt/lib/fuzzer/FuzzerOptions.h
+++ b/compiler-rt/lib/fuzzer/FuzzerOptions.h
@@ -82,6 +82,7 @@ struct FuzzingOptions {
   bool HandleInt = false;
   bool HandleSegv = false;
   bool HandleTerm = false;
+  bool HandleTrap = false;
   bool HandleXfsz = false;
   bool HandleUsr1 = false;
   bool HandleUsr2 = false;
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
index 735d1555d3053..7f065c79e717c 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -410,7 +410,7 @@ void SetSignalHandler(const FuzzingOptions &Options) {
 
   // Early exit if no crash handler needed.
   if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
-      !Options.HandleFpe && !Options.HandleAbrt)
+      !Options.HandleFpe && !Options.HandleAbrt && !Options.HandleTrap)
     return;
 
   // Set up the crash handler and wait until it is ready before proceeding.
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
index 392c1e5be4eea..ae22ecf108420 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
@@ -132,6 +132,8 @@ void SetSignalHandler(const FuzzingOptions& Options) {
     SetSigaction(SIGILL, CrashHandler);
   if (Options.HandleFpe)
     SetSigaction(SIGFPE, CrashHandler);
+  if (Options.HandleTrap)
+    SetSigaction(SIGTRAP, CrashHandler);
   if (Options.HandleXfsz)
     SetSigaction(SIGXFSZ, FileSizeExceedHandler);
   if (Options.HandleUsr1)
diff --git a/compiler-rt/test/fuzzer/SimpleTest.cpp b/compiler-rt/test/fuzzer/SimpleTest.cpp
index c51227ba2a441..3cd0cbc615120 100644
--- a/compiler-rt/test/fuzzer/SimpleTest.cpp
+++ b/compiler-rt/test/fuzzer/SimpleTest.cpp
@@ -9,6 +9,9 @@
 #include <cstdlib>
 #include <iostream>
 #include <ostream>
+#ifdef SIGTRAP_TEST
+#  include <signal.h>
+#endif
 
 static volatile int Sink;
 
@@ -20,7 +23,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
       Sink = 2;
       if (Size > 2 && Data[2] == '!') {
         std::cout << "BINGO; Found the target, exiting\n" << std::flush;
+#ifdef SIGTRAP_TEST
+        raise(SIGTRAP);
+#else
         exit(0);
+#endif
       }
     }
   }
diff --git a/compiler-rt/test/fuzzer/sig-trap.test b/compiler-rt/test/fuzzer/sig-trap.test
new file mode 100644
index 0000000000000..ac9bcaa608b18
--- /dev/null
+++ b/compiler-rt/test/fuzzer/sig-trap.test
@@ -0,0 +1,7 @@
+RUN: %cpp_compiler %S/SimpleTest.cpp -DSIGTRAP_TEST -o %t-SigTrapTest
+
+RUN: not %run %t-SigTrapTest            2>&1 | FileCheck %s
+CHECK: BINGO
+CHECK: ERROR: libFuzzer: deadly signal
+
+RUN: trap "%run %t-SigTrapTest -handle_trap=0" TRAP

Copy link
Contributor

@thetruestblue thetruestblue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems reasonable. I have one question about the test. Let's give fuzzer maintainers chance to approve as well.

@@ -9,6 +9,9 @@
#include <cstdlib>
#include <iostream>
#include <ostream>
#ifdef SIGTRAP_TEST
# include <signal.h>
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not super familiar with patterns for fuzzer testing. But is there a reason we're injecting the test here rather than a stand alone file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, I've broken it out into a separate file now because this was ugly.

Copy link

github-actions bot commented Jul 17, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@DanBlackwell DanBlackwell force-pushed the libfuzzer-support-sigtrap branch from 9f9fb62 to 0a0db65 Compare July 17, 2025 08:41
@DanBlackwell DanBlackwell force-pushed the libfuzzer-support-sigtrap branch from 0a0db65 to 72293b5 Compare July 17, 2025 08:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants