From a8d0dd01f46fdbdf3b6d5bd471b64e6bd07fc796 Mon Sep 17 00:00:00 2001 From: Dan Blackwell Date: Wed, 16 Jul 2025 16:31:08 +0100 Subject: [PATCH 1/2] [compiler-rt][libFuzzer] Add support for capturing SIGTRAP exits. Swift's FatalError raises a SIGTRAP, which currently causes the fuzzer to exit without writing out the crashing input. --- compiler-rt/lib/fuzzer/FuzzerDriver.cpp | 1 + compiler-rt/lib/fuzzer/FuzzerFlags.def | 1 + compiler-rt/lib/fuzzer/FuzzerOptions.h | 1 + compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp | 2 +- compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp | 2 ++ compiler-rt/test/fuzzer/SimpleTest.cpp | 7 +++++++ compiler-rt/test/fuzzer/sig-trap.test | 7 +++++++ 7 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 compiler-rt/test/fuzzer/sig-trap.test 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 #include #include +#ifdef SIGTRAP_TEST +# include +#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 From 72293b55020cf0cd83e3b4875ce299628064f530 Mon Sep 17 00:00:00 2001 From: Dan Blackwell Date: Thu, 17 Jul 2025 09:36:17 +0100 Subject: [PATCH 2/2] Break SIGTRAP test cpp file out into separate file --- compiler-rt/test/fuzzer/SigTrapTest.cpp | 29 +++++++++++++++++++++++++ compiler-rt/test/fuzzer/SimpleTest.cpp | 7 ------ compiler-rt/test/fuzzer/sig-trap.test | 6 ++--- 3 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 compiler-rt/test/fuzzer/SigTrapTest.cpp diff --git a/compiler-rt/test/fuzzer/SigTrapTest.cpp b/compiler-rt/test/fuzzer/SigTrapTest.cpp new file mode 100644 index 0000000000000..c3019a162fade --- /dev/null +++ b/compiler-rt/test/fuzzer/SigTrapTest.cpp @@ -0,0 +1,29 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include +#include +#include +#include +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + raise(SIGTRAP); + } + } + } + return 0; +} diff --git a/compiler-rt/test/fuzzer/SimpleTest.cpp b/compiler-rt/test/fuzzer/SimpleTest.cpp index 3cd0cbc615120..c51227ba2a441 100644 --- a/compiler-rt/test/fuzzer/SimpleTest.cpp +++ b/compiler-rt/test/fuzzer/SimpleTest.cpp @@ -9,9 +9,6 @@ #include #include #include -#ifdef SIGTRAP_TEST -# include -#endif static volatile int Sink; @@ -23,11 +20,7 @@ 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 index ac9bcaa608b18..ee47d2c79e0e2 100644 --- a/compiler-rt/test/fuzzer/sig-trap.test +++ b/compiler-rt/test/fuzzer/sig-trap.test @@ -1,7 +1,7 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -DSIGTRAP_TEST -o %t-SigTrapTest +RUN: %cpp_compiler %S/SigTrapTest.cpp -o %t -RUN: not %run %t-SigTrapTest 2>&1 | FileCheck %s +RUN: not %run %t 2>&1 | FileCheck %s CHECK: BINGO CHECK: ERROR: libFuzzer: deadly signal -RUN: trap "%run %t-SigTrapTest -handle_trap=0" TRAP +RUN: trap "%run %t -handle_trap=0" TRAP