Index: lib/Fuzzer/FuzzerInternal.h =================================================================== --- lib/Fuzzer/FuzzerInternal.h +++ lib/Fuzzer/FuzzerInternal.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "FuzzerDefs.h" @@ -121,6 +122,7 @@ void ShuffleCorpus(UnitVector *V); void AddToCorpus(const Unit &U); void CheckExitOnSrcPosOrItem(); + void SetRunningCB(bool Value); // Trace-based fuzzing: we run a unit with some kind of tracing // enabled and record potentially useful mutations. Then @@ -144,6 +146,8 @@ void AllocateCurrentUnitData(); uint8_t *CurrentUnitData = nullptr; std::atomic CurrentUnitSize; + bool RunningCB; + std::mutex RunningCBMtx; uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit. size_t TotalNumberOfRuns = 0; Index: lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- lib/Fuzzer/FuzzerLoop.cpp +++ lib/Fuzzer/FuzzerLoop.cpp @@ -173,7 +173,7 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, FuzzingOptions Options) - : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { + : RunningCB(false), CB(CB), Corpus(Corpus), MD(MD), Options(Options) { SetDeathCallback(); InitializeTraceState(); assert(!F); @@ -270,22 +270,26 @@ " Combine libFuzzer with AddressSanitizer or similar for better " "crash reports.\n"); Printf("SUMMARY: libFuzzer: deadly signal\n"); - DumpCurrentUnit("crash-"); - PrintFinalStats(); + if (RunningCB) { // The fuzzer is in a consistent state. + DumpCurrentUnit("crash-"); + PrintFinalStats(); + } exit(Options.ErrorExitCode); } void Fuzzer::InterruptCallback() { Printf("==%d== libFuzzer: run interrupted; exiting\n", GetPid()); - PrintFinalStats(); + std::lock_guard Lock(RunningCBMtx); + if (RunningCB) // The fuzzer is in a consistent state. + PrintFinalStats(); _Exit(0); // Stop right now, don't perform any at-exit actions. } NO_SANITIZE_MEMORY void Fuzzer::AlarmCallback() { assert(Options.UnitTimeoutSec > 0); - if (!InFuzzingThread()) return; - if (!CurrentUnitSize) + std::lock_guard Lock(RunningCBMtx); + if (!RunningCB) return; // We have not started running units yet. size_t Seconds = duration_cast(system_clock::now() - UnitStartTime).count(); @@ -315,9 +319,12 @@ Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); if (EF->__sanitizer_print_memory_profile) EF->__sanitizer_print_memory_profile(95); - DumpCurrentUnit("oom-"); Printf("SUMMARY: libFuzzer: out-of-memory\n"); - PrintFinalStats(); + std::lock_guard Lock(RunningCBMtx); + if (RunningCB) { // The fuzzer is in a consistent state. + DumpCurrentUnit("oom-"); + PrintFinalStats(); + } _Exit(Options.ErrorExitCode); // Stop right now. } @@ -420,6 +427,11 @@ } } +void Fuzzer::SetRunningCB(bool Value) { + std::lock_guard Lock(RunningCBMtx); + RunningCB = Value; +} + void Fuzzer::RereadOutputCorpus(size_t MaxSize) { if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; std::vector AdditionalCorpus; @@ -529,7 +541,9 @@ UnitStartTime = system_clock::now(); ResetCounters(); // Reset coverage right before the callback. TPC.ResetMaps(); + SetRunningCB(true); int Res = CB(DataCopy, Size); + SetRunningCB(false); UnitStopTime = system_clock::now(); (void)Res; assert(Res == 0); Index: lib/Fuzzer/FuzzerUtilPosix.cpp =================================================================== --- lib/Fuzzer/FuzzerUtilPosix.cpp +++ lib/Fuzzer/FuzzerUtilPosix.cpp @@ -43,21 +43,56 @@ } } +static void SignalHandlerThread(sigset_t Set) { + int Sig; + while (true) { + sigwait(&Set, &Sig); + switch (Sig) { + case SIGALRM: + HandlerOpt.sigalrm_cb(); + break; + case SIGINT: + HandlerOpt.sigint_cb(); + break; + case SIGTERM: + HandlerOpt.sigterm_cb(); + break; + } + } +} + void SetSignalHandler(const SignalHandlerOptions& Opt) { HandlerOpt = Opt; + sigset_t Set; + sigemptyset(&Set); + + // Set SIGALRM, SIGING and SIGTERM to be handled in a separate thread. if (Opt.timeout > 0 && Opt.sigalrm_cb) { + sigaddset(&Set, SIGALRM); struct itimerval T {{Opt.timeout, 0}, {Opt.timeout, 0}}; if (setitimer(ITIMER_REAL, &T, nullptr)) { Printf("libFuzzer: setitimer failed with %d\n", errno); exit(1); } - SetSigaction(SIGALRM, [](int,siginfo_t*,void*) {HandlerOpt.sigalrm_cb();}); } if (Opt.sigint_cb) - SetSigaction(SIGINT, [](int,siginfo_t*,void*) {HandlerOpt.sigint_cb();}); + sigaddset(&Set, SIGINT); if (Opt.sigterm_cb) - SetSigaction(SIGTERM, [](int,siginfo_t*,void*) {HandlerOpt.sigterm_cb();}); + sigaddset(&Set, SIGTERM); + + if ((Opt.timeout > 0 && Opt.sigalrm_cb) || Opt.sigint_cb || Opt.sigterm_cb) { + //Block the listed signals in all future threads. + int Err; + if ((Err = pthread_sigmask(SIG_BLOCK, &Set, NULL))) { + Printf("libFuzzer: pthread_sigmask failed with %d.\n", Err); + exit(1); + } + // Start thread to wait for incoming signals. + std::thread T(SignalHandlerThread, Set); + T.detach(); + } + if (Opt.sigsegv_cb) SetSigaction(SIGSEGV, [](int,siginfo_t*,void*) {HandlerOpt.sigsegv_cb();}); if (Opt.sigbus_cb)