summaryrefslogtreecommitdiffstats
path: root/tools/fuzzing/libfuzzer/patches/11-callback-rv.patch
blob: 3f9832b0a3eeee54e87d2b48b4e34c23e8a60dcb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# HG changeset patch
# User Christian Holler <choller@mozilla.com>
# Date 1596126448 -7200
#      Thu Jul 30 18:27:28 2020 +0200
# Node ID ea198a0331a6db043cb5978512226977514104db
# Parent  8a2a26b33d516c43c366b2f24d731d27d9843349
[libFuzzer] Change libFuzzer callback contract to allow positive return values

diff --git a/FuzzerInternal.h b/FuzzerInternal.h
--- a/FuzzerInternal.h
+++ b/FuzzerInternal.h
@@ -60,17 +60,17 @@ public:
 
   static void StaticAlarmCallback();
   static void StaticCrashSignalCallback();
   static void StaticExitCallback();
   static void StaticInterruptCallback();
   static void StaticFileSizeExceedCallback();
   static void StaticGracefulExitCallback();
 
-  void ExecuteCallback(const uint8_t *Data, size_t Size);
+  int ExecuteCallback(const uint8_t *Data, size_t Size);
   bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
               InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
 
   // Merge Corpora[1:] into Corpora[0].
   void Merge(const Vector<std::string> &Corpora);
   void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
   MutationDispatcher &GetMD() { return MD; }
   void PrintFinalStats();
diff --git a/FuzzerLoop.cpp b/FuzzerLoop.cpp
--- a/FuzzerLoop.cpp
+++ b/FuzzerLoop.cpp
@@ -463,17 +463,19 @@ static void RenameFeatureSetFile(const s
              DirPlusFile(FeaturesDir, NewFile));
 }
 
 bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
                     InputInfo *II, bool *FoundUniqFeatures) {
   if (!Size)
     return false;
 
-  ExecuteCallback(Data, Size);
+  if (ExecuteCallback(Data, Size) > 0) {
+    return false;
+  }
 
   UniqFeatureSetTmp.clear();
   size_t FoundUniqFeaturesOfII = 0;
   size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
   TPC.CollectFeatures([&](size_t Feature) {
     if (Corpus.AddFeature(Feature, Size, Options.Shrink))
       UniqFeatureSetTmp.push_back(Feature);
     if (Options.Entropic)
@@ -530,48 +532,49 @@ static bool LooseMemeq(const uint8_t *A,
   const size_t Limit = 64;
   if (Size <= 64)
     return !memcmp(A, B, Size);
   // Compare first and last Limit/2 bytes.
   return !memcmp(A, B, Limit / 2) &&
          !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
 }
 
-void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
+int Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
   TPC.RecordInitialStack();
   TotalNumberOfRuns++;
   assert(InFuzzingThread());
   // We copy the contents of Unit into a separate heap buffer
   // so that we reliably find buffer overflows in it.
   uint8_t *DataCopy = new uint8_t[Size];
   memcpy(DataCopy, Data, Size);
   if (EF->__msan_unpoison)
     EF->__msan_unpoison(DataCopy, Size);
   if (EF->__msan_unpoison_param)
     EF->__msan_unpoison_param(2);
   if (CurrentUnitData && CurrentUnitData != Data)
     memcpy(CurrentUnitData, Data, Size);
   CurrentUnitSize = Size;
+  int Res = 0;
   {
     ScopedEnableMsanInterceptorChecks S;
     AllocTracer.Start(Options.TraceMalloc);
     UnitStartTime = system_clock::now();
     TPC.ResetMaps();
     RunningUserCallback = true;
-    int Res = CB(DataCopy, Size);
+    Res = CB(DataCopy, Size);
     RunningUserCallback = false;
     UnitStopTime = system_clock::now();
-    (void)Res;
-    assert(Res == 0);
+    assert(Res >= 0);
     HasMoreMallocsThanFrees = AllocTracer.Stop();
   }
   if (!LooseMemeq(DataCopy, Data, Size))
     CrashOnOverwrittenData();
   CurrentUnitSize = 0;
   delete[] DataCopy;
+  return Res;
 }
 
 std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
   if (Options.OnlyASCII)
     assert(IsASCII(U));
   if (Options.OutputCorpus.empty())
     return "";
   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
diff --git a/FuzzerMerge.cpp b/FuzzerMerge.cpp
--- a/FuzzerMerge.cpp
+++ b/FuzzerMerge.cpp
@@ -223,17 +223,19 @@ void Fuzzer::CrashResistantMergeInternal
       U.shrink_to_fit();
     }
 
     // Write the pre-run marker.
     OF << "STARTED " << i << " " << U.size() << "\n";
     OF.flush();  // Flush is important since Command::Execute may crash.
     // Run.
     TPC.ResetMaps();
-    ExecuteCallback(U.data(), U.size());
+    if (ExecuteCallback(U.data(), U.size()) > 0) {
+      continue;
+    }
     // Collect coverage. We are iterating over the files in this order:
     // * First, files in the initial corpus ordered by size, smallest first.
     // * Then, all other files, smallest first.
     // So it makes no sense to record all features for all files, instead we
     // only record features that were not seen before.
     Set<size_t> UniqFeatures;
     TPC.CollectFeatures([&](size_t Feature) {
       if (AllFeatures.insert(Feature).second)