OSDN Git Service

[llvm-opt-fuzzer] Avoid adding incorrect inputs to the fuzzer corpus
authorIgor Laevsky <igmyrj@gmail.com>
Mon, 5 Feb 2018 11:05:47 +0000 (11:05 +0000)
committerIgor Laevsky <igmyrj@gmail.com>
Mon, 5 Feb 2018 11:05:47 +0000 (11:05 +0000)
Differential Revision: https://reviews.llvm.org/D42414

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

include/llvm/FuzzMutate/FuzzerCLI.h
lib/FuzzMutate/FuzzerCLI.cpp
tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp

index a775fdf..3333e96 100644 (file)
@@ -68,6 +68,12 @@ std::unique_ptr<Module> parseModule(const uint8_t *Data, size_t Size,
 ///         returns 0 and leaves Dest unchanged.
 size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize);
 
+/// Try to parse module and verify it. May output verification errors to the
+/// errs().
+/// \return New module or nullptr in case of error.
+std::unique_ptr<Module> parseAndVerify(const uint8_t *Data, size_t Size,
+                                       LLVMContext &Context);
+
 } // end llvm namespace
 
 #endif // LLVM_FUZZMUTATE_FUZZER_CLI_H
index 2d8973d..43698c6 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/Verifier.h"
 
 using namespace llvm;
 
@@ -175,3 +176,12 @@ size_t llvm::writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) {
   memcpy(Dest, Buf.data(), Buf.size());
   return Buf.size();
 }
+
+std::unique_ptr<Module> llvm::parseAndVerify(const uint8_t *Data, size_t Size,
+                                             LLVMContext &Context) {
+  auto M = parseModule(Data, Size, Context);
+  if (!M || verifyModule(*M, &errs()))
+    return nullptr;
+  
+  return M;
+}
index 764134d..73d6015 100644 (file)
@@ -84,8 +84,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
     return 0;
 
   LLVMContext Context;
-  auto M = parseModule(Data, Size, Context);
-  if (!M || verifyModule(*M, &errs())) {
+  auto M = parseAndVerify(Data, Size, Context);
+  if (!M) {
     errs() << "error: input module is broken!\n";
     return 0;
   }
index 8187bbc..39909ec 100644 (file)
@@ -57,23 +57,45 @@ extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator(
       "IR mutator should have been created during fuzzer initialization");
 
   LLVMContext Context;
-  auto M = parseModule(Data, Size, Context);
-  if (!M || verifyModule(*M, &errs())) {
+  auto M = parseAndVerify(Data, Size, Context);
+  if (!M) {
     errs() << "error: mutator input module is broken!\n";
     return 0;
   }
 
   Mutator->mutateModule(*M, Seed, Size, MaxSize);
 
-#ifndef NDEBUG
   if (verifyModule(*M, &errs())) {
     errs() << "mutation result doesn't pass verification\n";
     M->dump();
-    abort();
+    // Avoid adding incorrect test cases to the corpus.
+    return 0;
+  }
+  
+  std::string Buf;
+  {
+    raw_string_ostream OS(Buf);
+    WriteBitcodeToFile(M.get(), OS);
+  }
+  if (Buf.size() > MaxSize)
+    return 0;
+  
+  // There are some invariants which are not checked by the verifier in favor
+  // of having them checked by the parser. They may be considered as bugs in the
+  // verifier and should be fixed there. However until all of those are covered
+  // we want to check for them explicitly. Otherwise we will add incorrect input
+  // to the corpus and this is going to confuse the fuzzer which will start 
+  // exploration of the bitcode reader error handling code.
+  auto NewM = parseAndVerify(
+      reinterpret_cast<const uint8_t*>(Buf.data()), Buf.size(), Context);
+  if (!NewM) {
+    errs() << "mutator failed to re-read the module\n";
+    M->dump();
+    return 0;
   }
-#endif
 
-  return writeModule(*M, Data, MaxSize);
+  memcpy(Data, Buf.data(), Buf.size());
+  return Buf.size();
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
@@ -87,8 +109,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   //
 
   LLVMContext Context;
-  auto M = parseModule(Data, Size, Context);
-  if (!M || verifyModule(*M, &errs())) {
+  auto M = parseAndVerify(Data, Size, Context);
+  if (!M) {
     errs() << "error: input module is broken!\n";
     return 0;
   }