[libFuzzer] make sure we find buffer overflow in the input buffer. Previously, re-using the same vector object was hiding buffer overflows (unless we used annotated vector)

llvm-svn: 257701
diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h
index c1e9daa..3ab43d2 100644
--- a/llvm/lib/Fuzzer/FuzzerInternal.h
+++ b/llvm/lib/Fuzzer/FuzzerInternal.h
@@ -106,6 +106,7 @@
   void Drill();
   void ShuffleAndMinimize();
   void InitializeTraceState();
+  void AssignTaintLabels(uint8_t *Data, size_t Size);
   size_t CorpusSize() const { return Corpus.size(); }
   void ReadDir(const std::string &Path, long *Epoch) {
     Printf("Loading corpus: %s\n", Path.c_str());
diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp
index 5237682..ccc05c8 100644
--- a/llvm/lib/Fuzzer/FuzzerLoop.cpp
+++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp
@@ -11,6 +11,8 @@
 
 #include "FuzzerInternal.h"
 #include <algorithm>
+#include <cstring>
+#include <memory>
 
 #if defined(__has_include)
 # if __has_include(<sanitizer/coverage_interface.h>)
@@ -240,11 +242,12 @@
 }
 
 void Fuzzer::ExecuteCallback(const Unit &U) {
-  const uint8_t *Data = U.data();
-  uint8_t EmptyData;
-  if (!Data) 
-    Data = &EmptyData;
-  int Res = USF.TargetFunction(Data, U.size());
+  // We copy the contents of Unit into a separate heap buffer
+  // so that we reliably find buffer overflows in it.
+  std::unique_ptr<uint8_t[]> Data(new uint8_t[U.size()]);
+  memcpy(Data.get(), U.data(), U.size());
+  AssignTaintLabels(Data.get(), U.size());
+  int Res = USF.TargetFunction(Data.get(), U.size());
   (void)Res;
   assert(Res == 0);
 }
diff --git a/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/llvm/lib/Fuzzer/FuzzerTraceState.cpp
index b2006fa..10eab01 100644
--- a/llvm/lib/Fuzzer/FuzzerTraceState.cpp
+++ b/llvm/lib/Fuzzer/FuzzerTraceState.cpp
@@ -451,9 +451,6 @@
 
 void Fuzzer::StartTraceRecording() {
   if (!TS) return;
-  if (ReallyHaveDFSan())
-    for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++)
-      dfsan_set_label(i + 1, &CurrentUnit[i], 1);
   TS->StartTraceRecording();
 }
 
@@ -462,18 +459,24 @@
   TS->StopTraceRecording();
 }
 
+void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) {
+  if (!Options.UseTraces) return;
+  if (!ReallyHaveDFSan()) return;
+  for (size_t i = 0; i < Size; i++)
+    dfsan_set_label(i + 1, &Data[i], 1);
+}
+
 void Fuzzer::InitializeTraceState() {
   if (!Options.UseTraces) return;
   TS = new TraceState(USF, Options, CurrentUnit);
-  CurrentUnit.resize(Options.MaxLen);
-  // The rest really requires DFSan.
-  if (!ReallyHaveDFSan()) return;
-  for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
-    dfsan_label L = dfsan_create_label("input", (void*)(i + 1));
-    // We assume that no one else has called dfsan_create_label before.
-    if (L != i + 1) {
-      Printf("DFSan labels are not starting from 1, exiting\n");
-      exit(1);
+  if (ReallyHaveDFSan()) {
+    for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
+      dfsan_label L = dfsan_create_label("input", (void *)(i + 1));
+      // We assume that no one else has called dfsan_create_label before.
+      if (L != i + 1) {
+        Printf("DFSan labels are not starting from 1, exiting\n");
+        exit(1);
+      }
     }
   }
 }
diff --git a/llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp b/llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp
new file mode 100644
index 0000000..9bebd84
--- /dev/null
+++ b/llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp
@@ -0,0 +1,20 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <assert.h>
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile bool SeedLargeBuffer;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  assert(Data);
+  if (Size >= 4)
+    SeedLargeBuffer = true;
+  if (Size == 3 && SeedLargeBuffer && Data[3]) {
+    std::cout << "Woops, reading Data[3] w/o crashing\n";
+    exit(1);
+  }
+  return 0;
+}
+
diff --git a/llvm/lib/Fuzzer/test/CMakeLists.txt b/llvm/lib/Fuzzer/test/CMakeLists.txt
index cd0b167..2d526bd 100644
--- a/llvm/lib/Fuzzer/test/CMakeLists.txt
+++ b/llvm/lib/Fuzzer/test/CMakeLists.txt
@@ -13,6 +13,7 @@
   )
 
 set(Tests
+  BufferOverflowOnInput
   CallerCalleeTest
   CounterTest
   FourIndependentBranchesTest
diff --git a/llvm/lib/Fuzzer/test/fuzzer.test b/llvm/lib/Fuzzer/test/fuzzer.test
index c63014f..5b98fde 100644
--- a/llvm/lib/Fuzzer/test/fuzzer.test
+++ b/llvm/lib/Fuzzer/test/fuzzer.test
@@ -34,3 +34,6 @@
 PCS:NEW
 PCS:BINGO
 
+RUN: not LLVMFuzzer-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB
+OOB: AddressSanitizer: heap-buffer-overflow
+OOB: is located 0 bytes to the right of 3-byte region