Skip to content

Commit f45db18

Browse files
author
kcc
committed
[libFuzzer] split DataFlow.cpp into two .cpp files, one of which can be compiled w/o dfsan to speed things up (~25% speedup)
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer@364002 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent b9f51dc commit f45db18

File tree

3 files changed

+147
-100
lines changed

3 files changed

+147
-100
lines changed

dataflow/DataFlow.cpp

+29-100
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
// and also provides basic-block coverage for every input.
1818
//
1919
// Build:
20-
// 1. Compile this file with -fsanitize=dataflow
21-
// 2. Build the fuzz target with -g -fsanitize=dataflow
20+
// 1. Compile this file (DataFlow.cpp) with -fsanitize=dataflow and -O2.
21+
// 2. Compile DataFlowCallbacks.cpp with -O2 -fPIC.
22+
// 3. Build the fuzz target with -g -fsanitize=dataflow
2223
// -fsanitize-coverage=trace-pc-guard,pc-table,bb,trace-cmp
23-
// 3. Link those together with -fsanitize=dataflow
24+
// 4. Link those together with -fsanitize=dataflow
2425
//
2526
// -fsanitize-coverage=trace-cmp inserts callbacks around every comparison
2627
// instruction, DFSan modifies the calls to pass the data flow labels.
@@ -63,32 +64,24 @@
6364

6465
#include <execinfo.h> // backtrace_symbols_fd
6566

66-
#include <sanitizer/dfsan_interface.h>
67+
#include "DataFlow.h"
6768

6869
extern "C" {
6970
extern int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size);
7071
__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
7172
} // extern "C"
7273

74+
CallbackData __dft;
7375
static size_t InputLen;
7476
static size_t NumIterations;
75-
static size_t NumFuncs, NumGuards;
76-
static uint32_t *GuardsBeg, *GuardsEnd;
77-
static const uintptr_t *PCsBeg, *PCsEnd;
78-
static __thread size_t CurrentFunc, CurrentIteration;
79-
static dfsan_label **FuncLabels; // NumFuncs x NumIterations.
80-
static bool *BBExecuted; // Array of NumGuards elements.
81-
82-
enum {
83-
PCFLAG_FUNC_ENTRY = 1,
84-
};
85-
86-
const int kNumLabels = 16;
77+
static dfsan_label **FuncLabelsPerIter; // NumIterations x NumFuncs;
8778

8879
static inline bool BlockIsEntry(size_t BlockIdx) {
89-
return PCsBeg[BlockIdx * 2 + 1] & PCFLAG_FUNC_ENTRY;
80+
return __dft.PCsBeg[BlockIdx * 2 + 1] & PCFLAG_FUNC_ENTRY;
9081
}
9182

83+
const int kNumLabels = 16;
84+
9285
// Prints all instrumented functions.
9386
static int PrintFunctions() {
9487
// We don't have the symbolizer integrated with dfsan yet.
@@ -101,8 +94,8 @@ static int PrintFunctions() {
10194
"| sed 's/dfs\\$//g' "
10295
"| c++filt",
10396
"w");
104-
for (size_t I = 0; I < NumGuards; I++) {
105-
uintptr_t PC = PCsBeg[I * 2];
97+
for (size_t I = 0; I < __dft.NumGuards; I++) {
98+
uintptr_t PC = __dft.PCsBeg[I * 2];
10699
if (!BlockIsEntry(I)) continue;
107100
void *const Buf[1] = {(void*)PC};
108101
backtrace_symbols_fd(Buf, 1, fileno(Pipe));
@@ -121,10 +114,10 @@ static void PrintBinary(FILE *Out, dfsan_label L, size_t Len) {
121114
}
122115

123116
static void PrintDataFlow(FILE *Out) {
124-
for (size_t Func = 0; Func < NumFuncs; Func++) {
117+
for (size_t Func = 0; Func < __dft.NumFuncs; Func++) {
125118
bool HasAny = false;
126119
for (size_t Iter = 0; Iter < NumIterations; Iter++)
127-
if (FuncLabels[Func][Iter])
120+
if (FuncLabelsPerIter[Iter][Func])
128121
HasAny = true;
129122
if (!HasAny)
130123
continue;
@@ -133,7 +126,7 @@ static void PrintDataFlow(FILE *Out) {
133126
if (auto Tail = InputLen % kNumLabels)
134127
LenOfLastIteration = Tail;
135128
for (size_t Iter = 0; Iter < NumIterations; Iter++)
136-
PrintBinary(Out, FuncLabels[Func][Iter],
129+
PrintBinary(Out, FuncLabelsPerIter[Iter][Func],
137130
Iter == NumIterations - 1 ? LenOfLastIteration : kNumLabels);
138131
fprintf(Out, "\n");
139132
}
@@ -143,16 +136,16 @@ static void PrintCoverage(FILE *Out) {
143136
ssize_t CurrentFuncGuard = -1;
144137
ssize_t CurrentFuncNum = -1;
145138
ssize_t NumBlocksInCurrentFunc = -1;
146-
for (size_t FuncBeg = 0; FuncBeg < NumGuards;) {
139+
for (size_t FuncBeg = 0; FuncBeg < __dft.NumGuards;) {
147140
CurrentFuncNum++;
148141
assert(BlockIsEntry(FuncBeg));
149142
size_t FuncEnd = FuncBeg + 1;
150-
for (; FuncEnd < NumGuards && !BlockIsEntry(FuncEnd); FuncEnd++)
143+
for (; FuncEnd < __dft.NumGuards && !BlockIsEntry(FuncEnd); FuncEnd++)
151144
;
152-
if (BBExecuted[FuncBeg]) {
145+
if (__dft.BBExecuted[FuncBeg]) {
153146
fprintf(Out, "C%zd", CurrentFuncNum);
154147
for (size_t I = FuncBeg + 1; I < FuncEnd; I++)
155-
if (BBExecuted[I])
148+
if (__dft.BBExecuted[I])
156149
fprintf(Out, " %zd", I - FuncBeg);
157150
fprintf(Out, " %zd\n", FuncEnd - FuncBeg);
158151
}
@@ -180,19 +173,19 @@ int main(int argc, char **argv) {
180173
fclose(In);
181174

182175
NumIterations = (NumBytesRead + kNumLabels - 1) / kNumLabels;
183-
FuncLabels = (dfsan_label**)calloc(NumFuncs, sizeof(dfsan_label*));
184-
for (size_t Func = 0; Func < NumFuncs; Func++)
185-
FuncLabels[Func] =
186-
(dfsan_label *)calloc(NumIterations, sizeof(dfsan_label));
187-
188-
for (CurrentIteration = 0; CurrentIteration < NumIterations;
189-
CurrentIteration++) {
190-
fprintf(stderr, "INFO: running '%s' %zd/%zd\n", Input, CurrentIteration,
191-
NumIterations);
176+
FuncLabelsPerIter =
177+
(dfsan_label **)calloc(NumIterations, sizeof(dfsan_label *));
178+
for (size_t Iter = 0; Iter < NumIterations; Iter++)
179+
FuncLabelsPerIter[Iter] =
180+
(dfsan_label *)calloc(__dft.NumFuncs, sizeof(dfsan_label));
181+
182+
for (size_t Iter = 0; Iter < NumIterations; Iter++) {
183+
fprintf(stderr, "INFO: running '%s' %zd/%zd\n", Input, Iter, NumIterations);
192184
dfsan_flush();
193185
dfsan_set_label(0, Buf, InputLen);
186+
__dft.FuncLabels = FuncLabelsPerIter[Iter];
194187

195-
size_t BaseIdx = CurrentIteration * kNumLabels;
188+
size_t BaseIdx = Iter * kNumLabels;
196189
size_t LastIdx = BaseIdx + kNumLabels < NumBytesRead ? BaseIdx + kNumLabels
197190
: NumBytesRead;
198191
assert(BaseIdx < LastIdx);
@@ -210,67 +203,3 @@ int main(int argc, char **argv) {
210203
PrintCoverage(Out);
211204
if (!OutIsStdout) fclose(Out);
212205
}
213-
214-
extern "C" {
215-
216-
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
217-
uint32_t *stop) {
218-
assert(NumFuncs == 0 && "This tool does not support DSOs");
219-
assert(start < stop && "The code is not instrumented for coverage");
220-
if (start == stop || *start) return; // Initialize only once.
221-
GuardsBeg = start;
222-
GuardsEnd = stop;
223-
}
224-
225-
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
226-
const uintptr_t *pcs_end) {
227-
if (NumGuards) return; // Initialize only once.
228-
NumGuards = GuardsEnd - GuardsBeg;
229-
PCsBeg = pcs_beg;
230-
PCsEnd = pcs_end;
231-
assert(NumGuards == (PCsEnd - PCsBeg) / 2);
232-
for (size_t i = 0; i < NumGuards; i++) {
233-
if (BlockIsEntry(i)) {
234-
NumFuncs++;
235-
GuardsBeg[i] = NumFuncs;
236-
}
237-
}
238-
BBExecuted = (bool*)calloc(NumGuards, sizeof(bool));
239-
fprintf(stderr, "INFO: %zd instrumented function(s) observed "
240-
"and %zd basic blocks\n", NumFuncs, NumGuards);
241-
}
242-
243-
void __sanitizer_cov_trace_pc_indir(uint64_t x){} // unused.
244-
245-
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
246-
size_t GuardIdx = guard - GuardsBeg;
247-
assert(GuardIdx < NumGuards);
248-
BBExecuted[GuardIdx] = true;
249-
if (!*guard) return; // not a function entry.
250-
uint32_t FuncNum = *guard - 1; // Guards start from 1.
251-
assert(FuncNum < NumFuncs);
252-
CurrentFunc = FuncNum;
253-
}
254-
255-
void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
256-
dfsan_label L1, dfsan_label UnusedL) {
257-
assert(CurrentFunc < NumFuncs);
258-
FuncLabels[CurrentFunc][CurrentIteration] |= L1;
259-
}
260-
261-
#define HOOK(Name, Type) \
262-
void Name(Type Arg1, Type Arg2, dfsan_label L1, dfsan_label L2) { \
263-
assert(CurrentFunc < NumFuncs); \
264-
FuncLabels[CurrentFunc][CurrentIteration] |= L1 | L2; \
265-
}
266-
267-
HOOK(__dfsw___sanitizer_cov_trace_const_cmp1, uint8_t)
268-
HOOK(__dfsw___sanitizer_cov_trace_const_cmp2, uint16_t)
269-
HOOK(__dfsw___sanitizer_cov_trace_const_cmp4, uint32_t)
270-
HOOK(__dfsw___sanitizer_cov_trace_const_cmp8, uint64_t)
271-
HOOK(__dfsw___sanitizer_cov_trace_cmp1, uint8_t)
272-
HOOK(__dfsw___sanitizer_cov_trace_cmp2, uint16_t)
273-
HOOK(__dfsw___sanitizer_cov_trace_cmp4, uint32_t)
274-
HOOK(__dfsw___sanitizer_cov_trace_cmp8, uint64_t)
275-
276-
} // extern "C"

dataflow/DataFlow.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*===- DataFlow.h - a standalone DataFlow trace -------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// Internal header file to connect DataFlow.cpp and DataFlowCallbacks.cpp.
9+
//===----------------------------------------------------------------------===*/
10+
11+
#ifndef __LIBFUZZER_DATAFLOW_H
12+
#define __LIBFUZZER_DATAFLOW_H
13+
14+
#include <cstddef>
15+
#include <cstdint>
16+
#include <sanitizer/dfsan_interface.h>
17+
18+
// This data is shared between DataFlowCallbacks.cpp and DataFlow.cpp.
19+
struct CallbackData {
20+
size_t NumFuncs, NumGuards;
21+
const uintptr_t *PCsBeg, *PCsEnd;
22+
dfsan_label *FuncLabels; // Array of NumFuncs elements.
23+
bool *BBExecuted; // Array of NumGuards elements.
24+
};
25+
26+
extern CallbackData __dft;
27+
28+
enum {
29+
PCFLAG_FUNC_ENTRY = 1,
30+
};
31+
32+
#endif // __LIBFUZZER_DATAFLOW_H

dataflow/DataFlowCallbacks.cpp

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*===- DataFlowCallbacks.cpp - a standalone DataFlow trace -------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// Instrumentation callbacks for DataFlow.cpp.
9+
// These functions should not be instrumented by DFSan, so we
10+
// keep them in a separate file and compile it w/o DFSan.
11+
//===----------------------------------------------------------------------===*/
12+
#include "DataFlow.h"
13+
14+
#include <cassert>
15+
#include <cstdio>
16+
#include <cstdlib>
17+
18+
static __thread size_t CurrentFunc;
19+
static uint32_t *GuardsBeg, *GuardsEnd;
20+
static inline bool BlockIsEntry(size_t BlockIdx) {
21+
return __dft.PCsBeg[BlockIdx * 2 + 1] & PCFLAG_FUNC_ENTRY;
22+
}
23+
24+
extern "C" {
25+
26+
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
27+
uint32_t *stop) {
28+
assert(__dft.NumFuncs == 0 && "This tool does not support DSOs");
29+
assert(start < stop && "The code is not instrumented for coverage");
30+
if (start == stop || *start) return; // Initialize only once.
31+
GuardsBeg = start;
32+
GuardsEnd = stop;
33+
}
34+
35+
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
36+
const uintptr_t *pcs_end) {
37+
if (__dft.NumGuards) return; // Initialize only once.
38+
__dft.NumGuards = GuardsEnd - GuardsBeg;
39+
__dft.PCsBeg = pcs_beg;
40+
__dft.PCsEnd = pcs_end;
41+
assert(__dft.NumGuards == (__dft.PCsEnd - __dft.PCsBeg) / 2);
42+
for (size_t i = 0; i < __dft.NumGuards; i++) {
43+
if (BlockIsEntry(i)) {
44+
__dft.NumFuncs++;
45+
GuardsBeg[i] = __dft.NumFuncs;
46+
}
47+
}
48+
__dft.BBExecuted = (bool*)calloc(__dft.NumGuards, sizeof(bool));
49+
fprintf(stderr, "INFO: %zd instrumented function(s) observed "
50+
"and %zd basic blocks\n", __dft.NumFuncs, __dft.NumGuards);
51+
}
52+
53+
void __sanitizer_cov_trace_pc_indir(uint64_t x){} // unused.
54+
55+
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
56+
size_t GuardIdx = guard - GuardsBeg;
57+
// assert(GuardIdx < __dft.NumGuards);
58+
__dft.BBExecuted[GuardIdx] = true;
59+
if (!*guard) return; // not a function entry.
60+
uint32_t FuncNum = *guard - 1; // Guards start from 1.
61+
// assert(FuncNum < __dft.NumFuncs);
62+
CurrentFunc = FuncNum;
63+
}
64+
65+
void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
66+
dfsan_label L1, dfsan_label UnusedL) {
67+
assert(CurrentFunc < __dft.NumFuncs);
68+
__dft.FuncLabels[CurrentFunc] |= L1;
69+
}
70+
71+
#define HOOK(Name, Type) \
72+
void Name(Type Arg1, Type Arg2, dfsan_label L1, dfsan_label L2) { \
73+
__dft.FuncLabels[CurrentFunc] |= L1 | L2; \
74+
}
75+
//assert(CurrentFunc < __dft.NumFuncs);
76+
77+
HOOK(__dfsw___sanitizer_cov_trace_const_cmp1, uint8_t)
78+
HOOK(__dfsw___sanitizer_cov_trace_const_cmp2, uint16_t)
79+
HOOK(__dfsw___sanitizer_cov_trace_const_cmp4, uint32_t)
80+
HOOK(__dfsw___sanitizer_cov_trace_const_cmp8, uint64_t)
81+
HOOK(__dfsw___sanitizer_cov_trace_cmp1, uint8_t)
82+
HOOK(__dfsw___sanitizer_cov_trace_cmp2, uint16_t)
83+
HOOK(__dfsw___sanitizer_cov_trace_cmp4, uint32_t)
84+
HOOK(__dfsw___sanitizer_cov_trace_cmp8, uint64_t)
85+
86+
} // extern "C"

0 commit comments

Comments
 (0)