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" @@ -142,6 +143,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 @@ -157,7 +157,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); @@ -254,22 +254,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(); @@ -299,9 +303,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. } @@ -513,7 +520,13 @@ UnitStartTime = system_clock::now(); ResetCounters(); // Reset coverage right before the callback. TPC.ResetMaps(); + RunningCBMtx.lock(); + RunningCB = true; + RunningCBMtx.unlock(); int Res = CB(DataCopy, Size); + RunningCBMtx.lock(); + RunningCB = false; + RunningCBMtx.unlock(); 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)