Skip to content

Commit 001e5f7

Browse files
author
kcc
committed
[libFuzzer] when doing the merge, keep track of the coveraged edges, not just features
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer@354076 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent dd39114 commit 001e5f7

File tree

6 files changed

+82
-51
lines changed

6 files changed

+82
-51
lines changed

FuzzerLoop.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,10 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
384384
void Fuzzer::CheckExitOnSrcPosOrItem() {
385385
if (!Options.ExitOnSrcPos.empty()) {
386386
static auto *PCsSet = new Set<uintptr_t>;
387-
auto HandlePC = [&](uintptr_t PC) {
388-
if (!PCsSet->insert(PC).second)
387+
auto HandlePC = [&](const TracePC::PCTableEntry *TE) {
388+
if (!PCsSet->insert(TE->PC).second)
389389
return;
390-
std::string Descr = DescribePC("%F %L", PC + 1);
390+
std::string Descr = DescribePC("%F %L", TE->PC + 1);
391391
if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
392392
Printf("INFO: found line matching '%s', exiting.\n",
393393
Options.ExitOnSrcPos.c_str());

FuzzerMerge.cpp

+24-7
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
4242
// file1
4343
// file2 # One file name per line.
4444
// STARTED 0 123 # FileID, file size
45-
// DONE 0 1 4 6 8 # FileID COV1 COV2 ...
46-
// STARTED 1 456 # If DONE is missing, the input crashed while processing.
45+
// FT 0 1 4 6 8 # FileID COV1 COV2 ...
46+
// COV 0 7 8 9 # FileID COV1 COV1
47+
// STARTED 1 456 # If FT is missing, the input crashed while processing.
4748
// STARTED 2 567
48-
// DONE 2 8 9
49+
// FT 2 8 9
50+
// COV 2 11 12
4951
bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
5052
LastFailure.clear();
5153
std::string Line;
@@ -70,11 +72,12 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
7072
if (!std::getline(IS, Files[i].Name, '\n'))
7173
return false;
7274

73-
// Parse STARTED and DONE lines.
75+
// Parse STARTED, FT, and COV lines.
7476
size_t ExpectedStartMarker = 0;
7577
const size_t kInvalidStartMarker = -1;
7678
size_t LastSeenStartMarker = kInvalidStartMarker;
7779
Vector<uint32_t> TmpFeatures;
80+
Set<uintptr_t> PCs;
7881
while (std::getline(IS, Line, '\n')) {
7982
std::istringstream ISS1(Line);
8083
std::string Marker;
@@ -89,8 +92,8 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
8992
LastSeenStartMarker = ExpectedStartMarker;
9093
assert(ExpectedStartMarker < Files.size());
9194
ExpectedStartMarker++;
92-
} else if (Marker == "DONE") {
93-
// DONE FILE_ID COV1 COV2 COV3 ...
95+
} else if (Marker == "FT") {
96+
// FT FILE_ID COV1 COV2 COV3 ...
9497
size_t CurrentFileIdx = N;
9598
if (CurrentFileIdx != LastSeenStartMarker)
9699
return false;
@@ -102,6 +105,11 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
102105
std::sort(TmpFeatures.begin(), TmpFeatures.end());
103106
Files[CurrentFileIdx].Features = TmpFeatures;
104107
}
108+
} else if (Marker == "COV") {
109+
if (ParseCoverage)
110+
while (ISS1 >> std::hex >> N)
111+
if (PCs.insert(N).second)
112+
NumCoveredPCs++;
105113
} else {
106114
return false;
107115
}
@@ -199,6 +207,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
199207

200208
std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
201209
Set<size_t> AllFeatures;
210+
Set<const TracePC::PCTableEntry *> AllPCs;
202211
for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
203212
Fuzzer::MaybeExitGracefully();
204213
auto U = FileToVector(M.Files[i].Name);
@@ -223,16 +232,24 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
223232
if (AllFeatures.insert(Feature).second)
224233
UniqFeatures.insert(Feature);
225234
});
235+
TPC.UpdateObservedPCs();
226236
// Show stats.
227237
if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
228238
PrintStats("pulse ");
229239
// Write the post-run marker and the coverage.
230-
OF << "DONE " << i;
240+
OF << "FT " << i;
231241
for (size_t F : UniqFeatures)
232242
OF << " " << std::hex << F;
233243
OF << "\n";
244+
OF << "COV " << i;
245+
TPC.ForEachObservedPC([&](const TracePC::PCTableEntry *TE) {
246+
if (AllPCs.insert(TE).second)
247+
OF << " " << TPC.PCTableEntryIdx(TE);
248+
});
249+
OF << "\n";
234250
OF.flush();
235251
}
252+
PrintStats("DONE ");
236253
}
237254

238255
static void WriteNewControlFile(const std::string &CFPath,

FuzzerMerge.h

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct MergeFileInfo {
5656

5757
struct Merger {
5858
Vector<MergeFileInfo> Files;
59+
size_t NumCoveredPCs = 0;
5960
size_t NumFilesInFirstCorpus = 0;
6061
size_t FirstNotProcessedFile = 0;
6162
std::string LastFailure;

FuzzerTracePC.cpp

+22-10
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,19 @@ inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
187187

188188
void TracePC::UpdateObservedPCs() {
189189
Vector<uintptr_t> CoveredFuncs;
190-
auto ObservePC = [&](uintptr_t PC) {
191-
if (ObservedPCs.insert(PC).second && DoPrintNewPCs) {
192-
PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", GetNextInstructionPc(PC));
190+
auto ObservePC = [&](const PCTableEntry *TE) {
191+
if (ObservedPCs.insert(TE).second && DoPrintNewPCs) {
192+
PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p",
193+
GetNextInstructionPc(TE->PC));
193194
Printf("\n");
194195
}
195196
};
196197

197-
auto Observe = [&](const PCTableEntry &TE) {
198-
if (TE.PCFlags & 1)
199-
if (++ObservedFuncs[TE.PC] == 1 && NumPrintNewFuncs)
200-
CoveredFuncs.push_back(TE.PC);
201-
ObservePC(TE.PC);
198+
auto Observe = [&](const PCTableEntry *TE) {
199+
if (TE->PCFlags & 1)
200+
if (++ObservedFuncs[TE->PC] == 1 && NumPrintNewFuncs)
201+
CoveredFuncs.push_back(TE->PC);
202+
ObservePC(TE);
202203
};
203204

204205
if (NumPCsInPCTables) {
@@ -212,7 +213,7 @@ void TracePC::UpdateObservedPCs() {
212213
if (!R.Enabled) continue;
213214
for (uint8_t *P = R.Start; P < R.Stop; P++)
214215
if (*P)
215-
Observe(ModulePCTable[i].Start[M.Idx(P)]);
216+
Observe(&ModulePCTable[i].Start[M.Idx(P)]);
216217
}
217218
}
218219
}
@@ -226,6 +227,17 @@ void TracePC::UpdateObservedPCs() {
226227
}
227228
}
228229

230+
uintptr_t TracePC::PCTableEntryIdx(const PCTableEntry *TE) {
231+
size_t TotalTEs = 0;
232+
for (size_t i = 0; i < NumPCTables; i++) {
233+
auto &M = ModulePCTable[i];
234+
if (TE >= M.Start && TE < M.Stop)
235+
return TotalTEs + TE - M.Start;
236+
TotalTEs += M.Stop - M.Start;
237+
}
238+
assert(0);
239+
return 0;
240+
}
229241

230242
static std::string GetModuleName(uintptr_t PC) {
231243
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
@@ -303,7 +315,7 @@ void TracePC::PrintCoverage() {
303315
size_t NumEdges = Last - First;
304316
Vector<uintptr_t> UncoveredPCs;
305317
for (auto TE = First; TE < Last; TE++)
306-
if (!ObservedPCs.count(TE->PC))
318+
if (!ObservedPCs.count(TE))
307319
UncoveredPCs.push_back(TE->PC);
308320
Printf("%sCOVERED_FUNC: hits: %zd", Counter ? "" : "UN", Counter);
309321
Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges);

FuzzerTracePC.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ class TracePC {
122122
void ProtectLazyCounters();
123123
bool UnprotectLazyCounters(void *CounterPtr);
124124

125+
struct PCTableEntry {
126+
uintptr_t PC, PCFlags;
127+
};
128+
129+
uintptr_t PCTableEntryIdx(const PCTableEntry *TE);
130+
125131
private:
126132
bool UseCounters = false;
127133
uint32_t UseValueProfileMask = false;
@@ -159,16 +165,11 @@ class TracePC {
159165
CB(Modules[m].Regions[r]);
160166
}
161167

162-
163-
struct PCTableEntry {
164-
uintptr_t PC, PCFlags;
165-
};
166-
167168
struct { const PCTableEntry *Start, *Stop; } ModulePCTable[4096];
168169
size_t NumPCTables;
169170
size_t NumPCsInPCTables;
170171

171-
Set<uintptr_t> ObservedPCs;
172+
Set<const PCTableEntry*> ObservedPCs;
172173
std::unordered_map<uintptr_t, uintptr_t> ObservedFuncs; // PC => Counter.
173174

174175
uint8_t *FocusFunctionCounterPtr = nullptr;

tests/FuzzerUnittest.cpp

+25-25
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ TEST(Merge, Bad) {
619619
"2\n2\nA\n",
620620
"2\n2\nA\nB\nC\n",
621621
"0\n0\n",
622-
"1\n1\nA\nDONE 0",
622+
"1\n1\nA\nFT 0",
623623
"1\n1\nA\nSTARTED 1",
624624
};
625625
Merger M;
@@ -670,9 +670,9 @@ TEST(Merge, Good) {
670670

671671
EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n"
672672
"STARTED 0 1000\n"
673-
"DONE 0 1 2 3\n"
673+
"FT 0 1 2 3\n"
674674
"STARTED 1 1001\n"
675-
"DONE 1 4 5 6 \n"
675+
"FT 1 4 5 6 \n"
676676
"STARTED 2 1002\n"
677677
"", true));
678678
EXPECT_EQ(M.Files.size(), 3U);
@@ -693,9 +693,9 @@ TEST(Merge, Good) {
693693
Set<uint32_t> NewFeatures;
694694

695695
EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n"
696-
"STARTED 0 1000\nDONE 0 1 2 3\n"
697-
"STARTED 1 1001\nDONE 1 4 5 6 \n"
698-
"STARTED 2 1002\nDONE 2 6 1 3 \n"
696+
"STARTED 0 1000\nFT 0 1 2 3\n"
697+
"STARTED 1 1001\nFT 1 4 5 6 \n"
698+
"STARTED 2 1002\nFT 2 6 1 3 \n"
699699
"", true));
700700
EXPECT_EQ(M.Files.size(), 3U);
701701
EXPECT_EQ(M.NumFilesInFirstCorpus, 2U);
@@ -708,9 +708,9 @@ TEST(Merge, Good) {
708708
EQ(NewFiles, {});
709709

710710
EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n"
711-
"STARTED 0 1000\nDONE 0 1 2 3\n"
712-
"STARTED 1 1001\nDONE 1 4 5 6 \n"
713-
"STARTED 2 1002\nDONE 2 6 1 3\n"
711+
"STARTED 0 1000\nFT 0 1 2 3\n"
712+
"STARTED 1 1001\nFT 1 4 5 6 \n"
713+
"STARTED 2 1002\nFT 2 6 1 3\n"
714714
"", true));
715715
EQ(M.Files[0].Features, {1, 2, 3});
716716
EQ(M.Files[1].Features, {4, 5, 6});
@@ -720,8 +720,8 @@ TEST(Merge, Good) {
720720

721721
// Same as the above, but with InitialFeatures.
722722
EXPECT_TRUE(M.Parse("2\n0\nB\nC\n"
723-
"STARTED 0 1001\nDONE 0 4 5 6 \n"
724-
"STARTED 1 1002\nDONE 1 6 1 3\n"
723+
"STARTED 0 1001\nFT 0 4 5 6 \n"
724+
"STARTED 1 1002\nFT 1 6 1 3\n"
725725
"", true));
726726
EQ(M.Files[0].Features, {4, 5, 6});
727727
EQ(M.Files[1].Features, {1, 3, 6});
@@ -736,29 +736,29 @@ TEST(Merge, Good) {
736736
TEST(Merge, Merge) {
737737

738738
Merge("3\n1\nA\nB\nC\n"
739-
"STARTED 0 1000\nDONE 0 1 2 3\n"
740-
"STARTED 1 1001\nDONE 1 4 5 6 \n"
741-
"STARTED 2 1002\nDONE 2 6 1 3 \n",
739+
"STARTED 0 1000\nFT 0 1 2 3\n"
740+
"STARTED 1 1001\nFT 1 4 5 6 \n"
741+
"STARTED 2 1002\nFT 2 6 1 3 \n",
742742
{"B"}, 3);
743743

744744
Merge("3\n0\nA\nB\nC\n"
745-
"STARTED 0 2000\nDONE 0 1 2 3\n"
746-
"STARTED 1 1001\nDONE 1 4 5 6 \n"
747-
"STARTED 2 1002\nDONE 2 6 1 3 \n",
745+
"STARTED 0 2000\nFT 0 1 2 3\n"
746+
"STARTED 1 1001\nFT 1 4 5 6 \n"
747+
"STARTED 2 1002\nFT 2 6 1 3 \n",
748748
{"A", "B", "C"}, 6);
749749

750750
Merge("4\n0\nA\nB\nC\nD\n"
751-
"STARTED 0 2000\nDONE 0 1 2 3\n"
752-
"STARTED 1 1101\nDONE 1 4 5 6 \n"
753-
"STARTED 2 1102\nDONE 2 6 1 3 100 \n"
754-
"STARTED 3 1000\nDONE 3 1 \n",
751+
"STARTED 0 2000\nFT 0 1 2 3\n"
752+
"STARTED 1 1101\nFT 1 4 5 6 \n"
753+
"STARTED 2 1102\nFT 2 6 1 3 100 \n"
754+
"STARTED 3 1000\nFT 3 1 \n",
755755
{"A", "B", "C", "D"}, 7);
756756

757757
Merge("4\n1\nA\nB\nC\nD\n"
758-
"STARTED 0 2000\nDONE 0 4 5 6 7 8\n"
759-
"STARTED 1 1100\nDONE 1 1 2 3 \n"
760-
"STARTED 2 1100\nDONE 2 2 3 \n"
761-
"STARTED 3 1000\nDONE 3 1 \n",
758+
"STARTED 0 2000\nFT 0 4 5 6 7 8\n"
759+
"STARTED 1 1100\nFT 1 1 2 3 \n"
760+
"STARTED 2 1100\nFT 2 2 3 \n"
761+
"STARTED 3 1000\nFT 3 1 \n",
762762
{"B", "D"}, 3);
763763
}
764764

0 commit comments

Comments
 (0)