[libFuzzer] add generic signal handlers so that libFuzzer can report at least something if ASan is not handlig the signals for us. Remove abort_on_timeout flag.

llvm-svn: 262415
This commit is contained in:
Kostya Serebryany 2016-03-01 22:19:21 +00:00
parent 9cb02b1f3e
commit d5755334e5
7 changed files with 94 additions and 21 deletions

View File

@ -265,7 +265,6 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
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;
@ -322,6 +321,12 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
// 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);

View File

@ -29,9 +29,10 @@ FUZZER_FLAG_INT(
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.")
@ -76,3 +77,9 @@ FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.")
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.")

View File

@ -83,6 +83,12 @@ void PrintASCII(const Unit &U, const char *PrintAfter = "");
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();
@ -270,8 +276,8 @@ public:
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;
@ -331,6 +337,8 @@ public:
size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
static void StaticAlarmCallback();
static void StaticCrashSignalCallback();
static void StaticInterruptCallback();
void ExecuteCallback(const uint8_t *Data, size_t Size);
@ -341,6 +349,8 @@ public:
private:
void AlarmCallback();
void CrashCallback();
void InterruptCallback();
void MutateAndTestOne();
void ReportNewCoverage(const Unit &U);
bool RunOne(const uint8_t *Data, size_t Size);
@ -372,6 +382,7 @@ private:
void SetDeathCallback();
static void StaticDeathCallback();
void DumpCurrentUnit(const char *Prefix);
void DeathCallback();
uint8_t *CurrentUnitData;

View File

@ -83,15 +83,19 @@ void Fuzzer::StaticDeathCallback() {
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();
}
@ -100,6 +104,35 @@ void Fuzzer::StaticAlarmCallback() {
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)
@ -114,20 +147,13 @@ void Fuzzer::AlarmCallback() {
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);
}
}

View File

@ -71,17 +71,37 @@ 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 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;

View File

@ -11,5 +11,4 @@ RUN: not LLVMFuzzer-TimeoutTest -timeout=1 -test_single_input=%S/hi.txt 2>&1 | F
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

View File

@ -15,6 +15,11 @@ NullDerefTestPrefix: Test unit written to ZZZcrash-
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