OSDN Git Service

[libFuzzer] enhance -rss_limit_mb and enable by default. Now it will print the OOM...
authorKostya Serebryany <kcc@google.com>
Fri, 6 May 2016 23:38:07 +0000 (23:38 +0000)
committerKostya Serebryany <kcc@google.com>
Fri, 6 May 2016 23:38:07 +0000 (23:38 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268821 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LibFuzzer.rst
lib/Fuzzer/FuzzerDriver.cpp
lib/Fuzzer/FuzzerFlags.def
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerLoop.cpp
lib/Fuzzer/FuzzerUtil.cpp
lib/Fuzzer/test/CMakeLists.txt
lib/Fuzzer/test/OutOfMemoryTest.cpp [new file with mode: 0644]
lib/Fuzzer/test/fuzzer-oom.test [new file with mode: 0644]

index d2d02e8..fb6a10d 100644 (file)
@@ -201,6 +201,12 @@ The most important command line options are:
 ``-timeout``
   Timeout in seconds, default 1200. If an input takes longer than this timeout,
   the process is treated as a failure case.
+``-rss_limit_mb``
+  Memory usage limit in Mb, default 2048. Use 0 to disable the limit.
+  If an input requires more than this amount of RSS memory to execute,
+  the process is treated as a failure case.
+  The limit is checked in a separate thread every second.
+  If running w/o ASAN/MSAN, you may use 'ulimit -v' instead.
 ``-timeout_exitcode``
   Exit code (default 77) to emit when terminating due to timeout, when
   ``-abort_on_timeout`` is not set.
index 38e1968..9bd991a 100644 (file)
@@ -189,7 +189,7 @@ static std::mutex Mu;
 
 static void PulseThread() {
   while (true) {
-    std::this_thread::sleep_for(std::chrono::seconds(600));
+    SleepSeconds(600);
     std::lock_guard<std::mutex> Lock(Mu);
     Printf("pulse...\n");
   }
@@ -236,10 +236,10 @@ static int RunInMultipleProcesses(const std::vector<std::string> &Args,
 
 static void RssThread(Fuzzer *F, size_t RssLimitMb) {
   while (true) {
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    SleepSeconds(1);
     size_t Peak = GetPeakRSSMb();
     if (Peak > RssLimitMb)
-      F->RssLimitCallback(Peak, RssLimitMb);
+      F->RssLimitCallback();
   }
 }
 
@@ -310,6 +310,7 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
   Options.OnlyASCII = Flags.only_ascii;
   Options.OutputCSV = Flags.output_csv;
   Options.DetectLeaks = Flags.detect_leaks;
+  Options.RssLimitMb = Flags.rss_limit_mb;
   if (Flags.runs >= 0)
     Options.MaxNumberOfRuns = Flags.runs;
   if (!Inputs->empty())
index 86597cc..1024fa6 100644 (file)
@@ -81,7 +81,7 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
     "Be careful, this will also close e.g. asan's stderr/stdout.")
 FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
     "try to detect memory leaks during fuzzing (i.e. not only at shut down).")
-FUZZER_FLAG_INT(rss_limit_mb, 0, "If non-zero, the fuzzer will exit upon"
+FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
     "reaching this limit of RSS memory usage.")
 
 FUZZER_DEPRECATED_FLAG(exit_on_first)
index 75f058b..9b99767 100644 (file)
@@ -109,6 +109,8 @@ bool IsASCII(const Unit &U);
 
 int NumberOfCpuCores();
 int GetPid();
+int SignalToMainThread();
+void SleepSeconds(int Seconds);
 
 // Clears the current PC Map.
 void PcMapResetCurrent();
@@ -283,6 +285,7 @@ public:
     int TimeoutExitCode = 77;
     int ErrorExitCode = 77;
     int MaxTotalTimeSec = 0;
+    int RssLimitMb = 0;
     bool DoCrossOver = true;
     int MutateDepth = 5;
     bool UseCounters = false;
@@ -353,7 +356,7 @@ public:
   MutationDispatcher &GetMD() { return MD; }
   void PrintFinalStats();
   void SetMaxLen(size_t MaxLen);
-  void RssLimitCallback(size_t RssPeakMb, size_t RssLimitMb);
+  void RssLimitCallback();
 
 private:
   void AlarmCallback();
@@ -397,6 +400,7 @@ private:
 
   uint8_t *CurrentUnitData = nullptr;
   size_t CurrentUnitSize = 0;
+  bool InOOMState = false;
 
   size_t TotalNumberOfRuns = 0;
   size_t NumberOfNewUnitsAdded = 0;
index e02ebcf..6a7fe7d 100644 (file)
@@ -153,6 +153,20 @@ void Fuzzer::InterruptCallback() {
 NO_SANITIZE_MEMORY
 void Fuzzer::AlarmCallback() {
   assert(Options.UnitTimeoutSec > 0);
+  if (InOOMState) {
+    Printf("==%d== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
+           GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
+    Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n");
+    if (CurrentUnitSize && CurrentUnitData) {
+      DumpCurrentUnit("oom-");
+      if (__sanitizer_print_stack_trace)
+        __sanitizer_print_stack_trace();
+    }
+    Printf("SUMMARY: libFuzzer: out-of-memory\n");
+    PrintFinalStats();
+    _Exit(Options.ErrorExitCode); // Stop right now.
+  }
+
   if (!CurrentUnitSize)
     return; // We have not started running units yet.
   size_t Seconds =
@@ -176,15 +190,13 @@ void Fuzzer::AlarmCallback() {
   }
 }
 
-void Fuzzer::RssLimitCallback(size_t RssPeakMb, size_t RssLimitMb) {
-  Printf("==%d== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
-         GetPid(), RssPeakMb, RssLimitMb);
-  Printf("*****************************************************************\n");
-  Printf("** Experimental! TODO: dump the stack trace and the reproducer **\n");
-  Printf("*****************************************************************\n");
-  Printf("SUMMARY: libFuzzer: out-of-memory\n");
-  PrintFinalStats();
-  _Exit(Options.ErrorExitCode); // Stop right now.
+void Fuzzer::RssLimitCallback() {
+  InOOMState = true;
+  SignalToMainThread();
+  SleepSeconds(5);
+  Printf("Signal to main thread failed (non-linux?). Exiting.\n");
+  _Exit(Options.ErrorExitCode);
+  return;
 }
 
 void Fuzzer::PrintStats(const char *Where, const char *End) {
index d533561..88b18d7 100644 (file)
 #include <iomanip>
 #include <sys/resource.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
 #include <cassert>
+#include <chrono>
 #include <cstring>
 #include <signal.h>
 #include <sstream>
 #include <unistd.h>
 #include <errno.h>
+#include <thread>
 
 namespace fuzzer {
 
@@ -214,8 +218,18 @@ bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
   return true;
 }
 
-int GetPid() { return getpid(); }
+void SleepSeconds(int Seconds) {
+  std::this_thread::sleep_for(std::chrono::seconds(Seconds));
+}
 
+int GetPid() { return getpid(); }
+int SignalToMainThread() {
+#ifdef __linux__
+  return syscall(SYS_tgkill, GetPid(), GetPid(), SIGALRM);
+#else
+  return 0;
+#endif
+}
 
 std::string Base64(const Unit &U) {
   static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
index ff1a734..81a9969 100644 (file)
@@ -26,6 +26,7 @@ set(Tests
   LeakTimeoutTest
   NullDerefTest
   NthRunCrashTest
+  OutOfMemoryTest
   RepeatedMemcmp
   SimpleCmpTest
   SimpleDictionaryTest
diff --git a/lib/Fuzzer/test/OutOfMemoryTest.cpp b/lib/Fuzzer/test/OutOfMemoryTest.cpp
new file mode 100644 (file)
index 0000000..e5c9f0a
--- /dev/null
@@ -0,0 +1,31 @@
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// Tests OOM handling.
+#include <assert.h>
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <cstring>
+#include <iostream>
+#include <unistd.h>
+
+static volatile char *SinkPtr;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  if (Size > 0 && Data[0] == 'H') {
+    if (Size > 1 && Data[1] == 'i') {
+      if (Size > 2 && Data[2] == '!') {
+        while (true) {
+          size_t kSize = 1 << 28;
+          char *p = new char[kSize];
+          memset(p, 0, kSize);
+          SinkPtr = p;
+          sleep(1);
+        }
+      }
+    }
+  }
+  return 0;
+}
+
diff --git a/lib/Fuzzer/test/fuzzer-oom.test b/lib/Fuzzer/test/fuzzer-oom.test
new file mode 100644 (file)
index 0000000..4cdff21
--- /dev/null
@@ -0,0 +1,4 @@
+RUN: not LLVMFuzzer-OutOfMemoryTest -rss_limit_mb=10 2>&1 | FileCheck %s
+CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 10Mb)
+CHECK: Test unit written to ./oom-
+SUMMARY: libFuzzer: out-of-memory