Index: lib/Fuzzer/FuzzerDriver.cpp =================================================================== --- lib/Fuzzer/FuzzerDriver.cpp +++ lib/Fuzzer/FuzzerDriver.cpp @@ -455,18 +455,21 @@ if (U.size() <= Word::GetMaxSize()) MD->AddWordToManualDictionary(Word(U.data(), U.size())); - StartRssThread(F, Flags.rss_limit_mb); + SignalHandlerOptions Opts; + if (Flags.timeout > 0) { + Opts.timeout = Flags.timeout / 2 + 1; + Opts.sigalrm_cb = Fuzzer::StaticAlarmCallback; + } + Opts.sigsegv_cb = Fuzzer::StaticCrashSignalCallback; + Opts.sigbus_cb = Fuzzer::StaticCrashSignalCallback; + Opts.sigabrt_cb = Fuzzer::StaticCrashSignalCallback; + Opts.sigill_cb = Fuzzer::StaticCrashSignalCallback; + Opts.sigfpe_cb = Fuzzer::StaticCrashSignalCallback; + Opts.sigint_cb = Fuzzer::StaticInterruptCallback; + Opts.sigterm_cb = Fuzzer::StaticInterruptCallback; + SetSignalHandler(Opts); - // 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.handle_term) SetSigTermHandler(); + StartRssThread(F, Flags.rss_limit_mb); if (Flags.minimize_crash_internal_step) return MinimizeCrashInputInternalStep(F, Corpus); 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/FuzzerUtil.h =================================================================== --- lib/Fuzzer/FuzzerUtil.h +++ lib/Fuzzer/FuzzerUtil.h @@ -41,15 +41,20 @@ int NumberOfCpuCores(); // Platform specific functions. -void SetTimer(int Seconds); - -void SetSigSegvHandler(); -void SetSigBusHandler(); -void SetSigAbrtHandler(); -void SetSigIllHandler(); -void SetSigFpeHandler(); -void SetSigIntHandler(); -void SetSigTermHandler(); +struct SignalHandlerOptions { + typedef void (*HandlerT)(); + int timeout = 0; + HandlerT sigalrm_cb = nullptr; + HandlerT sigsegv_cb = nullptr; + HandlerT sigbus_cb = nullptr; + HandlerT sigabrt_cb = nullptr; + HandlerT sigill_cb = nullptr; + HandlerT sigfpe_cb = nullptr; + HandlerT sigint_cb = nullptr; + HandlerT sigterm_cb = nullptr; +}; + +void SetSignalHandler(const SignalHandlerOptions& Opt); void SleepSeconds(int Seconds); Index: lib/Fuzzer/FuzzerUtilPosix.cpp =================================================================== --- lib/Fuzzer/FuzzerUtilPosix.cpp +++ lib/Fuzzer/FuzzerUtilPosix.cpp @@ -11,7 +11,7 @@ #include "FuzzerDefs.h" #if LIBFUZZER_POSIX -#include "FuzzerInternal.h" +#include "FuzzerUtil.h" #include "FuzzerIO.h" #include #include @@ -30,17 +30,7 @@ namespace fuzzer { -static void AlarmHandler(int, siginfo_t *, void *) { - Fuzzer::StaticAlarmCallback(); -} - -static void CrashHandler(int, siginfo_t *, void *) { - Fuzzer::StaticCrashSignalCallback(); -} - -static void InterruptHandler(int, siginfo_t *, void *) { - Fuzzer::StaticInterruptCallback(); -} +static SignalHandlerOptions HandlerOpt; static void SetSigaction(int signum, void (*callback)(int, siginfo_t *, void *)) { @@ -53,22 +43,67 @@ } } -void SetTimer(int Seconds) { - struct itimerval T {{Seconds, 0}, {Seconds, 0}}; - if (setitimer(ITIMER_REAL, &T, nullptr)) { - Printf("libFuzzer: setitimer failed with %d\n", errno); - exit(1); +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; + } } - 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); } -void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); } +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); + } + } + if (Opt.sigint_cb) + sigaddset(&Set, SIGINT); + if (Opt.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) + SetSigaction(SIGBUS, [](int,siginfo_t*,void*) {HandlerOpt.sigbus_cb();}); + if (Opt.sigabrt_cb) + SetSigaction(SIGABRT, [](int,siginfo_t*,void*) {HandlerOpt.sigabrt_cb();}); + if (Opt.sigill_cb) + SetSigaction(SIGILL, [](int,siginfo_t*,void*) {HandlerOpt.sigill_cb();}); + if (Opt.sigfpe_cb) + SetSigaction(SIGFPE, [](int,siginfo_t*,void*) {HandlerOpt.sigfpe_cb();}); +} void SleepSeconds(int Seconds) { sleep(Seconds); // Use C API to avoid coverage from instrumented libc++. Index: lib/Fuzzer/FuzzerUtilWindows.cpp =================================================================== --- lib/Fuzzer/FuzzerUtilWindows.cpp +++ lib/Fuzzer/FuzzerUtilWindows.cpp @@ -11,7 +11,7 @@ #include "FuzzerDefs.h" #if LIBFUZZER_WINDOWS -#include "FuzzerInternal.h" +#include "FuzzerUtil.h" #include "FuzzerIO.h" #include #include @@ -27,39 +27,26 @@ namespace fuzzer { -LONG WINAPI SEGVHandler(PEXCEPTION_POINTERS ExceptionInfo) { +static SignalHandlerOptions HandlerOpt; + +LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_STACK_OVERFLOW: - Fuzzer::StaticCrashSignalCallback(); + if (HandlerOpt.sigsegv_cb) + HandlerOpt.sigsegv_cb(); break; - } - return EXCEPTION_CONTINUE_SEARCH; -} - -LONG WINAPI BUSHandler(PEXCEPTION_POINTERS ExceptionInfo) { - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_IN_PAGE_ERROR: - Fuzzer::StaticCrashSignalCallback(); + if (HandlerOpt.sigbus_cb) + HandlerOpt.sigbus_cb(); break; - } - return EXCEPTION_CONTINUE_SEARCH; -} - -LONG WINAPI ILLHandler(PEXCEPTION_POINTERS ExceptionInfo) { - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_ILLEGAL_INSTRUCTION: case EXCEPTION_PRIV_INSTRUCTION: - Fuzzer::StaticCrashSignalCallback(); + if (HandlerOpt.sigill_cb) + HandlerOpt.sigill_cb(); break; - } - return EXCEPTION_CONTINUE_SEARCH; -} - -LONG WINAPI FPEHandler(PEXCEPTION_POINTERS ExceptionInfo) { - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_FLT_DENORMAL_OPERAND: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_INEXACT_RESULT: @@ -69,87 +56,83 @@ case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_INT_DIVIDE_BY_ZERO: case EXCEPTION_INT_OVERFLOW: - Fuzzer::StaticCrashSignalCallback(); + if (HandlerOpt.sigfpe_cb) + HandlerOpt.sigfpe_cb(); break; } return EXCEPTION_CONTINUE_SEARCH; } -BOOL WINAPI INTHandler(DWORD dwCtrlType) { +BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: - Fuzzer::StaticInterruptCallback(); + if (HandlerOpt.sigint_cb) + HandlerOpt.sigint_cb(); return TRUE; - default: - return FALSE; - } -} - -BOOL WINAPI TERMHandler(DWORD dwCtrlType) { - switch (dwCtrlType) { case CTRL_BREAK_EVENT: - Fuzzer::StaticInterruptCallback(); + if (HandlerOpt.sigterm_cb) + HandlerOpt.sigterm_cb(); return TRUE; - default: - return FALSE; - } -} - -void SetTimer(int Seconds) { - // TODO: Complete this implementation. - return; -} - -void SetSigSegvHandler() { - if (!AddVectoredExceptionHandler(1, SEGVHandler)) { - Printf("libFuzzer: AddVectoredExceptionHandler failed.\n"); - exit(1); - } -} - -void SetSigBusHandler() { - if (!AddVectoredExceptionHandler(1, BUSHandler)) { - Printf("libFuzzer: AddVectoredExceptionHandler failed.\n"); - exit(1); - } -} - -static void CrashHandler(int) { - Fuzzer::StaticCrashSignalCallback(); -} - -void SetSigAbrtHandler() { signal(SIGABRT, CrashHandler); } - -void SetSigIllHandler() { - if (!AddVectoredExceptionHandler(1, ILLHandler)) { - Printf("libFuzzer: AddVectoredExceptionHandler failed.\n"); - exit(1); - } -} - -void SetSigFpeHandler() { - if (!AddVectoredExceptionHandler(1, FPEHandler)) { - Printf("libFuzzer: AddVectoredExceptionHandler failed.\n"); - exit(1); - } -} - -void SetSigIntHandler() { - if (!SetConsoleCtrlHandler(INTHandler, TRUE)) { - DWORD LastError = GetLastError(); - Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", - LastError); - exit(1); - } -} - -void SetSigTermHandler() { - if (!SetConsoleCtrlHandler(TERMHandler, TRUE)) { - DWORD LastError = GetLastError(); - Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", - LastError); - exit(1); } + return FALSE; +} + +void CALLBACK AlarmHandler(PVOID, BOOLEAN) { + HandlerOpt.sigalrm_cb(); +} + +class TimerQ { + HANDLE TimerQueue; + public: + TimerQ() : TimerQueue(NULL) {}; + ~TimerQ() { + if (TimerQueue) + DeleteTimerQueueEx(TimerQueue, NULL); + }; + void SetTimer(int Seconds) { + if (!TimerQueue) { + TimerQueue = CreateTimerQueue(); + if (!TimerQueue) { + Printf("libFuzzer: CreateTimerQueue failed.\n"); + exit(1); + } + } + HANDLE Timer; + if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, + Seconds*1000, Seconds*1000, 0)) { + Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); + exit(1); + } + }; +}; + +static TimerQ Timer; + +void SetSignalHandler(const SignalHandlerOptions& Opt) { + HandlerOpt = Opt; + + if (Opt.timeout > 0 && Opt.sigalrm_cb) + Timer.SetTimer(Opt.timeout); + + if (Opt.sigint_cb || Opt.sigterm_cb) + if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { + DWORD LastError = GetLastError(); + Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", + LastError); + exit(1); + } + + if (Opt.sigsegv_cb || Opt.sigbus_cb || Opt.sigill_cb || Opt.sigfpe_cb) + if (!AddVectoredExceptionHandler(1, ExceptionHandler)) { + Printf("libFuzzer: AddVectoredExceptionHandler failed.\n"); + exit(1); + } + + if (Opt.sigabrt_cb) + if (SIG_ERR == signal(SIGABRT, [](int){HandlerOpt.sigabrt_cb();})) { + Printf("libFuzzer: signal failed with %d\n", errno); + exit(1); + } } void SleepSeconds(int Seconds) {