honggfuzz icon indicating copy to clipboard operation
honggfuzz copied to clipboard

--timeout times out during LLVMFuzzerInitialize

Open maflcko opened this issue 5 years ago • 1 comments

LLVMFuzzerInitialize can be used to initialize deterministic, but expensive global state, which is later used by the target read-only.

However, --timeout starts counting inside the init function, thus killing the process before any actual fuzzing can be made. I think the solution would be to only start counting in LLVMFuzzerTestOneInput.

Steps to reproduce:

$ cat test.cpp 
#include <cassert>
#include <chrono>
#include <iostream>
#include <thread>

bool g_init{};

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
  assert(g_init);
  assert(len < 1); // A crash
  return 0;
}

extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
  using namespace std::chrono_literals;
  std::cout << "Init expensive global state...\n";
  std::this_thread::sleep_for(1.5s);
  g_init = true;
  std::cout << "Done\n";
  return 0;
}
$ hfuzz-clang test.cpp -lstdc++ -o test.exe && honggfuzz --verbose -iterations=10 --run_time=2 --threads=1 --timeout=1 -i /tmp/a_init/ -- test.exe 
Persistent signature found in 'test.exe'. Enabling persistent fuzzing mode
Start time:'2021-02-15.17.53.26' bin:'test.exe', input:'/tmp/a_init/', output:'/tmp/a_init/', persistent:true, stdin:false, mutation_rate:5, timeout:1, max_runs:0, threads:1, minimize:false, git_commit:ebc191e0525d5944f16d860aad49288b1bf6e448
Entering phase 1/3: Dry Run
Launched new fuzzing thread, no. #0
Persistent mode: Launched new persistent pid=1106642
[2021-02-15T17:53:27+0100][W][1106640] subproc_checkTimeLimit():529 pid=1106642 took too much time (limit 1 s). Killing it with SIGKILL
[2021-02-15T17:53:27+0100][W][1106640] arch_checkWait():232 Persistent mode: pid=1106642 exited with status: SIGNALED, signal: 9 (Killed)
Sz:4 Tm:1,001,219us (i/b/h/e/p/c) New:0/0/0/24/0/8, Cur:0/0/0/24/0/10
Persistent mode: Launched new persistent pid=1106643
[2021-02-15T17:53:28+0100][W][1106640] subproc_checkTimeLimit():529 pid=1106643 took too much time (limit 1 s). Killing it with SIGKILL
[2021-02-15T17:53:28+0100][W][1106640] arch_checkWait():232 Persistent mode: pid=1106643 exited with status: SIGNALED, signal: 9 (Killed)
Sz:8 Tm:1,099,895us (i/b/h/e/p/c) New:0/0/0/0/0/25, Cur:0/0/0/0/0/34
Persistent mode: Launched new persistent pid=1106644
Maximum run time reached, terminating
Sz:16 Tm:299,683us (i/b/h/e/p/c) New:0/0/0/0/0/23, Cur:0/0/0/0/0/34
Terminating thread no. #0, left: 0
Summary iterations:3 time:3 speed:1 crashes_count:0 timeout_count:2 new_units_added:0 slowest_unit_ms:1099 guard_nb:36 branch_coverage_percent:66 peak_rss_mb:4

maflcko avatar Feb 15 '21 16:02 maflcko

Yes, this is known, but as you pointed out, the user code can hang in initializers, in LLVMFuzzerInitialize() and, in case it's not a persistent binary, but the one using HF_ITER in its main().

I'll think about it, because it's doable, but in case I add it, I'll probably have to have 2 timeouts, one for initialization, and one for LLVMFuzzerInitialize()

robertswiecki avatar Feb 17 '21 14:02 robertswiecki