/src/mozilla-central/tools/fuzzing/libfuzzer/FuzzerMutate.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- FuzzerMutate.cpp - Mutate a test input -----------------------------===// |
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 | | // Mutate a test input. |
10 | | //===----------------------------------------------------------------------===// |
11 | | |
12 | | #include "FuzzerMutate.h" |
13 | | #include "FuzzerCorpus.h" |
14 | | #include "FuzzerDefs.h" |
15 | | #include "FuzzerExtFunctions.h" |
16 | | #include "FuzzerIO.h" |
17 | | #include "FuzzerOptions.h" |
18 | | |
19 | | namespace fuzzer { |
20 | | |
21 | | const size_t Dictionary::kMaxDictSize; |
22 | | |
23 | 0 | static void PrintASCII(const Word &W, const char *PrintAfter) { |
24 | 0 | PrintASCII(W.data(), W.size(), PrintAfter); |
25 | 0 | } |
26 | | |
27 | | MutationDispatcher::MutationDispatcher(Random &Rand, |
28 | | const FuzzingOptions &Options) |
29 | 3 | : Rand(Rand), Options(Options) { |
30 | 3 | DefaultMutators.insert( |
31 | 3 | DefaultMutators.begin(), |
32 | 3 | { |
33 | 3 | {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, |
34 | 3 | {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, |
35 | 3 | {&MutationDispatcher::Mutate_InsertRepeatedBytes, |
36 | 3 | "InsertRepeatedBytes"}, |
37 | 3 | {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, |
38 | 3 | {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, |
39 | 3 | {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, |
40 | 3 | {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, |
41 | 3 | {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, |
42 | 3 | {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, |
43 | 3 | {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, |
44 | 3 | {&MutationDispatcher::Mutate_AddWordFromManualDictionary, |
45 | 3 | "ManualDict"}, |
46 | 3 | {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, |
47 | 3 | "PersAutoDict"}, |
48 | 3 | }); |
49 | 3 | if(Options.UseCmp) |
50 | 3 | DefaultMutators.push_back( |
51 | 3 | {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); |
52 | 3 | |
53 | 3 | if (EF->LLVMFuzzerCustomMutator) |
54 | 0 | Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); |
55 | 3 | else |
56 | 3 | Mutators = DefaultMutators; |
57 | 3 | |
58 | 3 | if (EF->LLVMFuzzerCustomCrossOver) |
59 | 0 | Mutators.push_back( |
60 | 0 | {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); |
61 | 3 | } |
62 | | |
63 | 0 | static char RandCh(Random &Rand) { |
64 | 0 | if (Rand.RandBool()) return Rand(256); |
65 | 0 | const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00"; |
66 | 0 | return Special[Rand(sizeof(Special) - 1)]; |
67 | 0 | } |
68 | | |
69 | | size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, |
70 | 0 | size_t MaxSize) { |
71 | 0 | return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); |
72 | 0 | } |
73 | | |
74 | | size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, |
75 | 0 | size_t MaxSize) { |
76 | 0 | if (!Corpus || Corpus->size() < 2 || Size == 0) |
77 | 0 | return 0; |
78 | 0 | size_t Idx = Rand(Corpus->size()); |
79 | 0 | const Unit &Other = (*Corpus)[Idx]; |
80 | 0 | if (Other.empty()) |
81 | 0 | return 0; |
82 | 0 | CustomCrossOverInPlaceHere.resize(MaxSize); |
83 | 0 | auto &U = CustomCrossOverInPlaceHere; |
84 | 0 | size_t NewSize = EF->LLVMFuzzerCustomCrossOver( |
85 | 0 | Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); |
86 | 0 | if (!NewSize) |
87 | 0 | return 0; |
88 | 0 | assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); |
89 | 0 | memcpy(Data, U.data(), NewSize); |
90 | 0 | return NewSize; |
91 | 0 | } |
92 | | |
93 | | size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, |
94 | 0 | size_t MaxSize) { |
95 | 0 | if (Size > MaxSize || Size == 0) return 0; |
96 | 0 | size_t ShuffleAmount = |
97 | 0 | Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. |
98 | 0 | size_t ShuffleStart = Rand(Size - ShuffleAmount); |
99 | 0 | assert(ShuffleStart + ShuffleAmount <= Size); |
100 | 0 | std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); |
101 | 0 | return Size; |
102 | 0 | } |
103 | | |
104 | | size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size, |
105 | 0 | size_t MaxSize) { |
106 | 0 | if (Size <= 1) return 0; |
107 | 0 | size_t N = Rand(Size / 2) + 1; |
108 | 0 | assert(N < Size); |
109 | 0 | size_t Idx = Rand(Size - N + 1); |
110 | 0 | // Erase Data[Idx:Idx+N]. |
111 | 0 | memmove(Data + Idx, Data + Idx + N, Size - Idx - N); |
112 | 0 | // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); |
113 | 0 | return Size - N; |
114 | 0 | } |
115 | | |
116 | | size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, |
117 | 0 | size_t MaxSize) { |
118 | 0 | if (Size >= MaxSize) return 0; |
119 | 0 | size_t Idx = Rand(Size + 1); |
120 | 0 | // Insert new value at Data[Idx]. |
121 | 0 | memmove(Data + Idx + 1, Data + Idx, Size - Idx); |
122 | 0 | Data[Idx] = RandCh(Rand); |
123 | 0 | return Size + 1; |
124 | 0 | } |
125 | | |
126 | | size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data, |
127 | | size_t Size, |
128 | 0 | size_t MaxSize) { |
129 | 0 | const size_t kMinBytesToInsert = 3; |
130 | 0 | if (Size + kMinBytesToInsert >= MaxSize) return 0; |
131 | 0 | size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128); |
132 | 0 | size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert; |
133 | 0 | assert(Size + N <= MaxSize && N); |
134 | 0 | size_t Idx = Rand(Size + 1); |
135 | 0 | // Insert new values at Data[Idx]. |
136 | 0 | memmove(Data + Idx + N, Data + Idx, Size - Idx); |
137 | 0 | // Give preference to 0x00 and 0xff. |
138 | 0 | uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255); |
139 | 0 | for (size_t i = 0; i < N; i++) |
140 | 0 | Data[Idx + i] = Byte; |
141 | 0 | return Size + N; |
142 | 0 | } |
143 | | |
144 | | size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, |
145 | 0 | size_t MaxSize) { |
146 | 0 | if (Size > MaxSize) return 0; |
147 | 0 | size_t Idx = Rand(Size); |
148 | 0 | Data[Idx] = RandCh(Rand); |
149 | 0 | return Size; |
150 | 0 | } |
151 | | |
152 | | size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, |
153 | 0 | size_t MaxSize) { |
154 | 0 | if (Size > MaxSize) return 0; |
155 | 0 | size_t Idx = Rand(Size); |
156 | 0 | Data[Idx] ^= 1 << Rand(8); |
157 | 0 | return Size; |
158 | 0 | } |
159 | | |
160 | | size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, |
161 | | size_t Size, |
162 | 0 | size_t MaxSize) { |
163 | 0 | return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); |
164 | 0 | } |
165 | | |
166 | | size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size, |
167 | | size_t MaxSize, |
168 | 0 | DictionaryEntry &DE) { |
169 | 0 | const Word &W = DE.GetW(); |
170 | 0 | bool UsePositionHint = DE.HasPositionHint() && |
171 | 0 | DE.GetPositionHint() + W.size() < Size && |
172 | 0 | Rand.RandBool(); |
173 | 0 | if (Rand.RandBool()) { // Insert W. |
174 | 0 | if (Size + W.size() > MaxSize) return 0; |
175 | 0 | size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1); |
176 | 0 | memmove(Data + Idx + W.size(), Data + Idx, Size - Idx); |
177 | 0 | memcpy(Data + Idx, W.data(), W.size()); |
178 | 0 | Size += W.size(); |
179 | 0 | } else { // Overwrite some bytes with W. |
180 | 0 | if (W.size() > Size) return 0; |
181 | 0 | size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size()); |
182 | 0 | memcpy(Data + Idx, W.data(), W.size()); |
183 | 0 | } |
184 | 0 | return Size; |
185 | 0 | } |
186 | | |
187 | | // Somewhere in the past we have observed a comparison instructions |
188 | | // with arguments Arg1 Arg2. This function tries to guess a dictionary |
189 | | // entry that will satisfy that comparison. |
190 | | // It first tries to find one of the arguments (possibly swapped) in the |
191 | | // input and if it succeeds it creates a DE with a position hint. |
192 | | // Otherwise it creates a DE with one of the arguments w/o a position hint. |
193 | | DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( |
194 | | const void *Arg1, const void *Arg2, |
195 | | const void *Arg1Mutation, const void *Arg2Mutation, |
196 | | size_t ArgSize, const uint8_t *Data, |
197 | 0 | size_t Size) { |
198 | 0 | bool HandleFirst = Rand.RandBool(); |
199 | 0 | const void *ExistingBytes, *DesiredBytes; |
200 | 0 | Word W; |
201 | 0 | const uint8_t *End = Data + Size; |
202 | 0 | for (int Arg = 0; Arg < 2; Arg++) { |
203 | 0 | ExistingBytes = HandleFirst ? Arg1 : Arg2; |
204 | 0 | DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation; |
205 | 0 | HandleFirst = !HandleFirst; |
206 | 0 | W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize); |
207 | 0 | const size_t kMaxNumPositions = 8; |
208 | 0 | size_t Positions[kMaxNumPositions]; |
209 | 0 | size_t NumPositions = 0; |
210 | 0 | for (const uint8_t *Cur = Data; |
211 | 0 | Cur < End && NumPositions < kMaxNumPositions; Cur++) { |
212 | 0 | Cur = |
213 | 0 | (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize); |
214 | 0 | if (!Cur) break; |
215 | 0 | Positions[NumPositions++] = Cur - Data; |
216 | 0 | } |
217 | 0 | if (!NumPositions) continue; |
218 | 0 | return DictionaryEntry(W, Positions[Rand(NumPositions)]); |
219 | 0 | } |
220 | 0 | DictionaryEntry DE(W); |
221 | 0 | return DE; |
222 | 0 | } |
223 | | |
224 | | |
225 | | template <class T> |
226 | | DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( |
227 | 0 | T Arg1, T Arg2, const uint8_t *Data, size_t Size) { |
228 | 0 | if (Rand.RandBool()) Arg1 = Bswap(Arg1); |
229 | 0 | if (Rand.RandBool()) Arg2 = Bswap(Arg2); |
230 | 0 | T Arg1Mutation = Arg1 + Rand(-1, 1); |
231 | 0 | T Arg2Mutation = Arg2 + Rand(-1, 1); |
232 | 0 | return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation, |
233 | 0 | sizeof(Arg1), Data, Size); |
234 | 0 | } Unexecuted instantiation: fuzzer::DictionaryEntry fuzzer::MutationDispatcher::MakeDictionaryEntryFromCMP<unsigned long>(unsigned long, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: fuzzer::DictionaryEntry fuzzer::MutationDispatcher::MakeDictionaryEntryFromCMP<unsigned short>(unsigned short, unsigned short, unsigned char const*, unsigned long) Unexecuted instantiation: fuzzer::DictionaryEntry fuzzer::MutationDispatcher::MakeDictionaryEntryFromCMP<unsigned int>(unsigned int, unsigned int, unsigned char const*, unsigned long) |
235 | | |
236 | | DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( |
237 | 0 | const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) { |
238 | 0 | return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(), |
239 | 0 | Arg2.data(), Arg1.size(), Data, Size); |
240 | 0 | } |
241 | | |
242 | | size_t MutationDispatcher::Mutate_AddWordFromTORC( |
243 | 0 | uint8_t *Data, size_t Size, size_t MaxSize) { |
244 | 0 | Word W; |
245 | 0 | DictionaryEntry DE; |
246 | 0 | switch (Rand(4)) { |
247 | 0 | case 0: { |
248 | 0 | auto X = TPC.TORC8.Get(Rand.Rand()); |
249 | 0 | DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); |
250 | 0 | } break; |
251 | 0 | case 1: { |
252 | 0 | auto X = TPC.TORC4.Get(Rand.Rand()); |
253 | 0 | if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool()) |
254 | 0 | DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size); |
255 | 0 | else |
256 | 0 | DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); |
257 | 0 | } break; |
258 | 0 | case 2: { |
259 | 0 | auto X = TPC.TORCW.Get(Rand.Rand()); |
260 | 0 | DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); |
261 | 0 | } break; |
262 | 0 | case 3: if (Options.UseMemmem) { |
263 | 0 | auto X = TPC.MMT.Get(Rand.Rand()); |
264 | 0 | DE = DictionaryEntry(X); |
265 | 0 | } break; |
266 | 0 | default: |
267 | 0 | assert(0); |
268 | 0 | } |
269 | 0 | if (!DE.GetW().size()) return 0; |
270 | 0 | Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); |
271 | 0 | if (!Size) return 0; |
272 | 0 | DictionaryEntry &DERef = |
273 | 0 | CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ % |
274 | 0 | kCmpDictionaryEntriesDequeSize]; |
275 | 0 | DERef = DE; |
276 | 0 | CurrentDictionaryEntrySequence.push_back(&DERef); |
277 | 0 | return Size; |
278 | 0 | } |
279 | | |
280 | | size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( |
281 | 0 | uint8_t *Data, size_t Size, size_t MaxSize) { |
282 | 0 | return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); |
283 | 0 | } |
284 | | |
285 | | size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, |
286 | 0 | size_t Size, size_t MaxSize) { |
287 | 0 | if (Size > MaxSize) return 0; |
288 | 0 | if (D.empty()) return 0; |
289 | 0 | DictionaryEntry &DE = D[Rand(D.size())]; |
290 | 0 | Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); |
291 | 0 | if (!Size) return 0; |
292 | 0 | DE.IncUseCount(); |
293 | 0 | CurrentDictionaryEntrySequence.push_back(&DE); |
294 | 0 | return Size; |
295 | 0 | } |
296 | | |
297 | | // Overwrites part of To[0,ToSize) with a part of From[0,FromSize). |
298 | | // Returns ToSize. |
299 | | size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize, |
300 | 0 | uint8_t *To, size_t ToSize) { |
301 | 0 | // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize). |
302 | 0 | size_t ToBeg = Rand(ToSize); |
303 | 0 | size_t CopySize = Rand(ToSize - ToBeg) + 1; |
304 | 0 | assert(ToBeg + CopySize <= ToSize); |
305 | 0 | CopySize = std::min(CopySize, FromSize); |
306 | 0 | size_t FromBeg = Rand(FromSize - CopySize + 1); |
307 | 0 | assert(FromBeg + CopySize <= FromSize); |
308 | 0 | memmove(To + ToBeg, From + FromBeg, CopySize); |
309 | 0 | return ToSize; |
310 | 0 | } |
311 | | |
312 | | // Inserts part of From[0,ToSize) into To. |
313 | | // Returns new size of To on success or 0 on failure. |
314 | | size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize, |
315 | | uint8_t *To, size_t ToSize, |
316 | 0 | size_t MaxToSize) { |
317 | 0 | if (ToSize >= MaxToSize) return 0; |
318 | 0 | size_t AvailableSpace = MaxToSize - ToSize; |
319 | 0 | size_t MaxCopySize = std::min(AvailableSpace, FromSize); |
320 | 0 | size_t CopySize = Rand(MaxCopySize) + 1; |
321 | 0 | size_t FromBeg = Rand(FromSize - CopySize + 1); |
322 | 0 | assert(FromBeg + CopySize <= FromSize); |
323 | 0 | size_t ToInsertPos = Rand(ToSize + 1); |
324 | 0 | assert(ToInsertPos + CopySize <= MaxToSize); |
325 | 0 | size_t TailSize = ToSize - ToInsertPos; |
326 | 0 | if (To == From) { |
327 | 0 | MutateInPlaceHere.resize(MaxToSize); |
328 | 0 | memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize); |
329 | 0 | memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); |
330 | 0 | memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize); |
331 | 0 | } else { |
332 | 0 | memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); |
333 | 0 | memmove(To + ToInsertPos, From + FromBeg, CopySize); |
334 | 0 | } |
335 | 0 | return ToSize + CopySize; |
336 | 0 | } |
337 | | |
338 | | size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size, |
339 | 0 | size_t MaxSize) { |
340 | 0 | if (Size > MaxSize || Size == 0) return 0; |
341 | 0 | // If Size == MaxSize, `InsertPartOf(...)` will |
342 | 0 | // fail so there's no point using it in this case. |
343 | 0 | if (Size == MaxSize || Rand.RandBool()) |
344 | 0 | return CopyPartOf(Data, Size, Data, Size); |
345 | 0 | else |
346 | 0 | return InsertPartOf(Data, Size, Data, Size, MaxSize); |
347 | 0 | } |
348 | | |
349 | | size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, |
350 | 0 | size_t MaxSize) { |
351 | 0 | if (Size > MaxSize) return 0; |
352 | 0 | size_t B = Rand(Size); |
353 | 0 | while (B < Size && !isdigit(Data[B])) B++; |
354 | 0 | if (B == Size) return 0; |
355 | 0 | size_t E = B; |
356 | 0 | while (E < Size && isdigit(Data[E])) E++; |
357 | 0 | assert(B < E); |
358 | 0 | // now we have digits in [B, E). |
359 | 0 | // strtol and friends don't accept non-zero-teminated data, parse it manually. |
360 | 0 | uint64_t Val = Data[B] - '0'; |
361 | 0 | for (size_t i = B + 1; i < E; i++) |
362 | 0 | Val = Val * 10 + Data[i] - '0'; |
363 | 0 |
|
364 | 0 | // Mutate the integer value. |
365 | 0 | switch(Rand(5)) { |
366 | 0 | case 0: Val++; break; |
367 | 0 | case 1: Val--; break; |
368 | 0 | case 2: Val /= 2; break; |
369 | 0 | case 3: Val *= 2; break; |
370 | 0 | case 4: Val = Rand(Val * Val); break; |
371 | 0 | default: assert(0); |
372 | 0 | } |
373 | 0 | // Just replace the bytes with the new ones, don't bother moving bytes. |
374 | 0 | for (size_t i = B; i < E; i++) { |
375 | 0 | size_t Idx = E + B - i - 1; |
376 | 0 | assert(Idx >= B && Idx < E); |
377 | 0 | Data[Idx] = (Val % 10) + '0'; |
378 | 0 | Val /= 10; |
379 | 0 | } |
380 | 0 | return Size; |
381 | 0 | } |
382 | | |
383 | | template<class T> |
384 | 0 | size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { |
385 | 0 | if (Size < sizeof(T)) return 0; |
386 | 0 | size_t Off = Rand(Size - sizeof(T) + 1); |
387 | 0 | assert(Off + sizeof(T) <= Size); |
388 | 0 | T Val; |
389 | 0 | if (Off < 64 && !Rand(4)) { |
390 | 0 | Val = Size; |
391 | 0 | if (Rand.RandBool()) |
392 | 0 | Val = Bswap(Val); |
393 | 0 | } else { |
394 | 0 | memcpy(&Val, Data + Off, sizeof(Val)); |
395 | 0 | T Add = Rand(21); |
396 | 0 | Add -= 10; |
397 | 0 | if (Rand.RandBool()) |
398 | 0 | Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. |
399 | 0 | else |
400 | 0 | Val = Val + Add; // Add assuming current endiannes. |
401 | 0 | if (Add == 0 || Rand.RandBool()) // Maybe negate. |
402 | 0 | Val = -Val; |
403 | 0 | } |
404 | 0 | memcpy(Data + Off, &Val, sizeof(Val)); |
405 | 0 | return Size; |
406 | 0 | } Unexecuted instantiation: unsigned long fuzzer::ChangeBinaryInteger<unsigned long>(unsigned char*, unsigned long, fuzzer::Random&) Unexecuted instantiation: unsigned long fuzzer::ChangeBinaryInteger<unsigned int>(unsigned char*, unsigned long, fuzzer::Random&) Unexecuted instantiation: unsigned long fuzzer::ChangeBinaryInteger<unsigned short>(unsigned char*, unsigned long, fuzzer::Random&) Unexecuted instantiation: unsigned long fuzzer::ChangeBinaryInteger<unsigned char>(unsigned char*, unsigned long, fuzzer::Random&) |
407 | | |
408 | | size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data, |
409 | | size_t Size, |
410 | 0 | size_t MaxSize) { |
411 | 0 | if (Size > MaxSize) return 0; |
412 | 0 | switch (Rand(4)) { |
413 | 0 | case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand); |
414 | 0 | case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand); |
415 | 0 | case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand); |
416 | 0 | case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand); |
417 | 0 | default: assert(0); |
418 | 0 | } |
419 | 0 | return 0; |
420 | 0 | } |
421 | | |
422 | | size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, |
423 | 0 | size_t MaxSize) { |
424 | 0 | if (Size > MaxSize) return 0; |
425 | 0 | if (!Corpus || Corpus->size() < 2 || Size == 0) return 0; |
426 | 0 | size_t Idx = Rand(Corpus->size()); |
427 | 0 | const Unit &O = (*Corpus)[Idx]; |
428 | 0 | if (O.empty()) return 0; |
429 | 0 | MutateInPlaceHere.resize(MaxSize); |
430 | 0 | auto &U = MutateInPlaceHere; |
431 | 0 | size_t NewSize = 0; |
432 | 0 | switch(Rand(3)) { |
433 | 0 | case 0: |
434 | 0 | NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size()); |
435 | 0 | break; |
436 | 0 | case 1: |
437 | 0 | NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize); |
438 | 0 | if (!NewSize) |
439 | 0 | NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); |
440 | 0 | break; |
441 | 0 | case 2: |
442 | 0 | NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); |
443 | 0 | break; |
444 | 0 | default: assert(0); |
445 | 0 | } |
446 | 0 | assert(NewSize > 0 && "CrossOver returned empty unit"); |
447 | 0 | assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); |
448 | 0 | memcpy(Data, U.data(), NewSize); |
449 | 0 | return NewSize; |
450 | 0 | } |
451 | | |
452 | 0 | void MutationDispatcher::StartMutationSequence() { |
453 | 0 | CurrentMutatorSequence.clear(); |
454 | 0 | CurrentDictionaryEntrySequence.clear(); |
455 | 0 | } |
456 | | |
457 | | // Copy successful dictionary entries to PersistentAutoDictionary. |
458 | 0 | void MutationDispatcher::RecordSuccessfulMutationSequence() { |
459 | 0 | for (auto DE : CurrentDictionaryEntrySequence) { |
460 | 0 | // PersistentAutoDictionary.AddWithSuccessCountOne(DE); |
461 | 0 | DE->IncSuccessCount(); |
462 | 0 | assert(DE->GetW().size()); |
463 | 0 | // Linear search is fine here as this happens seldom. |
464 | 0 | if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) |
465 | 0 | PersistentAutoDictionary.push_back({DE->GetW(), 1}); |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | 3 | void MutationDispatcher::PrintRecommendedDictionary() { |
470 | 3 | Vector<DictionaryEntry> V; |
471 | 3 | for (auto &DE : PersistentAutoDictionary) |
472 | 0 | if (!ManualDictionary.ContainsWord(DE.GetW())) |
473 | 0 | V.push_back(DE); |
474 | 3 | if (V.empty()) return; |
475 | 0 | Printf("###### Recommended dictionary. ######\n"); |
476 | 0 | for (auto &DE: V) { |
477 | 0 | assert(DE.GetW().size()); |
478 | 0 | Printf("\""); |
479 | 0 | PrintASCII(DE.GetW(), "\""); |
480 | 0 | Printf(" # Uses: %zd\n", DE.GetUseCount()); |
481 | 0 | } |
482 | 0 | Printf("###### End of recommended dictionary. ######\n"); |
483 | 0 | } |
484 | | |
485 | 0 | void MutationDispatcher::PrintMutationSequence() { |
486 | 0 | Printf("MS: %zd ", CurrentMutatorSequence.size()); |
487 | 0 | for (auto M : CurrentMutatorSequence) |
488 | 0 | Printf("%s-", M.Name); |
489 | 0 | if (!CurrentDictionaryEntrySequence.empty()) { |
490 | 0 | Printf(" DE: "); |
491 | 0 | for (auto DE : CurrentDictionaryEntrySequence) { |
492 | 0 | Printf("\""); |
493 | 0 | PrintASCII(DE->GetW(), "\"-"); |
494 | 0 | } |
495 | 0 | } |
496 | 0 | } |
497 | | |
498 | 0 | size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { |
499 | 0 | return MutateImpl(Data, Size, MaxSize, Mutators); |
500 | 0 | } |
501 | | |
502 | | size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, |
503 | 0 | size_t MaxSize) { |
504 | 0 | return MutateImpl(Data, Size, MaxSize, DefaultMutators); |
505 | 0 | } |
506 | | |
507 | | // Mutates Data in place, returns new size. |
508 | | size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, |
509 | | size_t MaxSize, |
510 | 0 | Vector<Mutator> &Mutators) { |
511 | 0 | assert(MaxSize > 0); |
512 | 0 | // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), |
513 | 0 | // in which case they will return 0. |
514 | 0 | // Try several times before returning un-mutated data. |
515 | 0 | for (int Iter = 0; Iter < 100; Iter++) { |
516 | 0 | auto M = Mutators[Rand(Mutators.size())]; |
517 | 0 | size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); |
518 | 0 | if (NewSize && NewSize <= MaxSize) { |
519 | 0 | if (Options.OnlyASCII) |
520 | 0 | ToASCII(Data, NewSize); |
521 | 0 | CurrentMutatorSequence.push_back(M); |
522 | 0 | return NewSize; |
523 | 0 | } |
524 | 0 | } |
525 | 0 | *Data = ' '; |
526 | 0 | return 1; // Fallback, should not happen frequently. |
527 | 0 | } |
528 | | |
529 | | // Mask represents the set of Data bytes that are worth mutating. |
530 | | size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size, |
531 | | size_t MaxSize, |
532 | 0 | const Vector<uint8_t> &Mask) { |
533 | 0 | assert(Size <= Mask.size()); |
534 | 0 | // * Copy the worthy bytes into a temporary array T |
535 | 0 | // * Mutate T |
536 | 0 | // * Copy T back. |
537 | 0 | // This is totally unoptimized. |
538 | 0 | auto &T = MutateWithMaskTemp; |
539 | 0 | if (T.size() < Size) |
540 | 0 | T.resize(Size); |
541 | 0 | size_t OneBits = 0; |
542 | 0 | for (size_t I = 0; I < Size; I++) |
543 | 0 | if (Mask[I]) |
544 | 0 | T[OneBits++] = Data[I]; |
545 | 0 |
|
546 | 0 | assert(!T.empty()); |
547 | 0 | size_t NewSize = Mutate(T.data(), OneBits, OneBits); |
548 | 0 | assert(NewSize <= OneBits); |
549 | 0 | (void)NewSize; |
550 | 0 | // Even if NewSize < OneBits we still use all OneBits bytes. |
551 | 0 | for (size_t I = 0, J = 0; I < Size; I++) |
552 | 0 | if (Mask[I]) |
553 | 0 | Data[I] = T[J++]; |
554 | 0 | return Size; |
555 | 0 | } |
556 | | |
557 | 0 | void MutationDispatcher::AddWordToManualDictionary(const Word &W) { |
558 | 0 | ManualDictionary.push_back( |
559 | 0 | {W, std::numeric_limits<size_t>::max()}); |
560 | 0 | } |
561 | | |
562 | | } // namespace fuzzer |