[llvm] r278839 - [libFuzzer] new experimental feature: value profiling. Profiles values that affect control flow and treats new values as new coverage.

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 16 12:33:52 PDT 2016


Author: kcc
Date: Tue Aug 16 14:33:51 2016
New Revision: 278839

URL: http://llvm.org/viewvc/llvm-project?rev=278839&view=rev
Log:
[libFuzzer] new experimental feature: value profiling. Profiles values that affect control flow and treats new values as new coverage.

Added:
    llvm/trunk/lib/Fuzzer/test/SingleMemcmpTest.cpp
    llvm/trunk/lib/Fuzzer/test/SingleStrcmpTest.cpp
    llvm/trunk/lib/Fuzzer/test/SingleStrncmpTest.cpp
    llvm/trunk/lib/Fuzzer/test/value-profile-cmp.test
    llvm/trunk/lib/Fuzzer/test/value-profile-mem.test
    llvm/trunk/lib/Fuzzer/test/value-profile-set.test
Modified:
    llvm/trunk/lib/Fuzzer/CMakeLists.txt
    llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
    llvm/trunk/lib/Fuzzer/FuzzerFlags.def
    llvm/trunk/lib/Fuzzer/FuzzerInternal.h
    llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
    llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp
    llvm/trunk/lib/Fuzzer/FuzzerValueBitMap.h
    llvm/trunk/lib/Fuzzer/test/CMakeLists.txt
    llvm/trunk/lib/Fuzzer/test/StrncmpTest.cpp

Modified: llvm/trunk/lib/Fuzzer/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/CMakeLists.txt?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/CMakeLists.txt (original)
+++ llvm/trunk/lib/Fuzzer/CMakeLists.txt Tue Aug 16 14:33:51 2016
@@ -1,6 +1,6 @@
 set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS}")
 # Disable the coverage and sanitizer instrumentation for the fuzzer itself.
-set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror")
+set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -mpopcnt -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror")
 if( LLVM_USE_SANITIZE_COVERAGE )
   if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address")
     message(FATAL_ERROR

Modified: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp Tue Aug 16 14:33:51 2016
@@ -339,6 +339,9 @@ int FuzzerDriver(int *argc, char ***argv
   Options.TruncateUnits = Flags.truncate_units;
   Options.PruneCorpus = Flags.prune_corpus;
 
+  if (Flags.use_value_profile)
+    EnableValueProfile();
+
   unsigned Seed = Flags.seed;
   // Initialize Seed.
   if (Seed == 0)

Modified: llvm/trunk/lib/Fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerFlags.def?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerFlags.def (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def Tue Aug 16 14:33:51 2016
@@ -44,6 +44,8 @@ FUZZER_FLAG_INT(use_memcmp, 1,
                 "Use hints from intercepting memcmp, strcmp, etc")
 FUZZER_FLAG_INT(use_memmem, 1,
                 "Use hints from intercepting memmem, strstr, etc")
+FUZZER_FLAG_INT(use_value_profile, 0,
+                "Experimental. Use value profile to guide fuzzing.")
 FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
                           " this number of jobs in separate worker processes"
                           " with stdout/stderr redirected to fuzz-JOB.log.")

Modified: llvm/trunk/lib/Fuzzer/FuzzerInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerInternal.h?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerInternal.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerInternal.h Tue Aug 16 14:33:51 2016
@@ -134,6 +134,10 @@ void SleepSeconds(int Seconds);
 // See FuzzerTracePC.cpp
 size_t PCMapMergeFromCurrent(ValueBitMap &M);
 
+// See FuzzerTraceState.cpp
+void EnableValueProfile();
+size_t VPMapMergeFromCurrent(ValueBitMap &M);
+
 class Random {
  public:
   Random(unsigned int seed) : R(seed) {}
@@ -356,6 +360,8 @@ public:
       CounterBitmap.clear();
       PCMap.Reset();
       PCMapBits = 0;
+      VPMap.Reset();
+      VPMapBits = 0;
       PcBufferPos = 0;
     }
 
@@ -369,6 +375,8 @@ public:
     std::vector<uint8_t> CounterBitmap;
     ValueBitMap PCMap;
     size_t PCMapBits;
+    ValueBitMap VPMap;
+    size_t VPMapBits;
   };
 
   Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options);

Modified: llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp Tue Aug 16 14:33:51 2016
@@ -122,6 +122,12 @@ class CoverageController {
       C->PCMapBits = NewPCMapBits;
     }
 
+    size_t NewVPMapBits = VPMapMergeFromCurrent(C->VPMap);
+    if (NewVPMapBits > C->VPMapBits) {
+      Res = true;
+      C->VPMapBits = NewVPMapBits;
+    }
+
     if (EF->__sanitizer_get_coverage_pc_buffer_pos) {
       uint64_t NewPcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
       if (NewPcBufferPos > C->PcBufferPos) {
@@ -307,6 +313,8 @@ void Fuzzer::PrintStats(const char *Wher
     Printf(" cov: %zd", MaxCoverage.BlockCoverage);
   if (MaxCoverage.PCMapBits)
     Printf(" path: %zd", MaxCoverage.PCMapBits);
+  if (MaxCoverage.VPMapBits)
+    Printf(" vp: %zd", MaxCoverage.VPMapBits);
   if (auto TB = MaxCoverage.CounterBitmapBits)
     Printf(" bits: %zd", TB);
   if (MaxCoverage.CallerCalleeCoverage)
@@ -520,8 +528,9 @@ std::string Fuzzer::Coverage::DebugStrin
       std::string("Coverage{") + "BlockCoverage=" +
       std::to_string(BlockCoverage) + " CallerCalleeCoverage=" +
       std::to_string(CallerCalleeCoverage) + " CounterBitmapBits=" +
-      std::to_string(CounterBitmapBits) + " PcMapBits=" +
-      std::to_string(PCMapBits) + "}";
+      std::to_string(CounterBitmapBits) + " PCMapBits=" +
+      std::to_string(PCMapBits) + " VPMapBits " +
+      std::to_string(VPMapBits) + "}";
   return Result;
 }
 

Modified: llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp Tue Aug 16 14:33:51 2016
@@ -173,6 +173,7 @@ struct TraceBasedMutation {
 static bool RecordingTraces = false;
 static bool RecordingMemcmp = false;
 static bool RecordingMemmem = false;
+static bool RecordingValueProfile = false;
 static bool DoingMyOwnMemmem = false;
 
 struct ScopedDoingMyOwnMemmem {
@@ -529,11 +530,60 @@ static size_t InternalStrnlen(const char
   return Len;
 }
 
+// Value profile.
+// We keep track of various values that affect control flow.
+// These values are inserted into a bit-set-based hash map (ValueBitMap VP).
+// Every new bit in the map is treated as a new coverage.
+//
+// For memcmp/strcmp/etc the interesting value is the length of the common
+// prefix of the parameters.
+// For cmp instructions the interesting value is a XOR of the parameters.
+// The interesting value is mixed up with the PC and is then added to the map.
+static ValueBitMap VP;
+
+void EnableValueProfile() { RecordingValueProfile = true; }
+
+size_t VPMapMergeFromCurrent(ValueBitMap &M) {
+  if (!RecordingValueProfile) return 0;
+  return M.MergeFrom(VP);
+}
+
+static void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+                              size_t n) {
+  if (!n) return;
+  size_t Len = std::min(n, (size_t)32);
+  const char *A1 = reinterpret_cast<const char *>(s1);
+  const char *A2 = reinterpret_cast<const char *>(s2);
+  size_t LastSameByte = 0;
+  for (; LastSameByte < Len; LastSameByte++)
+    if (A1[LastSameByte] != A2[LastSameByte])
+      break;
+  size_t PC = reinterpret_cast<size_t>(caller_pc);
+  VP.AddValue((PC & 4095) | (LastSameByte << 12));
+}
+
+static void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
+                              size_t n) {
+  if (!n) return;
+  size_t Len = std::min(n, (size_t)32);
+  size_t LastSameByte = 0;
+  for (; LastSameByte < Len; LastSameByte++)
+    if (s1[LastSameByte] != s2[LastSameByte] || s1[LastSameByte] == 0)
+      break;
+  size_t PC = reinterpret_cast<size_t>(caller_pc);
+  VP.AddValue((PC & 4095) | (LastSameByte << 12));
+}
+
+static void AddValueForCmp(uintptr_t PC, uint64_t Arg1, uint64_t Arg2) {
+  VP.AddValue((PC & 4095) | (__builtin_popcountl(Arg1 ^ Arg2) << 12));
+}
+
 }  // namespace fuzzer
 
 using fuzzer::TS;
 using fuzzer::RecordingTraces;
 using fuzzer::RecordingMemcmp;
+using fuzzer::RecordingValueProfile;
 
 extern "C" {
 void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
@@ -597,6 +647,8 @@ void dfsan_weak_hook_strcmp(void *caller
 #if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
 void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
                                   const void *s2, size_t n, int result) {
+  if (RecordingValueProfile)
+    fuzzer::AddValueForMemcmp(caller_pc, s1, s2, n);
   if (!RecordingMemcmp) return;
   if (result == 0) return;  // No reason to mutate.
   if (n <= 1) return;  // Not interesting.
@@ -606,6 +658,8 @@ void __sanitizer_weak_hook_memcmp(void *
 
 void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
                                    const char *s2, size_t n, int result) {
+  if (RecordingValueProfile)
+    fuzzer::AddValueForStrcmp(caller_pc, s1, s2, n);
   if (!RecordingMemcmp) return;
   if (result == 0) return;  // No reason to mutate.
   size_t Len1 = fuzzer::InternalStrnlen(s1, n);
@@ -619,6 +673,8 @@ void __sanitizer_weak_hook_strncmp(void
 
 void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
                                    const char *s2, int result) {
+  if (RecordingValueProfile)
+    fuzzer::AddValueForStrcmp(caller_pc, s1, s2, 64);
   if (!RecordingMemcmp) return;
   if (result == 0) return;  // No reason to mutate.
   size_t Len1 = strlen(s1);
@@ -656,11 +712,15 @@ void __sanitizer_weak_hook_memmem(void *
 __attribute__((visibility("default")))
 void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
                                uint64_t Arg2) {
-  if (!RecordingTraces) return;
-  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
-  uint64_t CmpSize = (SizeAndType >> 32) / 8;
-  uint64_t Type = (SizeAndType << 32) >> 32;
-  TS->TraceCmpCallback(PC, CmpSize, Type, Arg1, Arg2);
+  if (RecordingTraces) {
+    uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+    uint64_t CmpSize = (SizeAndType >> 32) / 8;
+    uint64_t Type = (SizeAndType << 32) >> 32;
+    TS->TraceCmpCallback(PC, CmpSize, Type, Arg1, Arg2);
+  }
+  if (RecordingValueProfile)
+    fuzzer::AddValueForCmp(
+        reinterpret_cast<uintptr_t>(__builtin_return_address(0)), Arg1, Arg2);
 }
 
 __attribute__((visibility("default")))

Modified: llvm/trunk/lib/Fuzzer/FuzzerValueBitMap.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerValueBitMap.h?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerValueBitMap.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerValueBitMap.h Tue Aug 16 14:33:51 2016
@@ -32,7 +32,7 @@ struct ValueBitMap {
     Map[WordIdx] |= 1UL << BitIdx;
   }
 
-  // Merges 'Other' into 'this', clear Other,
+  // Merges 'Other' into 'this', clears 'Other',
   // returns the number of set bits in 'this'.
   size_t MergeFrom(ValueBitMap &Other) {
     uintptr_t Res = 0;
@@ -43,7 +43,8 @@ struct ValueBitMap {
         Map[i] = (M |= O);
         Other.Map[i] = 0;
       }
-      Res += __builtin_popcountl(M);
+      if (M)
+        Res += __builtin_popcountl(M);
     }
     return Res;
   }

Modified: llvm/trunk/lib/Fuzzer/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/CMakeLists.txt?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/CMakeLists.txt (original)
+++ llvm/trunk/lib/Fuzzer/test/CMakeLists.txt Tue Aug 16 14:33:51 2016
@@ -88,6 +88,9 @@ set(Tests
   SimpleHashTest
   SimpleTest
   SimpleThreadedTest
+  SingleMemcmpTest
+  SingleStrcmpTest
+  SingleStrncmpTest
   SpamyTest
   StrcmpTest
   StrncmpTest

Added: llvm/trunk/lib/Fuzzer/test/SingleMemcmpTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/SingleMemcmpTest.cpp?rev=278839&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/SingleMemcmpTest.cpp (added)
+++ llvm/trunk/lib/Fuzzer/test/SingleMemcmpTest.cpp Tue Aug 16 14:33:51 2016
@@ -0,0 +1,17 @@
+// 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 a particular string.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  char *S = (char*)Data;
+  if (Size >= 6 && !memcmp(S, "qwerty", 6)) {
+    fprintf(stderr, "BINGO\n");
+    exit(1);
+  }
+  return 0;
+}

Added: llvm/trunk/lib/Fuzzer/test/SingleStrcmpTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/SingleStrcmpTest.cpp?rev=278839&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/SingleStrcmpTest.cpp (added)
+++ llvm/trunk/lib/Fuzzer/test/SingleStrcmpTest.cpp Tue Aug 16 14:33:51 2016
@@ -0,0 +1,17 @@
+// 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 a particular string.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  char *S = (char*)Data;
+  if (Size >= 7 && !strcmp(S, "qwerty")) {
+    fprintf(stderr, "BINGO\n");
+    exit(1);
+  }
+  return 0;
+}

Added: llvm/trunk/lib/Fuzzer/test/SingleStrncmpTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/SingleStrncmpTest.cpp?rev=278839&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/SingleStrncmpTest.cpp (added)
+++ llvm/trunk/lib/Fuzzer/test/SingleStrncmpTest.cpp Tue Aug 16 14:33:51 2016
@@ -0,0 +1,17 @@
+// 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 a particular string.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  char *S = (char*)Data;
+  if (Size >= 6 && !strncmp(S, "qwerty", 6)) {
+    fprintf(stderr, "BINGO\n");
+    exit(1);
+  }
+  return 0;
+}

Modified: llvm/trunk/lib/Fuzzer/test/StrncmpTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/StrncmpTest.cpp?rev=278839&r1=278838&r2=278839&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/StrncmpTest.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/StrncmpTest.cpp Tue Aug 16 14:33:51 2016
@@ -17,7 +17,7 @@ extern "C" int LLVMFuzzerTestOneInput(co
   if (Size >= 8 && strncmp(S, "01234567", 8) == 0) {
     if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) {
       if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) {
-        if (Size >= 16 && strncmp(S + 14, "KLM", 3) == 0) {
+        if (Size >= 17 && strncmp(S + 14, "KLM", 3) == 0) {
           fprintf(stderr, "BINGO\n");
           exit(1);
         }

Added: llvm/trunk/lib/Fuzzer/test/value-profile-cmp.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/value-profile-cmp.test?rev=278839&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/value-profile-cmp.test (added)
+++ llvm/trunk/lib/Fuzzer/test/value-profile-cmp.test Tue Aug 16 14:33:51 2016
@@ -0,0 +1,3 @@
+CHECK: BINGO
+RUN: not LLVMFuzzer-SimpleCmpTest -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s
+

Added: llvm/trunk/lib/Fuzzer/test/value-profile-mem.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/value-profile-mem.test?rev=278839&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/value-profile-mem.test (added)
+++ llvm/trunk/lib/Fuzzer/test/value-profile-mem.test Tue Aug 16 14:33:51 2016
@@ -0,0 +1,4 @@
+CHECK: BINGO
+RUN: not LLVMFuzzer-SingleMemcmpTest -use_memcmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SingleStrcmpTest -use_memcmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SingleStrncmpTest -use_memcmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s

Added: llvm/trunk/lib/Fuzzer/test/value-profile-set.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/value-profile-set.test?rev=278839&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/value-profile-set.test (added)
+++ llvm/trunk/lib/Fuzzer/test/value-profile-set.test Tue Aug 16 14:33:51 2016
@@ -0,0 +1,3 @@
+CHECK: BINGO
+RUN: not LLVMFuzzer-FourIndependentBranchesTest -seed=1 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s
+




More information about the llvm-commits mailing list