Options.Verbosity = Flags.verbosity;
Options.MaxLen = Flags.max_len;
Options.UnitTimeoutSec = Flags.timeout;
- Options.AbortOnTimeout = Flags.abort_on_timeout;
Options.TimeoutExitCode = Flags.timeout_exitcode;
Options.MaxTotalTimeSec = Flags.max_total_time;
Options.DoCrossOver = Flags.cross_over;
// Timer
if (Flags.timeout > 0)
SetTimer(Flags.timeout / 2 + 1);
+ if (Flags.handle_segv) SetSigSegvHandler();
+ if (Flags.handle_bus) SetSigBusHandler();
+ if (Flags.handle_abrt) SetSigAbrtHandler();
+ if (Flags.handle_ill) SetSigIllHandler();
+ if (Flags.handle_fpe) SetSigFpeHandler();
+ if (Flags.handle_int) SetSigIntHandler();
if (Flags.test_single_input) {
RunOneTest(&F, Flags.test_single_input);
timeout, 1200,
"Timeout in seconds (if positive). "
"If one unit runs more than this number of seconds the process will abort.")
-FUZZER_FLAG_INT(abort_on_timeout, 0, "If positive, call abort on timeout.")
FUZZER_FLAG_INT(timeout_exitcode, 77,
"Unless abort_on_timeout is set, use this exitcode on timeout.")
+FUZZER_FLAG_INT(error_exit_code, 77, "When libFuzzer's signal handlers are in "
+ "use exit with this exitcode after catching a deadly signal.")
FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
"time in seconds to run the fuzzer.")
FUZZER_FLAG_INT(help, 0, "Print help.")
FUZZER_FLAG_INT(print_new_cov_pcs, 0, "If 1, print out new covered pcs.")
FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
+FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
+FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGSEGV.")
+FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
+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.")
void PrintASCII(const Word &W, const char *PrintAfter = "");
std::string Hash(const Unit &U);
void SetTimer(int Seconds);
+void SetSigSegvHandler();
+void SetSigBusHandler();
+void SetSigAbrtHandler();
+void SetSigIllHandler();
+void SetSigFpeHandler();
+void SetSigIntHandler();
std::string Base64(const Unit &U);
int ExecuteCommand(const std::string &Command);
size_t GetPeakRSSMb();
int Verbosity = 1;
int MaxLen = 0;
int UnitTimeoutSec = 300;
- bool AbortOnTimeout = false;
int TimeoutExitCode = 77;
+ int ErrorExitCode = 77;
int MaxTotalTimeSec = 0;
bool DoCrossOver = true;
int MutateDepth = 5;
size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
static void StaticAlarmCallback();
+ static void StaticCrashSignalCallback();
+ static void StaticInterruptCallback();
void ExecuteCallback(const uint8_t *Data, size_t Size);
private:
void AlarmCallback();
+ void CrashCallback();
+ void InterruptCallback();
void MutateAndTestOne();
void ReportNewCoverage(const Unit &U);
bool RunOne(const uint8_t *Data, size_t Size);
void SetDeathCallback();
static void StaticDeathCallback();
+ void DumpCurrentUnit(const char *Prefix);
void DeathCallback();
uint8_t *CurrentUnitData;
F->DeathCallback();
}
-void Fuzzer::DeathCallback() {
- if (!CurrentUnitSize) return;
- Printf("DEATH:\n");
+void Fuzzer::DumpCurrentUnit(const char *Prefix) {
if (CurrentUnitSize <= kMaxUnitSizeToPrint) {
PrintHexArray(CurrentUnitData, CurrentUnitSize, "\n");
PrintASCII(CurrentUnitData, CurrentUnitSize, "\n");
}
WriteUnitToFileWithPrefix(
- {CurrentUnitData, CurrentUnitData + CurrentUnitSize}, "crash-");
+ {CurrentUnitData, CurrentUnitData + CurrentUnitSize}, Prefix);
+}
+
+void Fuzzer::DeathCallback() {
+ if (!CurrentUnitSize) return;
+ Printf("DEATH:\n");
+ DumpCurrentUnit("crash-");
PrintFinalStats();
}
F->AlarmCallback();
}
+void Fuzzer::StaticCrashSignalCallback() {
+ assert(F);
+ F->CrashCallback();
+}
+
+void Fuzzer::StaticInterruptCallback() {
+ assert(F);
+ F->InterruptCallback();
+}
+
+void Fuzzer::CrashCallback() {
+ Printf("==%d== ERROR: libFuzzer: deadly signal\n", GetPid());
+ if (__sanitizer_print_stack_trace)
+ __sanitizer_print_stack_trace();
+ Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
+ " Combine libFuzzer with AddressSanitizer or similar for better "
+ "crash reports.\n");
+ Printf("SUMMARY: libFuzzer: deadly signal\n");
+ DumpCurrentUnit("crash-");
+ PrintFinalStats();
+ exit(Options.ErrorExitCode);
+}
+
+void Fuzzer::InterruptCallback() {
+ Printf("==%d== libFuzzer: run interrupted; exiting\n", GetPid());
+ PrintFinalStats();
+ exit(0);
+}
+
void Fuzzer::AlarmCallback() {
assert(Options.UnitTimeoutSec > 0);
if (!CurrentUnitSize)
Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
Printf(" and the timeout value is %d (use -timeout=N to change)\n",
Options.UnitTimeoutSec);
- if (CurrentUnitSize <= kMaxUnitSizeToPrint) {
- PrintHexArray(CurrentUnitData, CurrentUnitSize, "\n");
- PrintASCII(CurrentUnitData, CurrentUnitSize, "\n");
- }
- WriteUnitToFileWithPrefix(
- {CurrentUnitData, CurrentUnitData + CurrentUnitSize}, "timeout-");
+ DumpCurrentUnit("timeout-");
Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
Seconds);
if (__sanitizer_print_stack_trace)
__sanitizer_print_stack_trace();
Printf("SUMMARY: libFuzzer: timeout\n");
PrintFinalStats();
- if (Options.AbortOnTimeout)
- abort();
exit(Options.TimeoutExitCode);
}
}
Fuzzer::StaticAlarmCallback();
}
+static void CrashHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticCrashSignalCallback();
+}
+
+static void InterruptHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticInterruptCallback();
+}
+
+static void SetSigaction(int signum,
+ void (*callback)(int, siginfo_t *, void *)) {
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = callback;
+ int Res = sigaction(signum, &sigact, 0);
+ assert(Res == 0);
+}
+
void SetTimer(int Seconds) {
struct itimerval T {{Seconds, 0}, {Seconds, 0}};
int Res = setitimer(ITIMER_REAL, &T, nullptr);
assert(Res == 0);
- struct sigaction sigact;
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = AlarmHandler;
- Res = sigaction(SIGALRM, &sigact, 0);
- assert(Res == 0);
+ SetSigaction(SIGALRM, AlarmHandler);
}
+void SetSigSegvHandler() { SetSigaction(SIGSEGV, CrashHandler); }
+void SetSigBusHandler() { SetSigaction(SIGBUS, CrashHandler); }
+void SetSigAbrtHandler() { SetSigaction(SIGABRT, CrashHandler); }
+void SetSigIllHandler() { SetSigaction(SIGILL, CrashHandler); }
+void SetSigFpeHandler() { SetSigaction(SIGFPE, CrashHandler); }
+void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); }
+
int NumberOfCpuCores() {
FILE *F = popen("nproc", "r");
int N = 0;
SingleInputTimeoutTest: ALARM: working on the last Unit for
SingleInputTimeoutTest-NOT: Test unit written to ./timeout-
-RUN: ASAN_OPTIONS=handle_abort=0 not --crash LLVMFuzzer-TimeoutTest -timeout=1 -abort_on_timeout=1
RUN: LLVMFuzzer-TimeoutTest -timeout=1 -timeout_exitcode=0
RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath
NullDerefTestExactPath: Test unit written to FOOBAR
+RUN: ASAN_OPTIONS=handle_segv=0 not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_OWN_SEGV_HANDLER
+LIBFUZZER_OWN_SEGV_HANDLER: == ERROR: libFuzzer: deadly signal
+LIBFUZZER_OWN_SEGV_HANDLER: SUMMARY: libFuzzer: deadly signal
+LIBFUZZER_OWN_SEGV_HANDLER: Test unit written to ./crash-
+
#not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s
RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s