[libFuzzer] Fix bug in detecting timeouts when input string is empty.
authorMarcos Pividori <mpividori@google.com>
Tue, 13 Dec 2016 17:46:25 +0000 (17:46 +0000)
committerMarcos Pividori <mpividori@google.com>
Tue, 13 Dec 2016 17:46:25 +0000 (17:46 +0000)
I added a new flag RunningCB to know if the Fuzzer's main thread is
running the CB function, instead of using (!CurrentUnitSize).
(!CurrentUnitSize) doesn't work properly. For example, in FuzzerLoop.cpp,
inside ShuffleAndMinimize() function, we execute the callback with an
empty string (size=0). Previous implementation failed to detect timeouts
in that execution.
Also, I add a regression test for that case.

Differential Revision: https://reviews.llvm.org/D27433

llvm-svn: 289561

llvm/lib/Fuzzer/FuzzerInternal.h
llvm/lib/Fuzzer/FuzzerLoop.cpp
llvm/lib/Fuzzer/test/CMakeLists.txt
llvm/lib/Fuzzer/test/TimeoutEmptyTest.cpp [new file with mode: 0644]
llvm/lib/Fuzzer/test/fuzzer-timeout.test

index f1e7415..c041706 100644 (file)
@@ -147,6 +147,7 @@ private:
   uint8_t *CurrentUnitData = nullptr;
   std::atomic<size_t> CurrentUnitSize;
   uint8_t BaseSha1[kSHA1NumBytes];  // Checksum of the base unit.
+  bool RunningCB = false;
 
   size_t TotalNumberOfRuns = 0;
   size_t NumberOfNewUnitsAdded = 0;
index 93db617..f161cc7 100644 (file)
@@ -286,7 +286,7 @@ NO_SANITIZE_MEMORY
 void Fuzzer::AlarmCallback() {
   assert(Options.UnitTimeoutSec > 0);
   if (!InFuzzingThread()) return;
-  if (!CurrentUnitSize)
+  if (!RunningCB)
     return; // We have not started running units yet.
   size_t Seconds =
       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
@@ -532,7 +532,9 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
   UnitStartTime = system_clock::now();
   ResetCounters();  // Reset coverage right before the callback.
   TPC.ResetMaps();
+  RunningCB = true;
   int Res = CB(DataCopy, Size);
+  RunningCB = false;
   UnitStopTime = system_clock::now();
   (void)Res;
   assert(Res == 0);
index 27774b5..65199e9 100644 (file)
@@ -109,6 +109,7 @@ set(Tests
   ThreadedLeakTest
   ThreadedTest
   TimeoutTest
+  TimeoutEmptyTest
   TraceMallocTest
   )
 
diff --git a/llvm/lib/Fuzzer/test/TimeoutEmptyTest.cpp b/llvm/lib/Fuzzer/test/TimeoutEmptyTest.cpp
new file mode 100644 (file)
index 0000000..8066f48
--- /dev/null
@@ -0,0 +1,14 @@
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// Simple test for a fuzzer. The fuzzer must find the empty string.
+#include <cstdint>
+#include <cstddef>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  static volatile int Zero = 0;
+  if (!Size)
+    while(!Zero)
+      ;
+  return 0;
+}
index 8e8b713..beb0867 100644 (file)
@@ -12,3 +12,8 @@ SingleInputTimeoutTest: ALARM: working on the last Unit for {{[1-3]}} seconds
 SingleInputTimeoutTest-NOT: Test unit written to ./timeout-
 
 RUN: LLVMFuzzer-TimeoutTest -timeout=1 -timeout_exitcode=0
+
+RUN: not LLVMFuzzer-TimeoutEmptyTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutEmptyTest
+TimeoutEmptyTest: ALARM: working on the last Unit for
+TimeoutEmptyTest: == ERROR: libFuzzer: timeout after
+TimeoutEmptyTest: SUMMARY: libFuzzer: timeout