[libFuzzer] Fix minimizing timeouts

When one tries to minimize timeouts using -minimize_crash=1,
minimization immediately fails. The following sequence of events is
responsible for this:

[parent] SIGALRM occurs
[parent] read() returns -EINTR (or -ERESTARTSYS according to strace)
[parent] fgets() returns NULL
[parent] ExecuteCommand() closes child's stdout and returns
[child ] SIGALRM occurs
[child ] AlarmCallback() attempts to write "ALARM: ..." to stdout
[child ] Dies with SIGPIPE without calling DumpCurrentUnit()
[parent] Does not see -exact_artifact_path and exits

When minimizing, the timer in parent is not necessary, so fix by not
setting it in this case.

Reviewed By: morehouse

Differential Revision: https://reviews.llvm.org/D85359
This commit is contained in:
Ilya Leoshkevich 2020-08-11 22:16:08 +02:00
parent 06d567059e
commit 9df7ee34e1
6 changed files with 11 additions and 3 deletions

View File

@ -767,6 +767,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
#endif // LIBFUZZER_EMSCRIPTEN #endif // LIBFUZZER_EMSCRIPTEN
Options.HandleAbrt = Flags.handle_abrt; Options.HandleAbrt = Flags.handle_abrt;
Options.HandleAlrm = !Flags.minimize_crash;
Options.HandleBus = Flags.handle_bus; Options.HandleBus = Flags.handle_bus;
Options.HandleFpe = Flags.handle_fpe; Options.HandleFpe = Flags.handle_fpe;
Options.HandleIll = Flags.handle_ill; Options.HandleIll = Flags.handle_ill;

View File

@ -69,6 +69,7 @@ struct FuzzingOptions {
int PurgeAllocatorIntervalSec = 1; int PurgeAllocatorIntervalSec = 1;
int TraceMalloc = 0; int TraceMalloc = 0;
bool HandleAbrt = false; bool HandleAbrt = false;
bool HandleAlrm = false;
bool HandleBus = false; bool HandleBus = false;
bool HandleFpe = false; bool HandleFpe = false;
bool HandleIll = false; bool HandleIll = false;

View File

@ -354,7 +354,7 @@ void SetSignalHandler(const FuzzingOptions &Options) {
Printf("%s", Buf); Printf("%s", Buf);
// Set up alarm handler if needed. // Set up alarm handler if needed.
if (Options.UnitTimeoutSec > 0) { if (Options.HandleAlrm && Options.UnitTimeoutSec > 0) {
std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
T.detach(); T.detach();
} }

View File

@ -113,7 +113,7 @@ void SetTimer(int Seconds) {
void SetSignalHandler(const FuzzingOptions& Options) { void SetSignalHandler(const FuzzingOptions& Options) {
// setitimer is not implemented in emscripten. // setitimer is not implemented in emscripten.
if (Options.UnitTimeoutSec > 0 && !LIBFUZZER_EMSCRIPTEN) if (Options.HandleAlrm && Options.UnitTimeoutSec > 0 && !LIBFUZZER_EMSCRIPTEN)
SetTimer(Options.UnitTimeoutSec / 2 + 1); SetTimer(Options.UnitTimeoutSec / 2 + 1);
if (Options.HandleInt) if (Options.HandleInt)
SetSigaction(SIGINT, InterruptHandler); SetSigaction(SIGINT, InterruptHandler);

View File

@ -115,7 +115,7 @@ static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
void SetSignalHandler(const FuzzingOptions& Options) { void SetSignalHandler(const FuzzingOptions& Options) {
HandlerOpt = &Options; HandlerOpt = &Options;
if (Options.UnitTimeoutSec > 0) if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
if (Options.HandleInt || Options.HandleTerm) if (Options.HandleInt || Options.HandleTerm)

View File

@ -0,0 +1,6 @@
RUN: %cpp_compiler %S/TimeoutTest.cpp -o %t-TimeoutTest
RUN: mkdir -p %t.dir
RUN: echo 'Hi!?' > %t.dir/not_minimal_timeout
RUN: %run %t-TimeoutTest -minimize_crash=1 %t.dir/not_minimal_timeout -timeout=1 -max_total_time=3 2>&1 | FileCheck %s
CHECK: CRASH_MIN: failed to minimize beyond {{.*}}minimized-from{{.*}} (3 bytes), exiting