/src/mozilla-central/tools/fuzzing/libfuzzer/FuzzerTracePC.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- FuzzerTracePC.cpp - PC tracing--------------------------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // Trace PCs. |
10 | | // This module implements __sanitizer_cov_trace_pc_guard[_init], |
11 | | // the callback required for -fsanitize-coverage=trace-pc-guard instrumentation. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "FuzzerTracePC.h" |
16 | | #include "FuzzerCorpus.h" |
17 | | #include "FuzzerDefs.h" |
18 | | #include "FuzzerDictionary.h" |
19 | | #include "FuzzerExtFunctions.h" |
20 | | #include "FuzzerIO.h" |
21 | | #include "FuzzerUtil.h" |
22 | | #include "FuzzerValueBitMap.h" |
23 | | #include <set> |
24 | | |
25 | | // The coverage counters and PCs. |
26 | | // These are declared as global variables named "__sancov_*" to simplify |
27 | | // experiments with inlined instrumentation. |
28 | | alignas(64) ATTRIBUTE_INTERFACE |
29 | | uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs]; |
30 | | |
31 | | ATTRIBUTE_INTERFACE |
32 | | uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; |
33 | | |
34 | | // Used by -fsanitize-coverage=stack-depth to track stack depth |
35 | | ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack; |
36 | | |
37 | | namespace fuzzer { |
38 | | |
39 | | TracePC TPC; |
40 | | |
41 | 16.2k | uint8_t *TracePC::Counters() const { |
42 | 16.2k | return __sancov_trace_pc_guard_8bit_counters; |
43 | 16.2k | } |
44 | | |
45 | 0 | uintptr_t *TracePC::PCs() const { |
46 | 0 | return __sancov_trace_pc_pcs; |
47 | 0 | } |
48 | | |
49 | 14 | size_t TracePC::GetTotalPCCoverage() { |
50 | 14 | if (ObservedPCs.size()) |
51 | 14 | return ObservedPCs.size(); |
52 | 0 | size_t Res = 0; |
53 | 0 | for (size_t i = 1, N = GetNumPCs(); i < N; i++) |
54 | 0 | if (PCs()[i]) |
55 | 0 | Res++; |
56 | 0 | return Res; |
57 | 0 | } |
58 | | |
59 | | template<class CallBack> |
60 | 10.4k | void TracePC::IterateInline8bitCounters(CallBack CB) const { |
61 | 10.4k | if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) { |
62 | 10.4k | size_t CounterIdx = 0; |
63 | 20.8k | for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { |
64 | 10.4k | uint8_t *Beg = ModuleCounters[i].Start; |
65 | 10.4k | size_t Size = ModuleCounters[i].Stop - Beg; |
66 | 10.4k | assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); |
67 | 14.4G | for (size_t j = 0; j < Size; j++, CounterIdx++) |
68 | 14.4G | CB(i, j, CounterIdx); |
69 | 10.4k | } |
70 | 10.4k | } |
71 | 10.4k | } Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::InitializeUnstableCounters()::$_0>(fuzzer::TracePC::InitializeUnstableCounters()::$_0) const Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::UpdateUnstableCounters(int)::$_1>(fuzzer::TracePC::UpdateUnstableCounters(int)::$_1) const Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::UpdateAndApplyUnstableCounters(int)::$_2>(fuzzer::TracePC::UpdateAndApplyUnstableCounters(int)::$_2) const FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::UpdateObservedPCs()::$_3>(fuzzer::TracePC::UpdateObservedPCs()::$_3) const Line | Count | Source | 60 | 10.4k | void TracePC::IterateInline8bitCounters(CallBack CB) const { | 61 | 10.4k | if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) { | 62 | 10.4k | size_t CounterIdx = 0; | 63 | 20.8k | for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { | 64 | 10.4k | uint8_t *Beg = ModuleCounters[i].Start; | 65 | 10.4k | size_t Size = ModuleCounters[i].Stop - Beg; | 66 | 10.4k | assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); | 67 | 14.4G | for (size_t j = 0; j < Size; j++, CounterIdx++) | 68 | 14.4G | CB(i, j, CounterIdx); | 69 | 10.4k | } | 70 | 10.4k | } | 71 | 10.4k | } |
Unexecuted instantiation: FuzzerTracePC.cpp:void fuzzer::TracePC::IterateInline8bitCounters<fuzzer::TracePC::PrintUnstableStats()::$_6>(fuzzer::TracePC::PrintUnstableStats()::$_6) const |
72 | | |
73 | | // Initializes unstable counters by copying Inline8bitCounters to unstable |
74 | | // counters. |
75 | 0 | void TracePC::InitializeUnstableCounters() { |
76 | 0 | IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { |
77 | 0 | UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j]; |
78 | 0 | }); |
79 | 0 | } |
80 | | |
81 | | // Compares the current counters with counters from previous runs |
82 | | // and records differences as unstable edges. |
83 | 0 | bool TracePC::UpdateUnstableCounters(int UnstableMode) { |
84 | 0 | bool Updated = false; |
85 | 0 | IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { |
86 | 0 | if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) { |
87 | 0 | Updated = true; |
88 | 0 | UnstableCounters[UnstableIdx].IsUnstable = true; |
89 | 0 | if (UnstableMode == ZeroUnstable) |
90 | 0 | UnstableCounters[UnstableIdx].Counter = 0; |
91 | 0 | else if (UnstableMode == MinUnstable) |
92 | 0 | UnstableCounters[UnstableIdx].Counter = std::min( |
93 | 0 | ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter); |
94 | 0 | } |
95 | 0 | }); |
96 | 0 | return Updated; |
97 | 0 | } |
98 | | |
99 | | // Updates and applies unstable counters to ModuleCounters in single iteration |
100 | 0 | void TracePC::UpdateAndApplyUnstableCounters(int UnstableMode) { |
101 | 0 | IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { |
102 | 0 | if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) { |
103 | 0 | UnstableCounters[UnstableIdx].IsUnstable = true; |
104 | 0 | if (UnstableMode == ZeroUnstable) |
105 | 0 | ModuleCounters[i].Start[j] = 0; |
106 | 0 | else if (UnstableMode == MinUnstable) |
107 | 0 | ModuleCounters[i].Start[j] = std::min( |
108 | 0 | ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter); |
109 | 0 | } |
110 | 0 | }); |
111 | 0 | } |
112 | | |
113 | 3 | void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { |
114 | 3 | if (Start == Stop) return; |
115 | 3 | if (NumModulesWithInline8bitCounters && |
116 | 3 | ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return; |
117 | 3 | assert(NumModulesWithInline8bitCounters < |
118 | 3 | sizeof(ModuleCounters) / sizeof(ModuleCounters[0])); |
119 | 3 | ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop}; |
120 | 3 | NumInline8bitCounters += Stop - Start; |
121 | 3 | } |
122 | | |
123 | 3 | void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) { |
124 | 3 | const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start); |
125 | 3 | const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop); |
126 | 3 | if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return; |
127 | 3 | assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0])); |
128 | 3 | ModulePCTable[NumPCTables++] = {B, E}; |
129 | 3 | NumPCsInPCTables += E - B; |
130 | 3 | } |
131 | | |
132 | 0 | void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { |
133 | 0 | if (Start == Stop || *Start) return; |
134 | 0 | assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); |
135 | 0 | for (uint32_t *P = Start; P < Stop; P++) { |
136 | 0 | NumGuards++; |
137 | 0 | if (NumGuards == kNumPCs) { |
138 | 0 | RawPrint( |
139 | 0 | "WARNING: The binary has too many instrumented PCs.\n" |
140 | 0 | " You may want to reduce the size of the binary\n" |
141 | 0 | " for more efficient fuzzing and precise coverage data\n"); |
142 | 0 | } |
143 | 0 | *P = NumGuards % kNumPCs; |
144 | 0 | } |
145 | 0 | Modules[NumModules].Start = Start; |
146 | 0 | Modules[NumModules].Stop = Stop; |
147 | 0 | NumModules++; |
148 | 0 | } |
149 | | |
150 | 3 | void TracePC::PrintModuleInfo() { |
151 | 3 | if (NumGuards) { |
152 | 0 | Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards); |
153 | 0 | for (size_t i = 0; i < NumModules; i++) |
154 | 0 | Printf("%zd [%p, %p), ", Modules[i].Stop - Modules[i].Start, |
155 | 0 | Modules[i].Start, Modules[i].Stop); |
156 | 0 | Printf("\n"); |
157 | 0 | } |
158 | 3 | if (NumModulesWithInline8bitCounters) { |
159 | 3 | Printf("INFO: Loaded %zd modules (%zd inline 8-bit counters): ", |
160 | 3 | NumModulesWithInline8bitCounters, NumInline8bitCounters); |
161 | 6 | for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) |
162 | 3 | Printf("%zd [%p, %p), ", ModuleCounters[i].Stop - ModuleCounters[i].Start, |
163 | 3 | ModuleCounters[i].Start, ModuleCounters[i].Stop); |
164 | 3 | Printf("\n"); |
165 | 3 | } |
166 | 3 | if (NumPCTables) { |
167 | 3 | Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables, |
168 | 3 | NumPCsInPCTables); |
169 | 6 | for (size_t i = 0; i < NumPCTables; i++) { |
170 | 3 | Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start, |
171 | 3 | ModulePCTable[i].Start, ModulePCTable[i].Stop); |
172 | 3 | } |
173 | 3 | Printf("\n"); |
174 | 3 | |
175 | 3 | if ((NumGuards && NumGuards != NumPCsInPCTables) || |
176 | 3 | (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) { |
177 | 0 | Printf("ERROR: The size of coverage PC tables does not match the\n" |
178 | 0 | "number of instrumented PCs. This might be a compiler bug,\n" |
179 | 0 | "please contact the libFuzzer developers.\n" |
180 | 0 | "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n" |
181 | 0 | "for possible workarounds (tl;dr: don't use the old GNU ld)\n"); |
182 | 0 | _Exit(1); |
183 | 0 | } |
184 | 3 | } |
185 | 3 | if (size_t NumExtraCounters = ExtraCountersEnd() - ExtraCountersBegin()) |
186 | 0 | Printf("INFO: %zd Extra Counters\n", NumExtraCounters); |
187 | 3 | } |
188 | | |
189 | | ATTRIBUTE_NO_SANITIZE_ALL |
190 | 265M | void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { |
191 | 265M | const uintptr_t kBits = 12; |
192 | 265M | const uintptr_t kMask = (1 << kBits) - 1; |
193 | 265M | uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits); |
194 | 265M | ValueProfileMap.AddValueModPrime(Idx); |
195 | 265M | } |
196 | | |
197 | 10.4k | void TracePC::UpdateObservedPCs() { |
198 | 10.4k | Vector<uintptr_t> CoveredFuncs; |
199 | 7.32M | auto ObservePC = [&](uintptr_t PC) { |
200 | 7.32M | if (ObservedPCs.insert(PC).second && DoPrintNewPCs) { |
201 | 0 | PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1); |
202 | 0 | Printf("\n"); |
203 | 0 | } |
204 | 7.32M | }; |
205 | 10.4k | |
206 | 7.32M | auto Observe = [&](const PCTableEntry &TE) { |
207 | 7.32M | if (TE.PCFlags & 1) |
208 | 4.20M | if (++ObservedFuncs[TE.PC] == 1 && NumPrintNewFuncs) |
209 | 0 | CoveredFuncs.push_back(TE.PC); |
210 | 7.32M | ObservePC(TE.PC); |
211 | 7.32M | }; |
212 | 10.4k | |
213 | 10.4k | if (NumPCsInPCTables) { |
214 | 10.4k | if (NumInline8bitCounters == NumPCsInPCTables) { |
215 | 14.4G | IterateInline8bitCounters([&](int i, int j, int CounterIdx) { |
216 | 14.4G | if (ModuleCounters[i].Start[j]) |
217 | 7.32M | Observe(ModulePCTable[i].Start[j]); |
218 | 14.4G | }); |
219 | 10.4k | } else if (NumGuards == NumPCsInPCTables) { |
220 | 0 | size_t GuardIdx = 1; |
221 | 0 | for (size_t i = 0; i < NumModules; i++) { |
222 | 0 | uint32_t *Beg = Modules[i].Start; |
223 | 0 | size_t Size = Modules[i].Stop - Beg; |
224 | 0 | assert(Size == |
225 | 0 | (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); |
226 | 0 | for (size_t j = 0; j < Size; j++, GuardIdx++) |
227 | 0 | if (Counters()[GuardIdx]) |
228 | 0 | Observe(ModulePCTable[i].Start[j]); |
229 | 0 | } |
230 | 0 | } |
231 | 10.4k | } |
232 | 10.4k | |
233 | 10.4k | for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; |
234 | 10.4k | i++) { |
235 | 0 | Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size()); |
236 | 0 | PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1); |
237 | 0 | Printf("\n"); |
238 | 0 | } |
239 | 10.4k | } |
240 | | |
241 | 0 | inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { |
242 | 0 | // TODO: this implementation is x86 only. |
243 | 0 | // see sanitizer_common GetPreviousInstructionPc for full implementation. |
244 | 0 | return PC - 1; |
245 | 0 | } |
246 | | |
247 | 0 | inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) { |
248 | 0 | // TODO: this implementation is x86 only. |
249 | 0 | // see sanitizer_common GetPreviousInstructionPc for full implementation. |
250 | 0 | return PC + 1; |
251 | 0 | } |
252 | | |
253 | 0 | static std::string GetModuleName(uintptr_t PC) { |
254 | 0 | char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++? |
255 | 0 | void *OffsetRaw = nullptr; |
256 | 0 | if (!EF->__sanitizer_get_module_and_offset_for_pc( |
257 | 0 | reinterpret_cast<void *>(PC), ModulePathRaw, |
258 | 0 | sizeof(ModulePathRaw), &OffsetRaw)) |
259 | 0 | return ""; |
260 | 0 | return ModulePathRaw; |
261 | 0 | } |
262 | | |
263 | | template<class CallBack> |
264 | 0 | void TracePC::IterateCoveredFunctions(CallBack CB) { |
265 | 0 | for (size_t i = 0; i < NumPCTables; i++) { |
266 | 0 | auto &M = ModulePCTable[i]; |
267 | 0 | assert(M.Start < M.Stop); |
268 | 0 | auto ModuleName = GetModuleName(M.Start->PC); |
269 | 0 | for (auto NextFE = M.Start; NextFE < M.Stop; ) { |
270 | 0 | auto FE = NextFE; |
271 | 0 | assert((FE->PCFlags & 1) && "Not a function entry point"); |
272 | 0 | do { |
273 | 0 | NextFE++; |
274 | 0 | } while (NextFE < M.Stop && !(NextFE->PCFlags & 1)); |
275 | 0 | if (ObservedFuncs.count(FE->PC)) |
276 | 0 | CB(FE, NextFE, ObservedFuncs[FE->PC]); |
277 | 0 | } |
278 | 0 | } |
279 | 0 | } |
280 | | |
281 | 3 | void TracePC::SetFocusFunction(const std::string &FuncName) { |
282 | 3 | // This function should be called once. |
283 | 3 | assert(FocusFunction.first > NumModulesWithInline8bitCounters); |
284 | 3 | if (FuncName.empty()) |
285 | 3 | return; |
286 | 0 | for (size_t M = 0; M < NumModulesWithInline8bitCounters; M++) { |
287 | 0 | auto &PCTE = ModulePCTable[M]; |
288 | 0 | size_t N = PCTE.Stop - PCTE.Start; |
289 | 0 | for (size_t I = 0; I < N; I++) { |
290 | 0 | if (!(PCTE.Start[I].PCFlags & 1)) continue; // not a function entry. |
291 | 0 | auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC)); |
292 | 0 | if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ') |
293 | 0 | Name = Name.substr(3, std::string::npos); |
294 | 0 | if (FuncName != Name) continue; |
295 | 0 | Printf("INFO: Focus function is set to '%s'\n", Name.c_str()); |
296 | 0 | FocusFunction = {M, I}; |
297 | 0 | return; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | | |
302 | 10.4k | bool TracePC::ObservedFocusFunction() { |
303 | 10.4k | size_t I = FocusFunction.first; |
304 | 10.4k | size_t J = FocusFunction.second; |
305 | 10.4k | if (I >= NumModulesWithInline8bitCounters) |
306 | 10.4k | return false; |
307 | 0 | auto &MC = ModuleCounters[I]; |
308 | 0 | size_t Size = MC.Stop - MC.Start; |
309 | 0 | if (J >= Size) |
310 | 0 | return false; |
311 | 0 | return MC.Start[J] != 0; |
312 | 0 | } |
313 | | |
314 | 0 | void TracePC::PrintCoverage() { |
315 | 0 | if (!EF->__sanitizer_symbolize_pc || |
316 | 0 | !EF->__sanitizer_get_module_and_offset_for_pc) { |
317 | 0 | Printf("INFO: __sanitizer_symbolize_pc or " |
318 | 0 | "__sanitizer_get_module_and_offset_for_pc is not available," |
319 | 0 | " not printing coverage\n"); |
320 | 0 | return; |
321 | 0 | } |
322 | 0 | Printf("COVERAGE:\n"); |
323 | 0 | auto CoveredFunctionCallback = [&](const PCTableEntry *First, |
324 | 0 | const PCTableEntry *Last, |
325 | 0 | uintptr_t Counter) { |
326 | 0 | assert(First < Last); |
327 | 0 | auto VisualizePC = GetNextInstructionPc(First->PC); |
328 | 0 | std::string FileStr = DescribePC("%s", VisualizePC); |
329 | 0 | if (!IsInterestingCoverageFile(FileStr)) |
330 | 0 | return; |
331 | 0 | std::string FunctionStr = DescribePC("%F", VisualizePC); |
332 | 0 | if (FunctionStr.find("in ") == 0) |
333 | 0 | FunctionStr = FunctionStr.substr(3); |
334 | 0 | std::string LineStr = DescribePC("%l", VisualizePC); |
335 | 0 | size_t Line = std::stoul(LineStr); |
336 | 0 | size_t NumEdges = Last - First; |
337 | 0 | Vector<uintptr_t> UncoveredPCs; |
338 | 0 | for (auto TE = First; TE < Last; TE++) |
339 | 0 | if (!ObservedPCs.count(TE->PC)) |
340 | 0 | UncoveredPCs.push_back(TE->PC); |
341 | 0 | Printf("COVERED_FUNC: hits: %zd", Counter); |
342 | 0 | Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges); |
343 | 0 | Printf(" %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), Line); |
344 | 0 | for (auto PC: UncoveredPCs) |
345 | 0 | Printf(" UNCOVERED_PC: %s\n", |
346 | 0 | DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str()); |
347 | 0 | }; |
348 | 0 |
|
349 | 0 | IterateCoveredFunctions(CoveredFunctionCallback); |
350 | 0 | } |
351 | | |
352 | 0 | void TracePC::DumpCoverage() { |
353 | 0 | if (EF->__sanitizer_dump_coverage) { |
354 | 0 | Vector<uintptr_t> PCsCopy(GetNumPCs()); |
355 | 0 | for (size_t i = 0; i < GetNumPCs(); i++) |
356 | 0 | PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0; |
357 | 0 | EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size()); |
358 | 0 | } |
359 | 0 | } |
360 | | |
361 | 0 | void TracePC::PrintUnstableStats() { |
362 | 0 | size_t count = 0; |
363 | 0 | Printf("UNSTABLE_FUNCTIONS:\n"); |
364 | 0 | IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { |
365 | 0 | const PCTableEntry &TE = ModulePCTable[i].Start[j]; |
366 | 0 | if (UnstableCounters[UnstableIdx].IsUnstable) { |
367 | 0 | count++; |
368 | 0 | if (ObservedFuncs.count(TE.PC)) { |
369 | 0 | auto VisualizePC = GetNextInstructionPc(TE.PC); |
370 | 0 | std::string FunctionStr = DescribePC("%F", VisualizePC); |
371 | 0 | if (FunctionStr.find("in ") == 0) |
372 | 0 | FunctionStr = FunctionStr.substr(3); |
373 | 0 | Printf("%s\n", FunctionStr.c_str()); |
374 | 0 | } |
375 | 0 | } |
376 | 0 | }); |
377 | 0 |
|
378 | 0 | Printf("stat::stability_rate: %.2f\n", |
379 | 0 | 100 - static_cast<float>(count * 100) / NumInline8bitCounters); |
380 | 0 | } |
381 | | |
382 | | // Value profile. |
383 | | // We keep track of various values that affect control flow. |
384 | | // These values are inserted into a bit-set-based hash map. |
385 | | // Every new bit in the map is treated as a new coverage. |
386 | | // |
387 | | // For memcmp/strcmp/etc the interesting value is the length of the common |
388 | | // prefix of the parameters. |
389 | | // For cmp instructions the interesting value is a XOR of the parameters. |
390 | | // The interesting value is mixed up with the PC and is then added to the map. |
391 | | |
392 | | ATTRIBUTE_NO_SANITIZE_ALL |
393 | | void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, |
394 | 0 | size_t n, bool StopAtZero) { |
395 | 0 | if (!n) return; |
396 | 0 | size_t Len = std::min(n, Word::GetMaxSize()); |
397 | 0 | const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1); |
398 | 0 | const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2); |
399 | 0 | uint8_t B1[Word::kMaxSize]; |
400 | 0 | uint8_t B2[Word::kMaxSize]; |
401 | 0 | // Copy the data into locals in this non-msan-instrumented function |
402 | 0 | // to avoid msan complaining further. |
403 | 0 | size_t Hash = 0; // Compute some simple hash of both strings. |
404 | 0 | for (size_t i = 0; i < Len; i++) { |
405 | 0 | B1[i] = A1[i]; |
406 | 0 | B2[i] = A2[i]; |
407 | 0 | size_t T = B1[i]; |
408 | 0 | Hash ^= (T << 8) | B2[i]; |
409 | 0 | } |
410 | 0 | size_t I = 0; |
411 | 0 | for (; I < Len; I++) |
412 | 0 | if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0)) |
413 | 0 | break; |
414 | 0 | size_t PC = reinterpret_cast<size_t>(caller_pc); |
415 | 0 | size_t Idx = (PC & 4095) | (I << 12); |
416 | 0 | ValueProfileMap.AddValue(Idx); |
417 | 0 | TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len)); |
418 | 0 | } |
419 | | |
420 | | template <class T> |
421 | | ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE |
422 | | ATTRIBUTE_NO_SANITIZE_ALL |
423 | 9.25G | void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { |
424 | 9.25G | uint64_t ArgXor = Arg1 ^ Arg2; |
425 | 9.25G | if (sizeof(T) == 4) |
426 | 4.59G | TORC4.Insert(ArgXor, Arg1, Arg2); |
427 | 4.66G | else if (sizeof(T) == 8) |
428 | 1.48G | TORC8.Insert(ArgXor, Arg1, Arg2); |
429 | 9.25G | uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64] |
430 | 9.25G | uint64_t AbsoluteDistance = |
431 | 9.25G | (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1); |
432 | 9.25G | ValueProfileMap.AddValue(PC * 128 + HammingDistance); |
433 | 9.25G | ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); |
434 | 9.25G | } void fuzzer::TracePC::HandleCmp<unsigned long>(unsigned long, unsigned long, unsigned long) Line | Count | Source | 423 | 1.48G | void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { | 424 | 1.48G | uint64_t ArgXor = Arg1 ^ Arg2; | 425 | 1.48G | if (sizeof(T) == 4) | 426 | 0 | TORC4.Insert(ArgXor, Arg1, Arg2); | 427 | 1.48G | else if (sizeof(T) == 8) | 428 | 1.48G | TORC8.Insert(ArgXor, Arg1, Arg2); | 429 | 1.48G | uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64] | 430 | 1.48G | uint64_t AbsoluteDistance = | 431 | 1.48G | (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1); | 432 | 1.48G | ValueProfileMap.AddValue(PC * 128 + HammingDistance); | 433 | 1.48G | ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); | 434 | 1.48G | } |
void fuzzer::TracePC::HandleCmp<unsigned int>(unsigned long, unsigned int, unsigned int) Line | Count | Source | 423 | 4.59G | void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { | 424 | 4.59G | uint64_t ArgXor = Arg1 ^ Arg2; | 425 | 4.59G | if (sizeof(T) == 4) | 426 | 4.59G | TORC4.Insert(ArgXor, Arg1, Arg2); | 427 | 18.4E | else if (sizeof(T) == 8) | 428 | 0 | TORC8.Insert(ArgXor, Arg1, Arg2); | 429 | 4.59G | uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64] | 430 | 4.59G | uint64_t AbsoluteDistance = | 431 | 4.59G | (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1); | 432 | 4.59G | ValueProfileMap.AddValue(PC * 128 + HammingDistance); | 433 | 4.59G | ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); | 434 | 4.59G | } |
void fuzzer::TracePC::HandleCmp<unsigned short>(unsigned long, unsigned short, unsigned short) Line | Count | Source | 423 | 1.16G | void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { | 424 | 1.16G | uint64_t ArgXor = Arg1 ^ Arg2; | 425 | 1.16G | if (sizeof(T) == 4) | 426 | 0 | TORC4.Insert(ArgXor, Arg1, Arg2); | 427 | 1.16G | else if (sizeof(T) == 8) | 428 | 0 | TORC8.Insert(ArgXor, Arg1, Arg2); | 429 | 1.16G | uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64] | 430 | 1.16G | uint64_t AbsoluteDistance = | 431 | 1.16G | (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1); | 432 | 1.16G | ValueProfileMap.AddValue(PC * 128 + HammingDistance); | 433 | 1.16G | ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); | 434 | 1.16G | } |
void fuzzer::TracePC::HandleCmp<unsigned char>(unsigned long, unsigned char, unsigned char) Line | Count | Source | 423 | 2.01G | void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { | 424 | 2.01G | uint64_t ArgXor = Arg1 ^ Arg2; | 425 | 2.01G | if (sizeof(T) == 4) | 426 | 0 | TORC4.Insert(ArgXor, Arg1, Arg2); | 427 | 2.01G | else if (sizeof(T) == 8) | 428 | 0 | TORC8.Insert(ArgXor, Arg1, Arg2); | 429 | 2.01G | uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64] | 430 | 2.01G | uint64_t AbsoluteDistance = | 431 | 2.01G | (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1); | 432 | 2.01G | ValueProfileMap.AddValue(PC * 128 + HammingDistance); | 433 | 2.01G | ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); | 434 | 2.01G | } |
|
435 | | |
436 | 0 | static size_t InternalStrnlen(const char *S, size_t MaxLen) { |
437 | 0 | size_t Len = 0; |
438 | 0 | for (; Len < MaxLen && S[Len]; Len++) {} |
439 | 0 | return Len; |
440 | 0 | } |
441 | | |
442 | | // Finds min of (strlen(S1), strlen(S2)). |
443 | | // Needed bacause one of these strings may actually be non-zero terminated. |
444 | 0 | static size_t InternalStrnlen2(const char *S1, const char *S2) { |
445 | 0 | size_t Len = 0; |
446 | 0 | for (; S1[Len] && S2[Len]; Len++) {} |
447 | 0 | return Len; |
448 | 0 | } |
449 | | |
450 | 16.2k | void TracePC::ClearInlineCounters() { |
451 | 32.4k | for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { |
452 | 16.2k | uint8_t *Beg = ModuleCounters[i].Start; |
453 | 16.2k | size_t Size = ModuleCounters[i].Stop - Beg; |
454 | 16.2k | memset(Beg, 0, Size); |
455 | 16.2k | } |
456 | 16.2k | } |
457 | | |
458 | | ATTRIBUTE_NO_SANITIZE_ALL |
459 | 16.2k | void TracePC::RecordInitialStack() { |
460 | 16.2k | int stack; |
461 | 16.2k | __sancov_lowest_stack = InitialStack = reinterpret_cast<uintptr_t>(&stack); |
462 | 16.2k | } |
463 | | |
464 | 16.2k | uintptr_t TracePC::GetMaxStackOffset() const { |
465 | 16.2k | return InitialStack - __sancov_lowest_stack; // Stack grows down |
466 | 16.2k | } |
467 | | |
468 | | } // namespace fuzzer |
469 | | |
470 | | extern "C" { |
471 | | ATTRIBUTE_INTERFACE |
472 | | ATTRIBUTE_NO_SANITIZE_ALL |
473 | 0 | void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { |
474 | 0 | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
475 | 0 | uint32_t Idx = *Guard; |
476 | 0 | __sancov_trace_pc_pcs[Idx] = PC; |
477 | 0 | __sancov_trace_pc_guard_8bit_counters[Idx]++; |
478 | 0 | } |
479 | | |
480 | | // Best-effort support for -fsanitize-coverage=trace-pc, which is available |
481 | | // in both Clang and GCC. |
482 | | ATTRIBUTE_INTERFACE |
483 | | ATTRIBUTE_NO_SANITIZE_ALL |
484 | 0 | void __sanitizer_cov_trace_pc() { |
485 | 0 | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
486 | 0 | uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1); |
487 | 0 | __sancov_trace_pc_pcs[Idx] = PC; |
488 | 0 | __sancov_trace_pc_guard_8bit_counters[Idx]++; |
489 | 0 | } |
490 | | |
491 | | ATTRIBUTE_INTERFACE |
492 | 0 | void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { |
493 | 0 | fuzzer::TPC.HandleInit(Start, Stop); |
494 | 0 | } |
495 | | |
496 | | ATTRIBUTE_INTERFACE |
497 | 3 | void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) { |
498 | 3 | fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop); |
499 | 3 | } |
500 | | |
501 | | ATTRIBUTE_INTERFACE |
502 | | void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, |
503 | 3 | const uintptr_t *pcs_end) { |
504 | 3 | fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end); |
505 | 3 | } |
506 | | |
507 | | ATTRIBUTE_INTERFACE |
508 | | ATTRIBUTE_NO_SANITIZE_ALL |
509 | 265M | void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { |
510 | 265M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
511 | 265M | fuzzer::TPC.HandleCallerCallee(PC, Callee); |
512 | 265M | } |
513 | | |
514 | | ATTRIBUTE_INTERFACE |
515 | | ATTRIBUTE_NO_SANITIZE_ALL |
516 | | ATTRIBUTE_TARGET_POPCNT |
517 | 659M | void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { |
518 | 659M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
519 | 659M | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
520 | 659M | } |
521 | | |
522 | | ATTRIBUTE_INTERFACE |
523 | | ATTRIBUTE_NO_SANITIZE_ALL |
524 | | ATTRIBUTE_TARGET_POPCNT |
525 | | // Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic |
526 | | // the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however, |
527 | | // should be changed later to make full use of instrumentation. |
528 | 828M | void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) { |
529 | 828M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
530 | 828M | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
531 | 828M | } |
532 | | |
533 | | ATTRIBUTE_INTERFACE |
534 | | ATTRIBUTE_NO_SANITIZE_ALL |
535 | | ATTRIBUTE_TARGET_POPCNT |
536 | 3.32G | void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { |
537 | 3.32G | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
538 | 3.32G | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
539 | 3.32G | } |
540 | | |
541 | | ATTRIBUTE_INTERFACE |
542 | | ATTRIBUTE_NO_SANITIZE_ALL |
543 | | ATTRIBUTE_TARGET_POPCNT |
544 | 1.26G | void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) { |
545 | 1.26G | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
546 | 1.26G | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
547 | 1.26G | } |
548 | | |
549 | | ATTRIBUTE_INTERFACE |
550 | | ATTRIBUTE_NO_SANITIZE_ALL |
551 | | ATTRIBUTE_TARGET_POPCNT |
552 | 708M | void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { |
553 | 708M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
554 | 708M | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
555 | 708M | } |
556 | | |
557 | | ATTRIBUTE_INTERFACE |
558 | | ATTRIBUTE_NO_SANITIZE_ALL |
559 | | ATTRIBUTE_TARGET_POPCNT |
560 | 452M | void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) { |
561 | 452M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
562 | 452M | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
563 | 452M | } |
564 | | |
565 | | ATTRIBUTE_INTERFACE |
566 | | ATTRIBUTE_NO_SANITIZE_ALL |
567 | | ATTRIBUTE_TARGET_POPCNT |
568 | 127M | void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { |
569 | 127M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
570 | 127M | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
571 | 127M | } |
572 | | |
573 | | ATTRIBUTE_INTERFACE |
574 | | ATTRIBUTE_NO_SANITIZE_ALL |
575 | | ATTRIBUTE_TARGET_POPCNT |
576 | 1.88G | void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) { |
577 | 1.88G | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
578 | 1.88G | fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); |
579 | 1.88G | } |
580 | | |
581 | | ATTRIBUTE_INTERFACE |
582 | | ATTRIBUTE_NO_SANITIZE_ALL |
583 | | ATTRIBUTE_TARGET_POPCNT |
584 | 91.6M | void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { |
585 | 91.6M | uint64_t N = Cases[0]; |
586 | 91.6M | uint64_t ValSizeInBits = Cases[1]; |
587 | 91.6M | uint64_t *Vals = Cases + 2; |
588 | 91.6M | // Skip the most common and the most boring case. |
589 | 91.6M | if (Vals[N - 1] < 256 && Val < 256) |
590 | 88.7M | return; |
591 | 2.89M | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
592 | 2.89M | size_t i; |
593 | 2.89M | uint64_t Token = 0; |
594 | 11.1M | for (i = 0; i < N; i++) { |
595 | 9.57M | Token = Val ^ Vals[i]; |
596 | 9.57M | if (Val < Vals[i]) |
597 | 1.30M | break; |
598 | 9.57M | } |
599 | 2.89M | |
600 | 2.89M | if (ValSizeInBits == 16) |
601 | 1.30M | fuzzer::TPC.HandleCmp(PC + i, static_cast<uint16_t>(Token), (uint16_t)(0)); |
602 | 1.59M | else if (ValSizeInBits == 32) |
603 | 1.59M | fuzzer::TPC.HandleCmp(PC + i, static_cast<uint32_t>(Token), (uint32_t)(0)); |
604 | 0 | else |
605 | 0 | fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0)); |
606 | 2.89M | } |
607 | | |
608 | | ATTRIBUTE_INTERFACE |
609 | | ATTRIBUTE_NO_SANITIZE_ALL |
610 | | ATTRIBUTE_TARGET_POPCNT |
611 | 0 | void __sanitizer_cov_trace_div4(uint32_t Val) { |
612 | 0 | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
613 | 0 | fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); |
614 | 0 | } |
615 | | |
616 | | ATTRIBUTE_INTERFACE |
617 | | ATTRIBUTE_NO_SANITIZE_ALL |
618 | | ATTRIBUTE_TARGET_POPCNT |
619 | 0 | void __sanitizer_cov_trace_div8(uint64_t Val) { |
620 | 0 | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
621 | 0 | fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); |
622 | 0 | } |
623 | | |
624 | | ATTRIBUTE_INTERFACE |
625 | | ATTRIBUTE_NO_SANITIZE_ALL |
626 | | ATTRIBUTE_TARGET_POPCNT |
627 | 0 | void __sanitizer_cov_trace_gep(uintptr_t Idx) { |
628 | 0 | uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); |
629 | 0 | fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); |
630 | 0 | } |
631 | | |
632 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
633 | | void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, |
634 | 0 | const void *s2, size_t n, int result) { |
635 | 0 | if (!fuzzer::RunningUserCallback) return; |
636 | 0 | if (result == 0) return; // No reason to mutate. |
637 | 0 | if (n <= 1) return; // Not interesting. |
638 | 0 | fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false); |
639 | 0 | } |
640 | | |
641 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
642 | | void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, |
643 | 0 | const char *s2, size_t n, int result) { |
644 | 0 | if (!fuzzer::RunningUserCallback) return; |
645 | 0 | if (result == 0) return; // No reason to mutate. |
646 | 0 | size_t Len1 = fuzzer::InternalStrnlen(s1, n); |
647 | 0 | size_t Len2 = fuzzer::InternalStrnlen(s2, n); |
648 | 0 | n = std::min(n, Len1); |
649 | 0 | n = std::min(n, Len2); |
650 | 0 | if (n <= 1) return; // Not interesting. |
651 | 0 | fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true); |
652 | 0 | } |
653 | | |
654 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
655 | | void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, |
656 | 0 | const char *s2, int result) { |
657 | 0 | if (!fuzzer::RunningUserCallback) return; |
658 | 0 | if (result == 0) return; // No reason to mutate. |
659 | 0 | size_t N = fuzzer::InternalStrnlen2(s1, s2); |
660 | 0 | if (N <= 1) return; // Not interesting. |
661 | 0 | fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true); |
662 | 0 | } |
663 | | |
664 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
665 | | void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, |
666 | 0 | const char *s2, size_t n, int result) { |
667 | 0 | if (!fuzzer::RunningUserCallback) return; |
668 | 0 | return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result); |
669 | 0 | } |
670 | | |
671 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
672 | | void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, |
673 | 0 | const char *s2, int result) { |
674 | 0 | if (!fuzzer::RunningUserCallback) return; |
675 | 0 | return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result); |
676 | 0 | } |
677 | | |
678 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
679 | | void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, |
680 | 0 | const char *s2, char *result) { |
681 | 0 | if (!fuzzer::RunningUserCallback) return; |
682 | 0 | fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2)); |
683 | 0 | } |
684 | | |
685 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
686 | | void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, |
687 | 0 | const char *s2, char *result) { |
688 | 0 | if (!fuzzer::RunningUserCallback) return; |
689 | 0 | fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2)); |
690 | 0 | } |
691 | | |
692 | | ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY |
693 | | void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, |
694 | 0 | const void *s2, size_t len2, void *result) { |
695 | 0 | if (!fuzzer::RunningUserCallback) return; |
696 | 0 | fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2); |
697 | 0 | } |
698 | | } // extern "C" |