]> granicus.if.org Git - llvm/commitdiff
Generate error reports when a fuzz target exits.
authorMatt Morehouse <mascasa@google.com>
Thu, 20 Jul 2017 20:43:39 +0000 (20:43 +0000)
committerMatt Morehouse <mascasa@google.com>
Thu, 20 Jul 2017 20:43:39 +0000 (20:43 +0000)
Summary:
Implements https://github.com/google/sanitizers/issues/835.

Flush stdout before exiting in test cases.

Since the atexit hook is used for exit reports, pending prints to
stdout can be lost if they aren't flushed before calling exit().

Expect tests to have non-zero exit code if exit() is called.

Reviewers: vitalybuka, kcc

Reviewed By: kcc

Subscribers: eraman, llvm-commits, hiraditya

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@308669 91177308-0d34-0410-b5e6-96231b3b80d8

21 files changed:
lib/Fuzzer/FuzzerDriver.cpp
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerLoop.cpp
lib/Fuzzer/test/AbsNegAndConstant64Test.cpp
lib/Fuzzer/test/AbsNegAndConstantTest.cpp
lib/Fuzzer/test/BufferOverflowOnInput.cpp
lib/Fuzzer/test/CustomCrossOverTest.cpp
lib/Fuzzer/test/CustomMutatorTest.cpp
lib/Fuzzer/test/NthRunCrashTest.cpp
lib/Fuzzer/test/RepeatedBytesTest.cpp
lib/Fuzzer/test/SimpleDictionaryTest.cpp
lib/Fuzzer/test/SimpleTest.cpp
lib/Fuzzer/test/SimpleThreadedTest.cpp
lib/Fuzzer/test/exit-report.test [new file with mode: 0644]
lib/Fuzzer/test/fuzzer-flags.test
lib/Fuzzer/test/fuzzer-printcovpcs.test
lib/Fuzzer/test/fuzzer.test
lib/Fuzzer/test/inline-8bit-counters.test
lib/Fuzzer/test/repeated-bytes.test
lib/Fuzzer/test/trace-pc.test
lib/Fuzzer/test/ulimit.test

index fd8cab38a7bb40b36fa53c567107052fe9771a30..36d9422bc2846defc67649fea8b7cd12eac08a5e 100644 (file)
@@ -20,6 +20,7 @@
 #include <algorithm>
 #include <atomic>
 #include <chrono>
+#include <cstdlib>
 #include <cstring>
 #include <mutex>
 #include <string>
@@ -642,6 +643,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
   Options.HandleXfsz = Flags.handle_xfsz;
   SetSignalHandler(Options);
 
+  std::atexit(Fuzzer::StaticExitCallback);
+
   if (Flags.minimize_crash)
     return MinimizeCrashInput(Args, Options);
 
index 3fc3fe004cef92bce95c8185bf6a7e25570b1609..8602818a420bad577b0694f6164f39428777aee3 100644 (file)
@@ -60,6 +60,7 @@ public:
 
   static void StaticAlarmCallback();
   static void StaticCrashSignalCallback();
+  static void StaticExitCallback();
   static void StaticInterruptCallback();
   static void StaticFileSizeExceedCallback();
 
@@ -91,6 +92,7 @@ public:
 private:
   void AlarmCallback();
   void CrashCallback();
+  void ExitCallback();
   void CrashOnOverwrittenData();
   void InterruptCallback();
   void MutateAndTestOne();
index ba4ba80db00726c92b2e328df2505e61d707760d..b9e70b6daddf8f62a3df246199b38baaa19bb969 100644 (file)
@@ -175,6 +175,11 @@ void Fuzzer::StaticCrashSignalCallback() {
   F->CrashCallback();
 }
 
+void Fuzzer::StaticExitCallback() {
+  assert(F);
+  F->ExitCallback();
+}
+
 void Fuzzer::StaticInterruptCallback() {
   assert(F);
   F->InterruptCallback();
@@ -198,6 +203,19 @@ void Fuzzer::CrashCallback() {
   _Exit(Options.ErrorExitCode);  // Stop right now.
 }
 
+void Fuzzer::ExitCallback() {
+  if (!RunningCB)
+    return; // This exit did not come from the user callback
+  Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
+  if (EF->__sanitizer_print_stack_trace)
+    EF->__sanitizer_print_stack_trace();
+  Printf("SUMMARY: libFuzzer: fuzz target exited\n");
+  DumpCurrentUnit("crash-");
+  PrintFinalStats();
+  _Exit(Options.ErrorExitCode);
+}
+
+
 void Fuzzer::InterruptCallback() {
   Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
   PrintFinalStats();
index dfb6007b7970d9f8adf169d7b2635c642c39000c..abeb784e9a1162c8783a3ed2fb3d942f2a485c16 100644 (file)
@@ -16,6 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   memcpy(&y, Data + sizeof(x), sizeof(y));
   if (llabs(x) < 0 && y == 0xbaddcafedeadbeefULL) {
     printf("BINGO; Found the target, exiting; x = 0x%lx y 0x%lx\n", x, y);
+    fflush(stdout);
     exit(1);
   }
   return 0;
index e9d983ff1ebfe16cc9c3c834e6836bbd6921bf87..049db0a60c3d57336efd7a92aa382a139d2ecd86 100644 (file)
@@ -16,6 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   memcpy(&y, Data + sizeof(x), sizeof(y));
   if (abs(x) < 0 && y == 0xbaddcafe) {
     printf("BINGO; Found the target, exiting; x = 0x%x y 0x%x\n", x, y);
+    fflush(stdout);
     exit(1);
   }
   return 0;
index 75e1fb90a19a87bbffbc528e1664b94076406c57..159da92d4e991ab281d113eaa469dadb764868cc 100644 (file)
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <cstdlib>
 #include <iostream>
+#include <ostream>
 
 static volatile bool SeedLargeBuffer;
 
@@ -15,7 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   if (Size >= 4)
     SeedLargeBuffer = true;
   if (Size == 3 && SeedLargeBuffer && Data[3]) {
-    std::cout << "Woops, reading Data[3] w/o crashing\n";
+    std::cout << "Woops, reading Data[3] w/o crashing\n" << std::flush;
     exit(1);
   }
   return 0;
index b624088b9020af11cd95190bea67eef408f29c9e..58059c9c1ebc8edbcf2aeafa662622190af8b742 100644 (file)
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <cstdlib>
 #include <iostream>
+#include <ostream>
 #include <random>
 #include <string.h>
 
@@ -26,7 +27,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   if (Size && Data[0] == 'a') sink--;
 
   if (Str.find(Target) != std::string::npos) {
-    std::cout << "BINGO; Found the target, exiting\n";
+    std::cout << "BINGO; Found the target, exiting\n" << std::flush;
     exit(1);
   }
   return 0;
index 521d7f506b4d3c53987e4470fb368462df342662..b2adb94082daef3eea35a70cfb12a82e0fdbd5c3 100644 (file)
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <cstdlib>
 #include <iostream>
+#include <ostream>
 
 #include "FuzzerInterface.h"
 
@@ -19,7 +20,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
     if (Size > 1 && Data[1] == 'i') {
       Sink = 2;
       if (Size > 2 && Data[2] == '!') {
-        std::cout << "BINGO; Found the target, exiting\n";
+        std::cout << "BINGO; Found the target, exiting\n" << std::flush;
         exit(1);
       }
     }
index da5fbd33e9626e236fa36505eb40270763e5b128..26cdc8f17adf348b754be83b90ddc162e3be984c 100644 (file)
@@ -5,12 +5,13 @@
 #include <cstddef>
 #include <cstdint>
 #include <iostream>
+#include <ostream>
 
 static int Counter;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   if (Counter++ == 1000) {
-    std::cout << "BINGO; Found the target, exiting\n";
+    std::cout << "BINGO; Found the target, exiting\n" << std::flush;
     exit(1);
   }
   return 0;
index 14222f2847472e5bd56f6ed3937d51a7409108f4..31868cf8c540ae2f498f152ad127ebbae257e296 100644 (file)
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <cstdlib>
 #include <iostream>
+#include <ostream>
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   assert(Data);
@@ -21,7 +22,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
     MaxA = GT * CurA + (!GT) * MaxA;
   }
   if (MaxA >= 20) {
-    std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n";
+    std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n"
+              << std::flush;
     exit(0);
   }
   return 0;
index a1cd200472249c3a3fb7866550322bad385694a7..ffa2e4137bdeab290e6f8c524c5938cb76c7134a 100644 (file)
@@ -10,6 +10,7 @@
 #include <cstdlib>
 #include <cstring>
 #include <iostream>
+#include <ostream>
 
 static volatile int Zero = 0;
 
@@ -21,7 +22,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
     if (Expected[i] + Zero == Data[i])
       Match++;
   if (Match == strlen(Expected)) {
-    std::cout << "BINGO; Found the target, exiting\n";
+    std::cout << "BINGO; Found the target, exiting\n" << std::flush;
     exit(1);
   }
   return 0;
index a8b4988dff10ec31353b2f89ace9222ed4a9b88d..3882a842b88cce89369e6b989a92029a89525a1e 100644 (file)
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <cstdlib>
 #include <iostream>
+#include <ostream>
 
 static volatile int Sink;
 
@@ -17,7 +18,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
     if (Size > 1 && Data[1] == 'i') {
       Sink = 2;
       if (Size > 2 && Data[2] == '!') {
-        std::cout << "BINGO; Found the target, exiting\n";
+        std::cout << "BINGO; Found the target, exiting\n" << std::flush;
         exit(0);
       }
     }
index 1abdc3fc6d6be3a6d6f4d3a6ce07766acecccc7a..deeae756a8268fe7606bb5548fb317bc06e649d7 100644 (file)
@@ -7,12 +7,13 @@
 #include <cstdint>
 #include <cstring>
 #include <iostream>
+#include <ostream>
 #include <thread>
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   auto C = [&] {
     if (Size >= 2 && Data[0] == 'H') {
-        std::cout << "BINGO; Found the target, exiting\n";
+        std::cout << "BINGO; Found the target, exiting\n" << std::flush;
         abort();
     }
   };
diff --git a/lib/Fuzzer/test/exit-report.test b/lib/Fuzzer/test/exit-report.test
new file mode 100644 (file)
index 0000000..26e8cfc
--- /dev/null
@@ -0,0 +1,5 @@
+RUN: not LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s
+
+CHECK: ERROR: libFuzzer: fuzz target exited
+CHECK: SUMMARY: libFuzzer: fuzz target exited
+CHECK: Test unit written to
index 61ce07797b4995a53d6be19d72250d71a1ee35fe..b9bf2f8e4cc95fddef202114cb0b40b4fd895202 100644 (file)
@@ -1,18 +1,18 @@
-RUN: LLVMFuzzer-FlagsTest -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR
+RUN: not LLVMFuzzer-FlagsTest -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR
 FOO_BAR: WARNING: unrecognized flag '-foo_bar=1'; use -help=1 to list all flags
 FOO_BAR: BINGO
 
-RUN: LLVMFuzzer-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH
+RUN: not LLVMFuzzer-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH
 DASH_DASH: WARNING: did you mean '-max_len=100' (single dash)?
 DASH_DASH: INFO: A corpus is not provided, starting from an empty corpus
 
 RUN: LLVMFuzzer-FlagsTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL
 NO_INTERNAL-NOT: internal flag
 
-RUN: LLVMFuzzer-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU
+RUN: not LLVMFuzzer-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU
 PASSTHRU: BINGO --foo-bar --baz -help=1 test
 
 RUN: mkdir -p %t/T0 %t/T1
 RUN: touch %t/T1/empty
-RUN: LLVMFuzzer-FlagsTest --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE
+RUN: not LLVMFuzzer-FlagsTest --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE
 PASSTHRU-MERGE: BINGO --foo-bar --baz -help=1 test
index e4c6f0ed1df4e2d4214cbec0170bac77c09f7607..77a2e7d147c46db2c9600bcada85b69cb1a1b798 100644 (file)
@@ -1,4 +1,4 @@
-RUN: LLVMFuzzer-SimpleTest -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS
+RUN: not LLVMFuzzer-SimpleTest -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS
 PCS-NOT: NEW_PC
 PCS:INITED
 PCS:NEW_PC: {{0x[a-f0-9]+}}
index ff46d32b387d74e855c87399c34c734bccd98ca3..a3b7d93603fd85f8283283cbb38473af889be5f5 100644 (file)
@@ -1,10 +1,10 @@
 CHECK: BINGO
 Done1000000: Done 1000000 runs in
 
-RUN: LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s
 
 # only_ascii mode. Will perform some minimal self-validation.
-RUN: LLVMFuzzer-SimpleTest -only_ascii=1 2>&1
+RUN: not LLVMFuzzer-SimpleTest -only_ascii=1 2>&1
 
 RUN: LLVMFuzzer-SimpleCmpTest -max_total_time=1 -use_cmp=0 2>&1 | FileCheck %s --check-prefix=MaxTotalTime
 MaxTotalTime: Done {{.*}} runs in {{.}} second(s)
@@ -47,7 +47,7 @@ RUN: not LLVMFuzzer-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO
 DSO: INFO: Loaded 3 modules
 DSO: BINGO
 
-RUN: LLVMFuzzer-SimpleTest  -exit_on_src_pos=SimpleTest.cpp:17                 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
+RUN: LLVMFuzzer-SimpleTest  -exit_on_src_pos=SimpleTest.cpp:18                 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
 RUN: LLVMFuzzer-ShrinkControlFlowTest  -exit_on_src_pos=ShrinkControlFlowTest.cpp:23 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
 EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting.
 
index 8747af81451f3647c580a177d19ad01867b34704..ff84dd119c123be171ca1f74792cd38b8a74f8f3 100644 (file)
@@ -1,4 +1,4 @@
 REQUIRES: linux
 CHECK: INFO: Loaded 1 modules with {{.*}} inline 8-bit counters
 CHECK: BINGO
-RUN: LLVMFuzzer-SimpleTest-Inline8bitCounters -runs=1000000 -seed=1 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SimpleTest-Inline8bitCounters -runs=1000000 -seed=1 2>&1 | FileCheck %s
index 7139408793971d75c8034c37617e2bf657059e1a..fc72142f15de37f7668981144aebc2bd6262ef06 100644 (file)
@@ -1,2 +1,2 @@
 CHECK: BINGO
-RUN: LLVMFuzzer-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s
index 3709677b71b6fff1a0a8ab9b61f51d242ec12d52..93bb2c06154bacfd31076ff90b94b5e113faee44 100644 (file)
@@ -1,2 +1,2 @@
 CHECK: BINGO
-RUN: LLVMFuzzer-SimpleTest-TracePC -runs=100000 -seed=1 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SimpleTest-TracePC -runs=100000 -seed=1 2>&1 | FileCheck %s
index c2faca13f728ae31b6d845388df90b80aa1bcad4..ca4e5ffce15f1f76ba2e96466fc7595bb53ca04a 100644 (file)
@@ -1,4 +1,4 @@
 REQUIRES: posix
 
 RUN: ulimit -s 1000
-RUN: LLVMFuzzer-SimpleTest
+RUN: not LLVMFuzzer-SimpleTest