VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fuzz/fuzz.cpp@ 80346

Last change on this file since 80346 was 77758, checked in by vboxsync, 6 years ago

Runtime/common/fuzz: Updates, add possiblity to dump the recorded target state and make it configurable what to include when comparing target states for equality

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.3 KB
Line 
1/* $Id: fuzz.cpp 77758 2019-03-18 13:17:30Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, core.
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/fuzz.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/critsect.h>
38#include <iprt/ctype.h>
39#include <iprt/dir.h>
40#include <iprt/err.h>
41#include <iprt/file.h>
42#include <iprt/list.h>
43#include <iprt/md5.h>
44#include <iprt/mem.h>
45#include <iprt/path.h>
46#include <iprt/rand.h>
47#include <iprt/semaphore.h>
48#include <iprt/string.h>
49#include <iprt/time.h>
50#include <iprt/vfs.h>
51
52
53#define RTFUZZCTX_MAGIC UINT32_C(0xdeadc0de) /** @todo */
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59/** Pointer to the internal fuzzer state. */
60typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
61/** Pointer to a fuzzed mutation. */
62typedef struct RTFUZZMUTATION *PRTFUZZMUTATION;
63/** Pointer to a fuzzed mutation pointer. */
64typedef PRTFUZZMUTATION *PPRTFUZZMUTATION;
65/** Pointer to a const mutation. */
66typedef const struct RTFUZZMUTATION *PCRTFUZZMUTATION;
67
68
69/**
70 * Mutator class.
71 */
72typedef enum RTFUZZMUTATORCLASS
73{
74 /** Invalid class, do not use. */
75 RTFUZZMUTATORCLASS_INVALID = 0,
76 /** Mutator operates on single bits. */
77 RTFUZZMUTATORCLASS_BITS,
78 /** Mutator operates on bytes (single or multiple). */
79 RTFUZZMUTATORCLASS_BYTES,
80 /** Mutator interpretes data as integers and operates on them. */
81 RTFUZZMUTATORCLASS_INTEGERS,
82 /** Mutator uses multiple mutations to create new mutations. */
83 RTFUZZMUTATORCLASS_MUTATORS,
84 /** 32bit hack. */
85 RTFUZZMUTATORCLASS_32BIT_HACK = 0x7fffffff
86} RTFUZZMUTATORCLASS;
87
88
89/**
90 * Mutator preparation callback.
91 *
92 * @returns IPRT status code.
93 * @param pThis The fuzzer context instance.
94 * @param offStart Where the mutation should start.
95 * @param pMutationParent The parent mutation to start working from.
96 * @param ppMutation Where to store the created mutation on success.
97 */
98typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATORPREP(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
99 PPRTFUZZMUTATION ppMutation);
100/** Pointer to a mutator preparation callback. */
101typedef FNRTFUZZCTXMUTATORPREP *PFNRTFUZZCTXMUTATORPREP;
102
103
104/**
105 * Mutator execution callback.
106 *
107 * @returns IPRT status code.
108 * @param pThis The fuzzer context instance.
109 * @param pMutation The mutation to work on.
110 * @param pvMutation Mutation dependent data.
111 * @param pbBuf The buffer to work on.
112 * @param cbBuf Size of the remaining buffer.
113 */
114typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOREXEC(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
115 uint8_t *pbBuf, size_t cbBuf);
116/** Pointer to a mutator execution callback. */
117typedef FNRTFUZZCTXMUTATOREXEC *PFNRTFUZZCTXMUTATOREXEC;
118
119
120/**
121 * Mutator export callback.
122 *
123 * @returns IPRT status code.
124 * @param pThis The fuzzer context instance.
125 * @param pMutation The mutation to work on.
126 * @param pvMutation Mutation dependent data.
127 * @param pfnExport The export callback.
128 * @param pvUser Opaque user data to pass to the export callback.
129 */
130typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOREXPORT(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
131 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
132/** Pointer to a mutator export callback. */
133typedef FNRTFUZZCTXMUTATOREXPORT *PFNRTFUZZCTXMUTATOREXPORT;
134
135
136/**
137 * Mutator import callback.
138 *
139 * @returns IPRT status code.
140 * @param pThis The fuzzer context instance.
141 * @param pMutation The mutation to work on.
142 * @param pvMutation Mutation dependent data.
143 * @param pfnExport The import callback.
144 * @param pvUser Opaque user data to pass to the import callback.
145 */
146typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATORIMPORT(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
147 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
148/** Pointer to a mutator import callback. */
149typedef FNRTFUZZCTXMUTATORIMPORT *PFNRTFUZZCTXMUTATORIMPORT;
150
151
152/**
153 * A fuzzing mutator descriptor.
154 */
155typedef struct RTFUZZMUTATOR
156{
157 /** Id of the mutator. */
158 const char *pszId;
159 /** Mutator description. */
160 const char *pszDesc;
161 /** Mutator index. */
162 uint32_t uMutator;
163 /** Mutator class. */
164 RTFUZZMUTATORCLASS enmClass;
165 /** Additional flags for the mutator, controlling the behavior. */
166 uint64_t fFlags;
167 /** The preparation callback. */
168 PFNRTFUZZCTXMUTATORPREP pfnPrep;
169 /** The execution callback. */
170 PFNRTFUZZCTXMUTATOREXEC pfnExec;
171 /** The export callback. */
172 PFNRTFUZZCTXMUTATOREXPORT pfnExport;
173 /** The import callback. */
174 PFNRTFUZZCTXMUTATORIMPORT pfnImport;
175} RTFUZZMUTATOR;
176/** Pointer to a fuzzing mutator descriptor. */
177typedef RTFUZZMUTATOR *PRTFUZZMUTATOR;
178/** Pointer to a const fuzzing mutator descriptor. */
179typedef const RTFUZZMUTATOR *PCRTFUZZMUTATOR;
180
181/** The special corpus mutator. */
182#define RTFUZZMUTATOR_ID_CORPUS UINT32_C(0xffffffff)
183
184/** Mutator always works from the end of the buffer (no starting offset generation). */
185#define RTFUZZMUTATOR_F_END_OF_BUF RT_BIT_64(0)
186/** Default flags. */
187#define RTFUZZMUTATOR_F_DEFAULT (0)
188
189
190/**
191 * A fuzzed mutation.
192 */
193typedef struct RTFUZZMUTATION
194{
195 /** The AVL tree core. */
196 AVLU64NODECORE Core;
197 /** The list node if the mutation has the mutated
198 * data allocated. */
199 RTLISTNODE NdAlloc;
200 /** Magic identifying this structure. */
201 uint32_t u32Magic;
202 /** Reference counter. */
203 volatile uint32_t cRefs;
204 /** The fuzzer this mutation belongs to. */
205 PRTFUZZCTXINT pFuzzer;
206 /** Parent mutation (no reference is held), NULL means root or original data. */
207 PRTFUZZMUTATION pMutationParent;
208 /** Mutation level. */
209 uint32_t iLvl;
210 /** The mutator causing this mutation, NULL if original input data. */
211 PCRTFUZZMUTATOR pMutator;
212 /** Byte offset where the mutation starts. */
213 uint64_t offMutation;
214 /** Size of the generated input data in bytes after the mutation was applied. */
215 size_t cbInput;
216 /** Size of the mutation dependent data. */
217 size_t cbMutation;
218 /** Size allocated for the input. */
219 size_t cbAlloc;
220 /** Pointer to the input data if created. */
221 void *pvInput;
222 /** Flag whether the mutation is contained in the tree of the context. */
223 bool fInTree;
224 /** Flag whether the mutation input data is cached. */
225 bool fCached;
226 /** Mutation dependent data, variable in size. */
227 uint8_t abMutation[1];
228} RTFUZZMUTATION;
229
230
231/**
232 * A fuzzing input seed.
233 */
234typedef struct RTFUZZINPUTINT
235{
236 /** Magic identifying this structure. */
237 uint32_t u32Magic;
238 /** Reference counter. */
239 volatile uint32_t cRefs;
240 /** The fuzzer this input belongs to. */
241 PRTFUZZCTXINT pFuzzer;
242 /** The top mutation to work from (reference held). */
243 PRTFUZZMUTATION pMutationTop;
244 /** Fuzzer context type dependent data. */
245 union
246 {
247 /** Blob data. */
248 struct
249 {
250 /** Pointer to the input data if created. */
251 void *pvInput;
252 } Blob;
253 /** Stream state. */
254 struct
255 {
256 /** Number of bytes seen so far. */
257 size_t cbSeen;
258 } Stream;
259 } u;
260} RTFUZZINPUTINT;
261/** Pointer to the internal input state. */
262typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
263/** Pointer to an internal input state pointer. */
264typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
265
266
267/**
268 * The fuzzer state.
269 */
270typedef struct RTFUZZCTXINT
271{
272 /** Magic value for identification. */
273 uint32_t u32Magic;
274 /** Reference counter. */
275 volatile uint32_t cRefs;
276 /** The random number generator. */
277 RTRAND hRand;
278 /** Fuzzing context type. */
279 RTFUZZCTXTYPE enmType;
280 /** Semaphore protecting the mutations tree. */
281 RTSEMRW hSemRwMutations;
282 /** The AVL tree for indexing the mutations (keyed by counter). */
283 AVLU64TREE TreeMutations;
284 /** Number of inputs currently in the tree. */
285 volatile uint64_t cMutations;
286 /** The maximum size of one input seed to generate. */
287 size_t cbInputMax;
288 /** Behavioral flags. */
289 uint32_t fFlagsBehavioral;
290 /** Number of enabled mutators. */
291 uint32_t cMutators;
292 /** Pointer to the mutator descriptors. */
293 PRTFUZZMUTATOR paMutators;
294 /** Maximum amount of bytes of mutated inputs to cache. */
295 size_t cbMutationsAllocMax;
296 /** Current amount of bytes of cached mutated inputs. */
297 size_t cbMutationsAlloc;
298 /** List of mutators having data allocated currently. */
299 RTLISTANCHOR LstMutationsAlloc;
300 /** Critical section protecting the allocation list. */
301 RTCRITSECT CritSectAlloc;
302 /** Total number of bytes of memory currently allocated in total for this context. */
303 volatile size_t cbMemTotal;
304} RTFUZZCTXINT;
305
306
307/**
308 * The fuzzer state to be exported - all members are stored in little endian form.
309 */
310typedef struct RTFUZZCTXSTATE
311{
312 /** Magic value for identification. */
313 uint32_t u32Magic;
314 /** Context type. */
315 uint32_t uCtxType;
316 /** Size of the PRNG state following in bytes. */
317 uint32_t cbPrng;
318 /** Number of mutator descriptors following. */
319 uint32_t cMutators;
320 /** Number of mutation descriptors following. */
321 uint32_t cMutations;
322 /** Behavioral flags. */
323 uint32_t fFlagsBehavioral;
324 /** Maximum input size to generate. */
325 uint64_t cbInputMax;
326} RTFUZZCTXSTATE;
327/** Pointer to a fuzzing context state. */
328typedef RTFUZZCTXSTATE *PRTFUZZCTXSTATE;
329
330/** BLOB context type. */
331#define RTFUZZCTX_STATE_TYPE_BLOB UINT32_C(0)
332/** Stream context type. */
333#define RTFUZZCTX_STATE_TYPE_STREAM UINT32_C(1)
334
335
336/**
337 * The fuzzer mutation state to be exported - all members are stored in little endian form.
338 */
339typedef struct RTFUZZMUTATIONSTATE
340{
341 /** The mutation identifier. */
342 uint64_t u64Id;
343 /** The mutation identifier of the parent, 0 for no parent. */
344 uint64_t u64IdParent;
345 /** The byte offset where the mutation starts. */
346 uint64_t u64OffMutation;
347 /** Size of input data after mutation was applied. */
348 uint64_t cbInput;
349 /** Size of mutation dependent data following. */
350 uint64_t cbMutation;
351 /** The mutator ID. */
352 uint32_t u32IdMutator;
353 /** The mutation level. */
354 uint32_t iLvl;
355 /** Magic value for identification. */
356 uint32_t u32Magic;
357} RTFUZZMUTATIONSTATE;
358
359
360/**
361 * Fuzzing context memory header.
362 */
363typedef struct RTFUZZMEMHDR
364{
365 /** Size of the memory area following. */
366 size_t cb;
367#if HC_ARCH_BITS == 32
368 /** Some padding. */
369 uint32_t uPadding0;
370#elif HC_ARCH_BITS == 64
371#else
372 /** Some padding. */
373 uint64_t uPadding0;
374# error "Port me"
375#endif
376} RTFUZZMEMHDR;
377/** Pointer to a memory header. */
378typedef RTFUZZMEMHDR *PRTFUZZMEMHDR;
379
380
381/**
382 * Fuzzing context export AVL arguments.
383 */
384typedef struct RTFUZZEXPORTARGS
385{
386 /** Pointer to the export callback. */
387 PFNRTFUZZCTXEXPORT pfnExport;
388 /** Opaque user data to pass to the callback. */
389 void *pvUser;
390} RTFUZZEXPORTARGS;
391/** Pointer to the export arguments. */
392typedef RTFUZZEXPORTARGS *PRTFUZZEXPORTARGS;
393/** Pointer to the constant export arguments. */
394typedef const RTFUZZEXPORTARGS *PCRTFUZZEXPORTARGS;
395
396
397/**
398 * Integer replacing mutator additional data.
399 */
400typedef struct RTFUZZMUTATORINTEGER
401{
402 /** The integer class. */
403 uint8_t uIntClass;
404 /** Flag whether to do a byte swap. */
405 bool fByteSwap;
406 /** The index into the class specific array. */
407 uint16_t idxInt;
408} RTFUZZMUTATORINTEGER;
409/** Pointer to additional integer replacing mutator data. */
410typedef RTFUZZMUTATORINTEGER *PRTFUZZMUTATORINTEGER;
411/** Pointer to constant additional integer replacing mutator data. */
412typedef const RTFUZZMUTATORINTEGER *PCRTFUZZMUTATORINTEGER;
413
414
415/*********************************************************************************************************************************
416* Internal Functions *
417*********************************************************************************************************************************/
418static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
419 PPRTFUZZMUTATION ppMutation);
420static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
421 PPRTFUZZMUTATION ppMutation);
422static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
423 PPRTFUZZMUTATION ppMutation);
424static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
425 PPRTFUZZMUTATION ppMutation);
426static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
427 PPRTFUZZMUTATION ppMutation);
428static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
429 PPRTFUZZMUTATION ppMutation);
430static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
431 PPRTFUZZMUTATION ppMutation);
432static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
433 PPRTFUZZMUTATION ppMutation);
434
435static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
436 uint8_t *pbBuf, size_t cbBuf);
437static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
438 uint8_t *pbBuf, size_t cbBuf);
439static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
440 uint8_t *pbBuf, size_t cbBuf);
441static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
442 uint8_t *pbBuf, size_t cbBuf);
443static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
444 uint8_t *pbBuf, size_t cbBuf);
445static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
446 uint8_t *pbBuf, size_t cbBuf);
447static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
448 uint8_t *pbBuf, size_t cbBuf);
449static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
450 uint8_t *pbBuf, size_t cbBuf);
451static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
452 uint8_t *pbBuf, size_t cbBuf);
453
454static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
455 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
456static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
457 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
458
459static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
460 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
461static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverImport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
462 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
463
464
465/*********************************************************************************************************************************
466* Global Variables *
467*********************************************************************************************************************************/
468
469/** Signed 8bit interesting values. */
470static int8_t s_ai8Interesting[] = { INT8_MIN, INT8_MIN + 1, -1, 0, 1, INT8_MAX - 1, INT8_MAX };
471/** Unsigned 8bit interesting values. */
472static uint8_t s_au8Interesting[] = { 0, 1, UINT8_MAX - 1, UINT8_MAX };
473/** Signed 16bit interesting values. */
474static int16_t s_ai16Interesting[] = { INT16_MIN, INT16_MIN + 1, -1, 0, 1, INT16_MAX - 1, INT16_MAX };
475/** Unsigned 16bit interesting values. */
476static uint16_t s_au16Interesting[] = { 0, 1, UINT16_MAX - 1, UINT16_MAX };
477/** Signed 32bit interesting values. */
478static int32_t s_ai32Interesting[] = { INT32_MIN, INT32_MIN + 1, -1, 0, 1, INT32_MAX - 1, INT32_MAX };
479/** Unsigned 32bit interesting values. */
480static uint32_t s_au32Interesting[] = { 0, 1, UINT32_MAX - 1, UINT32_MAX };
481/** Signed 64bit interesting values. */
482static int64_t s_ai64Interesting[] = { INT64_MIN, INT64_MIN + 1, -1, 0, 1, INT64_MAX - 1, INT64_MAX };
483/** Unsigned 64bit interesting values. */
484static uint64_t s_au64Interesting[] = { 0, 1, UINT64_MAX - 1, UINT64_MAX };
485
486
487/**
488 * The special corpus mutator for the original data.
489 */
490static RTFUZZMUTATOR const g_MutatorCorpus =
491{
492 /** pszId */
493 "Corpus",
494 /** pszDesc */
495 "Special mutator, which is assigned to the initial corpus",
496 /** uMutator. */
497 RTFUZZMUTATOR_ID_CORPUS,
498 /** enmClass. */
499 RTFUZZMUTATORCLASS_BYTES,
500 /** fFlags */
501 RTFUZZMUTATOR_F_DEFAULT,
502 /** pfnPrep */
503 NULL,
504 /** pfnExec */
505 rtFuzzCtxMutatorCorpusExec,
506 /** pfnExport */
507 rtFuzzCtxMutatorExportDefault,
508 /** pfnImport */
509 rtFuzzCtxMutatorImportDefault
510};
511
512/**
513 * Array of all available mutators.
514 */
515static RTFUZZMUTATOR const g_aMutators[] =
516{
517 /* pszId pszDesc uMutator enmClass fFlags pfnPrep pfnExec pfnExport pfnImport */
518 { "BitFlip", "Flips a single bit in the input", 0, RTFUZZMUTATORCLASS_BITS, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorBitFlipPrep, rtFuzzCtxMutatorBitFlipExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
519 { "ByteReplace", "Replaces a single byte in the input", 1, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteReplacePrep, rtFuzzCtxMutatorByteReplaceExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
520 { "ByteInsert", "Inserts a single byte sequence into the input", 2, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteInsertPrep, rtFuzzCtxMutatorByteInsertExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
521 { "ByteSeqIns", "Inserts a byte sequence in the input", 3, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteSequenceInsertAppendPrep, rtFuzzCtxMutatorByteSequenceInsertAppendExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
522 { "ByteSeqApp", "Appends a byte sequence to the input", 4, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_END_OF_BUF, rtFuzzCtxMutatorByteSequenceInsertAppendPrep, rtFuzzCtxMutatorByteSequenceInsertAppendExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
523 { "ByteDelete", "Deletes a single byte sequence from the input", 5, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteDeletePrep, rtFuzzCtxMutatorByteDeleteExec, NULL, NULL },
524 { "ByteSeqDel", "Deletes a byte sequence from the input", 6, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteSequenceDeletePrep, rtFuzzCtxMutatorByteSequenceDeleteExec, NULL, NULL },
525 { "IntReplace", "Replaces a possible integer with an interesting one", 7, RTFUZZMUTATORCLASS_INTEGERS, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorIntegerReplacePrep, rtFuzzCtxMutatorIntegerReplaceExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
526 { "MutCrossover", "Creates a crossover of two other mutations", 8, RTFUZZMUTATORCLASS_MUTATORS, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorCrossoverPrep, rtFuzzCtxMutatorCrossoverExec, rtFuzzCtxMutatorCrossoverExport, rtFuzzCtxMutatorCrossoverImport }
527};
528
529
530/**
531 * Allocates the given number of bytes.
532 *
533 * @returns Pointer to the allocated memory
534 * @param pThis The fuzzer context instance.
535 * @param cb How much to allocate.
536 */
537static void *rtFuzzCtxMemoryAlloc(PRTFUZZCTXINT pThis, size_t cb)
538{
539 AssertReturn(cb > 0, NULL);
540
541 PRTFUZZMEMHDR pMemHdr = (PRTFUZZMEMHDR)RTMemAllocZ(cb + sizeof(RTFUZZMEMHDR));
542 if (RT_LIKELY(pMemHdr))
543 {
544 pMemHdr->cb = cb;
545 size_t cbIgn = ASMAtomicAddZ(&pThis->cbMemTotal, cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
546 return pMemHdr + 1;
547 }
548
549 return NULL;
550}
551
552
553/**
554 * Frees the given memory.
555 *
556 * @returns nothing.
557 * @param pThis The fuzzer context instance.
558 * @param pv Pointer to the memory area to free.
559 */
560static void rtFuzzCtxMemoryFree(PRTFUZZCTXINT pThis, void *pv)
561{
562 AssertReturnVoid(pv != NULL);
563 PRTFUZZMEMHDR pMemHdr = ((PRTFUZZMEMHDR)pv) - 1;
564
565 size_t cbIgn = ASMAtomicSubZ(&pThis->cbMemTotal, pMemHdr->cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
566 RTMemFree(pMemHdr);
567}
568
569
570/**
571 * Frees the cached inputs until the given amount is free.
572 *
573 * @returns Whether the amount of memory is free.
574 * @param pThis The fuzzer context instance.
575 * @param cb How many bytes to reclaim
576 */
577static bool rtFuzzCtxMutationAllocReclaim(PRTFUZZCTXINT pThis, size_t cb)
578{
579 while ( !RTListIsEmpty(&pThis->LstMutationsAlloc)
580 && pThis->cbMutationsAlloc + cb > pThis->cbMutationsAllocMax)
581 {
582 PRTFUZZMUTATION pMutation = RTListGetLast(&pThis->LstMutationsAlloc, RTFUZZMUTATION, NdAlloc);
583 AssertPtr(pMutation);
584 AssertPtr(pMutation->pvInput);
585
586 rtFuzzCtxMemoryFree(pThis, pMutation->pvInput);
587 pThis->cbMutationsAlloc -= pMutation->cbAlloc;
588 pMutation->pvInput = NULL;
589 pMutation->cbAlloc = 0;
590 pMutation->fCached = false;
591 RTListNodeRemove(&pMutation->NdAlloc);
592 }
593
594 return pThis->cbMutationsAlloc + cb <= pThis->cbMutationsAllocMax;
595}
596
597
598/**
599 * Updates the cache status of the given mutation.
600 *
601 * @returns nothing.
602 * @param pThis The fuzzer context instance.
603 * @param pMutation The mutation to update.
604 */
605static void rtFuzzCtxMutationMaybeEnterCache(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
606{
607 RTCritSectEnter(&pThis->CritSectAlloc);
608
609 /* Initial corpus mutations are not freed. */
610 if ( pMutation->pvInput
611 && pMutation->pMutator != &g_MutatorCorpus)
612 {
613 Assert(!pMutation->fCached);
614
615 if (rtFuzzCtxMutationAllocReclaim(pThis, pMutation->cbAlloc))
616 {
617 RTListPrepend(&pThis->LstMutationsAlloc, &pMutation->NdAlloc);
618 pThis->cbMutationsAlloc += pMutation->cbAlloc;
619 pMutation->fCached = true;
620 }
621 else
622 {
623 rtFuzzCtxMemoryFree(pThis, pMutation->pvInput);
624 pMutation->pvInput = NULL;
625 pMutation->cbAlloc = 0;
626 pMutation->fCached = false;
627 }
628 }
629 RTCritSectLeave(&pThis->CritSectAlloc);
630}
631
632
633/**
634 * Removes a cached mutation from the cache.
635 *
636 * @returns nothing.
637 * @param pThis The fuzzer context instance.
638 * @param pMutation The mutation to remove.
639 */
640static void rtFuzzCtxMutationCacheRemove(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
641{
642 RTCritSectEnter(&pThis->CritSectAlloc);
643 if (pMutation->fCached)
644 {
645 RTListNodeRemove(&pMutation->NdAlloc);
646 pThis->cbMutationsAlloc -= pMutation->cbAlloc;
647 pMutation->fCached = false;
648 }
649 RTCritSectLeave(&pThis->CritSectAlloc);
650}
651
652
653/**
654 * Destroys the given mutation.
655 *
656 * @returns nothing.
657 * @param pMutation The mutation to destroy.
658 */
659static void rtFuzzMutationDestroy(PRTFUZZMUTATION pMutation)
660{
661 if (pMutation->pvInput)
662 {
663 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation->pvInput);
664 if (pMutation->fCached)
665 {
666 RTCritSectEnter(&pMutation->pFuzzer->CritSectAlloc);
667 RTListNodeRemove(&pMutation->NdAlloc);
668 pMutation->pFuzzer->cbMutationsAlloc -= pMutation->cbAlloc;
669 RTCritSectLeave(&pMutation->pFuzzer->CritSectAlloc);
670 }
671 pMutation->pvInput = NULL;
672 pMutation->cbAlloc = 0;
673 pMutation->fCached = false;
674 }
675 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation);
676}
677
678
679/**
680 * Retains an external reference to the given mutation.
681 *
682 * @returns New reference count on success.
683 * @param pMutation The mutation to retain.
684 */
685static uint32_t rtFuzzMutationRetain(PRTFUZZMUTATION pMutation)
686{
687 uint32_t cRefs = ASMAtomicIncU32(&pMutation->cRefs);
688 AssertMsg( ( cRefs > 1
689 || pMutation->fInTree)
690 && cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
691
692 if (cRefs == 1)
693 rtFuzzCtxMutationCacheRemove(pMutation->pFuzzer, pMutation);
694 return cRefs;
695}
696
697
698/**
699 * Releases an external reference from the given mutation.
700 *
701 * @returns New reference count on success.
702 * @param pMutation The mutation to retain.
703 */
704static uint32_t rtFuzzMutationRelease(PRTFUZZMUTATION pMutation)
705{
706 uint32_t cRefs = ASMAtomicDecU32(&pMutation->cRefs);
707 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
708
709 if (cRefs == 0)
710 {
711 if (!pMutation->fInTree)
712 rtFuzzMutationDestroy(pMutation);
713 else
714 rtFuzzCtxMutationMaybeEnterCache(pMutation->pFuzzer, pMutation);
715 }
716
717 return cRefs;
718}
719
720
721/**
722 * Adds the given mutation to the corpus of the given fuzzer context.
723 *
724 * @returns IPRT status code.
725 * @param pThis The fuzzer context instance.
726 * @param pMutation The mutation to add.
727 */
728static int rtFuzzCtxMutationAdd(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
729{
730 int rc = VINF_SUCCESS;
731
732 pMutation->Core.Key = ASMAtomicIncU64(&pThis->cMutations);
733 rc = RTSemRWRequestWrite(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
734 AssertRC(rc); RT_NOREF(rc);
735 bool fIns = RTAvlU64Insert(&pThis->TreeMutations, &pMutation->Core);
736 Assert(fIns); RT_NOREF(fIns);
737 rc = RTSemRWReleaseWrite(pThis->hSemRwMutations);
738 AssertRC(rc); RT_NOREF(rc);
739
740 pMutation->fInTree = true;
741 return rc;
742}
743
744
745/**
746 * Locates the mutation with the given key.
747 *
748 * @returns Pointer to the mutation if found or NULL otherwise.
749 * @param pThis The fuzzer context instance.
750 * @param uKey The key to locate.
751 */
752static PRTFUZZMUTATION rtFuzzCtxMutationLocate(PRTFUZZCTXINT pThis, uint64_t uKey)
753{
754 int rc = RTSemRWRequestRead(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
755 AssertRC(rc); RT_NOREF(rc);
756
757 /*
758 * Using best fit getter here as there might be a racing mutation insertion and the mutation counter has increased
759 * already but the mutation is not yet in the tree.
760 */
761 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)RTAvlU64GetBestFit(&pThis->TreeMutations, uKey, false /*fAbove*/);
762 if (RT_LIKELY(pMutation))
763 rtFuzzMutationRetain(pMutation);
764
765 rc = RTSemRWReleaseRead(pThis->hSemRwMutations);
766 AssertRC(rc); RT_NOREF(rc);
767
768 return pMutation;
769}
770
771
772/**
773 * Returns a random mutation from the corpus of the given fuzzer context.
774 *
775 * @returns Pointer to a randomly picked mutation (reference count is increased).
776 * @param pThis The fuzzer context instance.
777 */
778static PRTFUZZMUTATION rtFuzzCtxMutationPickRnd(PRTFUZZCTXINT pThis)
779{
780 uint64_t idxMutation = RTRandAdvU64Ex(pThis->hRand, 1, ASMAtomicReadU64(&pThis->cMutations));
781 return rtFuzzCtxMutationLocate(pThis, idxMutation);
782}
783
784
785/**
786 * Creates a new mutation capable of holding the additional number of bytes.
787 *
788 * @returns Pointer to the newly created mutation or NULL if out of memory.
789 * @param pThis The fuzzer context instance.
790 * @param offMutation The starting offset for the mutation.
791 * @param pMutationParent The parent mutation, can be NULL.
792 * @param cbAdditional Additional number of bytes to allocate after the core structure.
793 * @param ppvMutation Where to store the pointer to the mutation dependent data on success.
794 */
795static PRTFUZZMUTATION rtFuzzMutationCreate(PRTFUZZCTXINT pThis, uint64_t offMutation, PRTFUZZMUTATION pMutationParent,
796 size_t cbAdditional, void **ppvMutation)
797{
798 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZMUTATION) + cbAdditional);
799 if (RT_LIKELY(pMutation))
800 {
801 pMutation->u32Magic = 0; /** @todo */
802 pMutation->pFuzzer = pThis;
803 pMutation->cRefs = 1;
804 pMutation->iLvl = 0;
805 pMutation->offMutation = offMutation;
806 pMutation->pMutationParent = pMutationParent;
807 pMutation->cbMutation = cbAdditional;
808 pMutation->fInTree = false;
809 pMutation->fCached = false;
810 pMutation->pvInput = NULL;
811 pMutation->cbInput = 0;
812 pMutation->cbAlloc = 0;
813
814 if (pMutationParent)
815 pMutation->iLvl = pMutationParent->iLvl + 1;
816 if (ppvMutation)
817 *ppvMutation = &pMutation->abMutation[0];
818 }
819
820 return pMutation;
821}
822
823
824/**
825 * Destroys the given fuzzer context freeing all allocated resources.
826 *
827 * @returns nothing.
828 * @param pThis The fuzzer context instance.
829 */
830static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
831{
832 RT_NOREF(pThis);
833}
834
835
836/**
837 * Creates the final input data applying all accumulated mutations.
838 *
839 * @returns IPRT status code.
840 * @param pMutation The mutation to finalize.
841 */
842static int rtFuzzMutationDataFinalize(PRTFUZZMUTATION pMutation)
843{
844 if (pMutation->pvInput)
845 return VINF_SUCCESS;
846
847 /* Traverse the mutations top to bottom and insert into the array. */
848 int rc = VINF_SUCCESS;
849 uint32_t idx = pMutation->iLvl + 1;
850 PRTFUZZMUTATION *papMutations = (PRTFUZZMUTATION *)RTMemTmpAlloc(idx * sizeof(PCRTFUZZMUTATION));
851 if (RT_LIKELY(papMutations))
852 {
853 PRTFUZZMUTATION pMutationCur = pMutation;
854 size_t cbAlloc = 0;
855
856 /*
857 * As soon as a mutation with allocated input data is encountered the insertion is
858 * stopped as it contains all necessary mutated inputs we can start from.
859 */
860 while (idx > 0)
861 {
862 rtFuzzMutationRetain(pMutationCur);
863 papMutations[idx - 1] = pMutationCur;
864 cbAlloc = RT_MAX(cbAlloc, pMutationCur->cbInput);
865 if (pMutationCur->pvInput)
866 {
867 idx--;
868 break;
869 }
870 pMutationCur = pMutationCur->pMutationParent;
871 idx--;
872 }
873
874 pMutation->cbAlloc = cbAlloc;
875 uint8_t *pbBuf = (uint8_t *)rtFuzzCtxMemoryAlloc(pMutation->pFuzzer, cbAlloc);
876 if (RT_LIKELY(pbBuf))
877 {
878 pMutation->pvInput = pbBuf;
879
880 /* Copy the initial input data. */
881 size_t cbInputNow = papMutations[idx]->cbInput;
882 memcpy(pbBuf, papMutations[idx]->pvInput, cbInputNow);
883 rtFuzzMutationRelease(papMutations[idx]);
884
885 for (uint32_t i = idx + 1; i < pMutation->iLvl + 1; i++)
886 {
887 PRTFUZZMUTATION pCur = papMutations[i];
888 pCur->pMutator->pfnExec(pCur->pFuzzer, pCur, (void *)&pCur->abMutation[0],
889 pbBuf + pCur->offMutation,
890 cbInputNow - pCur->offMutation);
891
892 cbInputNow = pCur->cbInput;
893 rtFuzzMutationRelease(pCur);
894 }
895
896 Assert(cbInputNow == pMutation->cbInput);
897 }
898 else
899 rc = VERR_NO_MEMORY;
900
901 RTMemTmpFree(papMutations);
902 }
903 else
904 rc = VERR_NO_MEMORY;
905
906 return rc;
907}
908
909
910/**
911 * Default mutator export callback (just writing the raw data).
912 */
913static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
914 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
915{
916 return pfnExport(pThis, pvMutation, pMutation->cbMutation, pvUser);
917}
918
919
920/**
921 * Default mutator import callback (just reading the raw data).
922 */
923static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
924 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
925{
926 return pfnImport(pThis, pvMutation, pMutation->cbMutation, NULL, pvUser);
927}
928
929
930static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
931 uint8_t *pbBuf, size_t cbBuf)
932{
933 RT_NOREF(pThis, cbBuf, pvMutation);
934 memcpy(pbBuf, pvMutation, pMutation->cbInput);
935 return VINF_SUCCESS;
936}
937
938
939/**
940 * Mutator callback - flips a single bit in the input.
941 */
942static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
943 PPRTFUZZMUTATION ppMutation)
944{
945 int rc = VINF_SUCCESS;
946 uint8_t *pidxBitFlip = 0;
947 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxBitFlip), (void **)&pidxBitFlip);
948 if (RT_LIKELY(pMutation))
949 {
950 pMutation->cbInput = pMutationParent->cbInput; /* Bit flips don't change the input size. */
951 *pidxBitFlip = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, sizeof(uint8_t) * 8 - 1);
952 *ppMutation = pMutation;
953 }
954 else
955 rc = VERR_NO_MEMORY;
956
957 return rc;
958}
959
960
961static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
962 uint8_t *pbBuf, size_t cbBuf)
963{
964 RT_NOREF(pThis, cbBuf, pMutation);
965 uint8_t idxBitFlip = *(uint8_t *)pvMutation;
966 ASMBitToggle(pbBuf, idxBitFlip);
967 return VINF_SUCCESS;
968}
969
970
971/**
972 * Mutator callback - replaces a single byte in the input.
973 */
974static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
975 PPRTFUZZMUTATION ppMutation)
976{
977 int rc = VINF_SUCCESS;
978 uint8_t *pbReplace = 0;
979 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pbReplace), (void **)&pbReplace);
980 if (RT_LIKELY(pMutation))
981 {
982 pMutation->cbInput = pMutationParent->cbInput; /* Byte replacements don't change the input size. */
983 RTRandAdvBytes(pThis->hRand, pbReplace, 1); /** @todo Filter out same values. */
984 *ppMutation = pMutation;
985 }
986 else
987 rc = VERR_NO_MEMORY;
988
989 return rc;
990}
991
992
993static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
994 uint8_t *pbBuf, size_t cbBuf)
995{
996 RT_NOREF(pThis, cbBuf, pMutation);
997 uint8_t bReplace = *(uint8_t *)pvMutation;
998 *pbBuf = bReplace;
999 return VINF_SUCCESS;
1000}
1001
1002
1003/**
1004 * Mutator callback - inserts a single byte into the input.
1005 */
1006static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1007 PPRTFUZZMUTATION ppMutation)
1008{
1009 int rc = VINF_SUCCESS;
1010 uint8_t *pbInsert = 0;
1011 if (pMutationParent->cbInput < pThis->cbInputMax)
1012 {
1013 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 1 /*cbAdditional*/, (void **)&pbInsert);
1014 if (RT_LIKELY(pMutation))
1015 {
1016 pMutation->cbInput = pMutationParent->cbInput + 1;
1017 RTRandAdvBytes(pThis->hRand, pbInsert, 1);
1018 *ppMutation = pMutation;
1019 }
1020 else
1021 rc = VERR_NO_MEMORY;
1022 }
1023
1024 return rc;
1025}
1026
1027
1028static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1029 uint8_t *pbBuf, size_t cbBuf)
1030{
1031 RT_NOREF(pThis, pMutation, pvMutation);
1032
1033 /* Just move the residual data one byte to the back. */
1034 memmove(pbBuf + 1, pbBuf, cbBuf);
1035 *pbBuf = *(uint8_t *)pvMutation;
1036 return VINF_SUCCESS;
1037}
1038
1039
1040/**
1041 * Mutator callback - inserts a byte sequence into the input.
1042 */
1043static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1044 PPRTFUZZMUTATION ppMutation)
1045{
1046 int rc = VINF_SUCCESS;
1047 if (pMutationParent->cbInput < pThis->cbInputMax)
1048 {
1049 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, pMutationParent->cbInput + 1, pThis->cbInputMax);
1050 size_t cbInsert = cbInputMutated - pMutationParent->cbInput;
1051 uint8_t *pbAdd = NULL;
1052
1053 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, cbInsert, (void **)&pbAdd);
1054 if (RT_LIKELY(pMutation))
1055 {
1056 pMutation->cbInput = cbInputMutated;
1057 RTRandAdvBytes(pThis->hRand, pbAdd, cbInsert);
1058 *ppMutation = pMutation;
1059 }
1060 else
1061 rc = VERR_NO_MEMORY;
1062 }
1063
1064 return rc;
1065}
1066
1067
1068static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1069 uint8_t *pbBuf, size_t cbBuf)
1070{
1071 RT_NOREF(pThis);
1072 size_t cbInsert = pMutation->cbInput - pMutation->pMutationParent->cbInput;
1073
1074 /* Move any remaining data to the end. */
1075 if (cbBuf)
1076 memmove(pbBuf + cbInsert, pbBuf, cbBuf);
1077
1078 memcpy(pbBuf, pvMutation, cbInsert);
1079 return VINF_SUCCESS;
1080}
1081
1082
1083/**
1084 * Mutator callback - deletes a single byte in the input.
1085 */
1086static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1087 PPRTFUZZMUTATION ppMutation)
1088{
1089 int rc = VINF_SUCCESS;
1090 if (pMutationParent->cbInput - offStart >= 1)
1091 {
1092 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
1093 if (RT_LIKELY(pMutation))
1094 {
1095 pMutation->cbInput = pMutationParent->cbInput - 1;
1096 *ppMutation = pMutation;
1097 }
1098 else
1099 rc = VERR_NO_MEMORY;
1100 }
1101
1102 return rc;
1103}
1104
1105
1106static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1107 uint8_t *pbBuf, size_t cbBuf)
1108{
1109 RT_NOREF(pThis, pMutation, pvMutation);
1110
1111 /* Just move the residual data to the front. */
1112 memmove(pbBuf, pbBuf + 1, cbBuf - 1);
1113 return VINF_SUCCESS;
1114}
1115
1116
1117/**
1118 * Mutator callback - deletes a byte sequence in the input.
1119 */
1120static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1121 PPRTFUZZMUTATION ppMutation)
1122{
1123 int rc = VINF_SUCCESS;
1124 if ( pMutationParent->cbInput > offStart
1125 && pMutationParent->cbInput > 1)
1126 {
1127 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, offStart, pMutationParent->cbInput - 1);
1128
1129 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
1130 if (RT_LIKELY(pMutation))
1131 {
1132 pMutation->cbInput = cbInputMutated;
1133 *ppMutation = pMutation;
1134 }
1135 else
1136 rc = VERR_NO_MEMORY;
1137 }
1138
1139 return rc;
1140}
1141
1142
1143static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1144 uint8_t *pbBuf, size_t cbBuf)
1145{
1146 RT_NOREF(pThis, pvMutation);
1147 Assert(pMutation->pMutationParent->cbInput > pMutation->cbInput);
1148 size_t cbDel = pMutation->pMutationParent->cbInput - pMutation->cbInput;
1149
1150 /* Just move the residual data to the front. */
1151 memmove(pbBuf, pbBuf + cbDel, cbBuf - cbDel);
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * Mutator callback - replaces a possible integer with something interesting.
1158 */
1159static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1160 PPRTFUZZMUTATION ppMutation)
1161{
1162 int rc = VINF_SUCCESS;
1163 PRTFUZZMUTATORINTEGER pMutInt = NULL;
1164 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pMutInt), (void **)&pMutInt);
1165 if (RT_LIKELY(pMutation))
1166 {
1167 size_t cbLeft = pMutationParent->cbInput - offStart;
1168 uint32_t uClassMax = 0;
1169
1170 switch (cbLeft)
1171 {
1172 case 1:
1173 uClassMax = 1;
1174 break;
1175 case 2:
1176 case 3:
1177 uClassMax = 3;
1178 break;
1179 case 4:
1180 case 5:
1181 case 6:
1182 case 7:
1183 uClassMax = 5;
1184 break;
1185 default:
1186 uClassMax = 7;
1187 break;
1188 }
1189
1190 pMutInt->uIntClass = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, uClassMax);
1191 pMutInt->fByteSwap = RT_BOOL(RTRandAdvU32Ex(pThis->hRand, 0, 1));
1192
1193 switch (pMutInt->uIntClass)
1194 {
1195 case 0:
1196 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai8Interesting) - 1);
1197 break;
1198 case 1:
1199 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au8Interesting) - 1);
1200 break;
1201 case 2:
1202 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai16Interesting) - 1);
1203 break;
1204 case 3:
1205 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au16Interesting) - 1);
1206 break;
1207 case 4:
1208 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai32Interesting) - 1);
1209 break;
1210 case 5:
1211 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au32Interesting) - 1);
1212 break;
1213 case 6:
1214 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai64Interesting) - 1);
1215 break;
1216 case 7:
1217 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au64Interesting) - 1);
1218 break;
1219 default:
1220 AssertReleaseFailed();
1221 }
1222
1223 pMutation->cbInput = pMutationParent->cbInput;
1224 *ppMutation = pMutation;
1225 }
1226 else
1227 rc = VERR_NO_MEMORY;
1228
1229 return rc;
1230}
1231
1232
1233static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1234 uint8_t *pbBuf, size_t cbBuf)
1235{
1236 RT_NOREF(pThis, pMutation, cbBuf);
1237 union
1238 {
1239 int8_t i8;
1240 uint8_t u8;
1241 int16_t i16;
1242 uint16_t u16;
1243 int32_t i32;
1244 uint32_t u32;
1245 int64_t i64;
1246 uint64_t u64;
1247 } Int;
1248 PCRTFUZZMUTATORINTEGER pMutInt = (PCRTFUZZMUTATORINTEGER)pvMutation;
1249 size_t cb = 0;
1250
1251 switch (pMutInt->uIntClass)
1252 {
1253 case 0:
1254 Int.i8 = s_ai8Interesting[pMutInt->idxInt];
1255 cb = 1;
1256 break;
1257 case 1:
1258 Int.u8 = s_au8Interesting[pMutInt->idxInt];
1259 cb = 1;
1260 break;
1261 case 2:
1262 Int.i16 = s_ai16Interesting[pMutInt->idxInt];
1263 cb = 2;
1264 if (pMutInt->fByteSwap)
1265 Int.u16 = RT_BSWAP_U16(Int.u16);
1266 break;
1267 case 3:
1268 Int.u16 = s_au16Interesting[pMutInt->idxInt];
1269 cb = 2;
1270 if (pMutInt->fByteSwap)
1271 Int.u16 = RT_BSWAP_U16(Int.u16);
1272 break;
1273 case 4:
1274 Int.i32 = s_ai32Interesting[pMutInt->idxInt];
1275 cb = 4;
1276 if (pMutInt->fByteSwap)
1277 Int.u32 = RT_BSWAP_U32(Int.u32);
1278 break;
1279 case 5:
1280 Int.u32 = s_au32Interesting[pMutInt->idxInt];
1281 cb = 4;
1282 if (pMutInt->fByteSwap)
1283 Int.u32 = RT_BSWAP_U32(Int.u32);
1284 break;
1285 case 6:
1286 Int.i64 = s_ai64Interesting[pMutInt->idxInt];
1287 cb = 8;
1288 if (pMutInt->fByteSwap)
1289 Int.u64 = RT_BSWAP_U64(Int.u64);
1290 break;
1291 case 7:
1292 Int.u64 = s_au64Interesting[pMutInt->idxInt];
1293 cb = 8;
1294 if (pMutInt->fByteSwap)
1295 Int.u64 = RT_BSWAP_U64(Int.u64);
1296 break;
1297 default:
1298 AssertReleaseFailed();
1299 }
1300
1301 memcpy(pbBuf, &Int, cb);
1302 return VINF_SUCCESS;
1303}
1304
1305
1306/**
1307 * Mutator callback - crosses over two mutations at the given point.
1308 */
1309static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1310 PPRTFUZZMUTATION ppMutation)
1311{
1312 int rc = VINF_SUCCESS;
1313
1314 if (pThis->cMutations > 1)
1315 {
1316 uint64_t *pidxMutCrossover = NULL;
1317 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxMutCrossover), (void **)&pidxMutCrossover);
1318 if (RT_LIKELY(pMutation))
1319 {
1320 uint32_t cTries = 10;
1321 PRTFUZZMUTATION pMutCrossover = NULL;
1322 /*
1323 * Pick a random mutation to crossover with (making sure it is not the current one
1324 * or the crossover point is beyond the end of input).
1325 */
1326 do
1327 {
1328 if (pMutCrossover)
1329 rtFuzzMutationRelease(pMutCrossover);
1330 pMutCrossover = rtFuzzCtxMutationPickRnd(pThis);
1331 cTries--;
1332 } while ( ( pMutCrossover == pMutationParent
1333 || offStart >= pMutCrossover->cbInput)
1334 && cTries > 0);
1335
1336 if (cTries)
1337 {
1338 pMutation->cbInput = pMutCrossover->cbInput;
1339 *pidxMutCrossover = pMutCrossover->Core.Key;
1340 *ppMutation = pMutation;
1341 }
1342 else
1343 rtFuzzMutationDestroy(pMutation);
1344
1345 rtFuzzMutationRelease(pMutCrossover);
1346 }
1347 else
1348 rc = VERR_NO_MEMORY;
1349 }
1350
1351 return rc;
1352}
1353
1354
1355static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1356 uint8_t *pbBuf, size_t cbBuf)
1357{
1358 RT_NOREF(cbBuf);
1359 uint64_t idxMutCrossover = *(uint64_t *)pvMutation;
1360
1361 PRTFUZZMUTATION pMutCrossover = rtFuzzCtxMutationLocate(pThis, idxMutCrossover);
1362 int rc = rtFuzzMutationDataFinalize(pMutCrossover);
1363 if (RT_SUCCESS(rc))
1364 {
1365 memcpy(pbBuf, (uint8_t *)pMutCrossover->pvInput + pMutation->offMutation,
1366 pMutCrossover->cbInput - pMutation->offMutation);
1367 rtFuzzMutationRelease(pMutCrossover);
1368 }
1369
1370 return rc;
1371}
1372
1373
1374static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1375 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1376{
1377 RT_NOREF(pMutation);
1378
1379 uint64_t idxMutCrossover = *(uint64_t *)pvMutation;
1380 idxMutCrossover = RT_H2LE_U64(idxMutCrossover);
1381 return pfnExport(pThis, &idxMutCrossover, sizeof(idxMutCrossover), pvUser);
1382}
1383
1384
1385static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverImport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
1386 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
1387{
1388 RT_NOREF(pMutation);
1389
1390 uint64_t uKey = 0;
1391 int rc = pfnImport(pThis, &uKey, sizeof(uKey), NULL, pvUser);
1392 if (RT_SUCCESS(rc))
1393 {
1394 uKey = RT_LE2H_U64(uKey);
1395 *(uint64_t *)pvMutation = uKey;
1396 }
1397
1398 return rc;
1399}
1400
1401
1402/**
1403 * Creates an empty fuzzing context.
1404 *
1405 * @returns IPRT status code.
1406 * @param ppThis Where to store the pointer to the internal fuzzing context instance on success.
1407 * @param enmType Fuzzing context type.
1408 */
1409static int rtFuzzCtxCreateEmpty(PRTFUZZCTXINT *ppThis, RTFUZZCTXTYPE enmType)
1410{
1411 int rc;
1412 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
1413 if (RT_LIKELY(pThis))
1414 {
1415 pThis->u32Magic = RTFUZZCTX_MAGIC;
1416 pThis->cRefs = 1;
1417 pThis->enmType = enmType;
1418 pThis->TreeMutations = NULL;
1419 pThis->cbInputMax = UINT32_MAX;
1420 pThis->cMutations = 0;
1421 pThis->fFlagsBehavioral = 0;
1422 pThis->cbMutationsAllocMax = _1G;
1423 pThis->cbMemTotal = 0;
1424 RTListInit(&pThis->LstMutationsAlloc);
1425
1426 /* Copy the default mutator descriptors over. */
1427 pThis->paMutators = (PRTFUZZMUTATOR)RTMemAllocZ(RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
1428 if (RT_LIKELY(pThis->paMutators))
1429 {
1430 pThis->cMutators = RT_ELEMENTS(g_aMutators);
1431 memcpy(&pThis->paMutators[0], &g_aMutators[0], RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
1432
1433 rc = RTSemRWCreate(&pThis->hSemRwMutations);
1434 if (RT_SUCCESS(rc))
1435 {
1436 rc = RTCritSectInit(&pThis->CritSectAlloc);
1437 if (RT_SUCCESS(rc))
1438 {
1439 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
1440 if (RT_SUCCESS(rc))
1441 {
1442 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
1443 *ppThis = pThis;
1444 return VINF_SUCCESS;
1445 }
1446
1447 RTCritSectDelete(&pThis->CritSectAlloc);
1448 }
1449
1450 RTSemRWDestroy(pThis->hSemRwMutations);
1451 }
1452 }
1453 else
1454 rc = VERR_NO_MEMORY;
1455
1456 RTMemFree(pThis);
1457 }
1458 else
1459 rc = VERR_NO_MEMORY;
1460
1461 return rc;
1462}
1463
1464
1465/**
1466 * Destroys the given fuzzing input.
1467 *
1468 * @returns nothing.
1469 * @param pThis The fuzzing input to destroy.
1470 */
1471static void rtFuzzInputDestroy(PRTFUZZINPUTINT pThis)
1472{
1473 PRTFUZZCTXINT pFuzzer = pThis->pFuzzer;
1474
1475 rtFuzzMutationRelease(pThis->pMutationTop);
1476 rtFuzzCtxMemoryFree(pFuzzer, pThis);
1477 RTFuzzCtxRelease(pFuzzer);
1478}
1479
1480
1481RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType)
1482{
1483 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1484
1485 return rtFuzzCtxCreateEmpty(phFuzzCtx, enmType);
1486}
1487
1488
1489RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
1490{
1491 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1492 AssertPtrReturn(pfnImport, VERR_INVALID_POINTER);
1493
1494#if 0
1495 int rc = VINF_SUCCESS;
1496 if (cbState >= sizeof(RTFUZZCTXSTATE))
1497 {
1498 RTFUZZCTXSTATE StateImport;
1499
1500 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
1501 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
1502 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
1503 {
1504 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
1505 if (RT_LIKELY(pThis))
1506 {
1507 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
1508 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
1509
1510 uint8_t *pbState = (uint8_t *)pvState;
1511 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
1512 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
1513 if (RT_SUCCESS(rc))
1514 {
1515 /* Go through the inputs and add them. */
1516 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
1517 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
1518
1519 uint32_t idx = 0;
1520 while ( idx < cInputs
1521 && RT_SUCCESS(rc))
1522 {
1523 size_t cbInput = 0;
1524 if (cbState >= sizeof(uint32_t))
1525 {
1526 memcpy(&cbInput, pbState, sizeof(uint32_t));
1527 cbInput = RT_LE2H_U32(cbInput);
1528 pbState += sizeof(uint32_t);
1529 }
1530
1531 if ( cbInput
1532 && cbInput <= cbState)
1533 {
1534 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
1535 if (RT_LIKELY(pInput))
1536 {
1537 memcpy(&pInput->abInput[0], pbState, cbInput);
1538 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
1539 rc = rtFuzzCtxInputAdd(pThis, pInput);
1540 if (RT_FAILURE(rc))
1541 RTMemFree(pInput);
1542 pbState += cbInput;
1543 }
1544 }
1545 else
1546 rc = VERR_INVALID_STATE;
1547
1548 idx++;
1549 }
1550
1551 if (RT_SUCCESS(rc))
1552 {
1553 *phFuzzCtx = pThis;
1554 return VINF_SUCCESS;
1555 }
1556 }
1557
1558 rtFuzzCtxDestroy(pThis);
1559 }
1560 else
1561 rc = VERR_NO_MEMORY;
1562 }
1563 else
1564 rc = VERR_INVALID_MAGIC;
1565 }
1566 else
1567 rc = VERR_INVALID_MAGIC;
1568
1569 return rc;
1570#else
1571 RT_NOREF(pvUser);
1572 return VERR_NOT_IMPLEMENTED;
1573#endif
1574}
1575
1576
1577RTDECL(int) RTFuzzCtxCreateFromStateMem(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
1578{
1579 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1580 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
1581 AssertPtrReturn(cbState, VERR_INVALID_POINTER);
1582
1583 return VERR_NOT_IMPLEMENTED;
1584}
1585
1586
1587RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
1588{
1589 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1590 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1591
1592 void *pv = NULL;
1593 size_t cb = 0;
1594 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1595 if (RT_SUCCESS(rc))
1596 {
1597 rc = RTFuzzCtxCreateFromStateMem(phFuzzCtx, pv, cb);
1598 RTFileReadAllFree(pv, cb);
1599 }
1600
1601 return rc;
1602}
1603
1604
1605RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
1606{
1607 PRTFUZZCTXINT pThis = hFuzzCtx;
1608
1609 AssertPtrReturn(pThis, UINT32_MAX);
1610
1611 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1612 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1613 return cRefs;
1614}
1615
1616
1617RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
1618{
1619 PRTFUZZCTXINT pThis = hFuzzCtx;
1620 if (pThis == NIL_RTFUZZCTX)
1621 return 0;
1622 AssertPtrReturn(pThis, UINT32_MAX);
1623
1624 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1625 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1626 if (cRefs == 0)
1627 rtFuzzCtxDestroy(pThis);
1628 return cRefs;
1629}
1630
1631
1632RTDECL(int) RTFuzzCtxQueryStats(RTFUZZCTX hFuzzCtx, PRTFUZZCTXSTATS pStats)
1633{
1634 PRTFUZZCTXINT pThis = hFuzzCtx;
1635 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1636 AssertPtrReturn(pStats, VERR_INVALID_POINTER);
1637
1638 pStats->cbMemory = ASMAtomicReadZ(&pThis->cbMemTotal);
1639 pStats->cMutations = ASMAtomicReadU64(&pThis->cMutations);
1640 return VINF_SUCCESS;
1641}
1642
1643
1644/**
1645 * Fuzzing context export callback for a single mutation.
1646 */
1647static DECLCALLBACK(int) rtFuzzCtxStateExportMutations(PAVLU64NODECORE pCore, void *pvParam)
1648{
1649 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)pCore;
1650 PCRTFUZZMUTATOR pMutator = pMutation->pMutator;
1651 PCRTFUZZEXPORTARGS pArgs = (PCRTFUZZEXPORTARGS)pvParam;
1652 RTFUZZMUTATIONSTATE MutationState;
1653
1654 MutationState.u64Id = RT_H2LE_U64(pMutation->Core.Key);
1655 if (pMutation->pMutationParent)
1656 MutationState.u64IdParent = RT_H2LE_U64(pMutation->pMutationParent->Core.Key);
1657 else
1658 MutationState.u64IdParent = RT_H2LE_U64(0);
1659 MutationState.u64OffMutation = RT_H2LE_U64(pMutation->offMutation);
1660 MutationState.cbInput = RT_H2LE_U64((uint64_t)pMutation->cbInput);
1661 MutationState.cbMutation = RT_H2LE_U64((uint64_t)pMutation->cbMutation);
1662 MutationState.u32IdMutator = RT_H2LE_U32(pMutator->uMutator);
1663 MutationState.iLvl = RT_H2LE_U32(pMutation->iLvl);
1664 MutationState.u32Magic = RT_H2LE_U32(pMutation->u32Magic);
1665
1666 int rc = pArgs->pfnExport(pMutation->pFuzzer, &MutationState, sizeof(MutationState), pArgs->pvUser);
1667 if ( RT_SUCCESS(rc)
1668 && pMutator->pfnExport)
1669 rc = pMutator->pfnExport(pMutation->pFuzzer, pMutation, &pMutation->abMutation[0], pArgs->pfnExport, pArgs->pvUser);
1670 return rc;
1671}
1672
1673
1674RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1675{
1676 PRTFUZZCTXINT pThis = hFuzzCtx;
1677 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1678 AssertPtrReturn(pfnExport, VERR_INVALID_POINTER);
1679
1680 char aszPrngExport[_4K]; /* Should be plenty of room here. */
1681 size_t cbPrng = sizeof(aszPrngExport);
1682 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
1683 if (RT_SUCCESS(rc))
1684 {
1685 RTFUZZCTXSTATE StateExport;
1686
1687 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
1688 switch (pThis->enmType)
1689 {
1690 case RTFUZZCTXTYPE_BLOB:
1691 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_BLOB);
1692 break;
1693 case RTFUZZCTXTYPE_STREAM:
1694 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_STREAM);
1695 break;
1696 default:
1697 AssertFailed();
1698 break;
1699 }
1700 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
1701 StateExport.cMutations = RT_H2LE_U32(pThis->cMutations);
1702 StateExport.cMutators = RT_H2LE_U32(pThis->cMutators);
1703 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
1704 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
1705
1706 /* Write the context state and PRNG state first. */
1707 rc = pfnExport(pThis, &StateExport, sizeof(StateExport), pvUser);
1708 if (RT_SUCCESS(rc))
1709 rc = pfnExport(pThis, &aszPrngExport[0], cbPrng, pvUser);
1710 if (RT_SUCCESS(rc))
1711 {
1712 /* Write the mutator descriptors next. */
1713 for (uint32_t i = 0; i < pThis->cMutators && RT_SUCCESS(rc); i++)
1714 {
1715 PRTFUZZMUTATOR pMutator = &pThis->paMutators[i];
1716 uint32_t cchId = (uint32_t)strlen(pMutator->pszId) + 1;
1717 uint32_t cchIdW = RT_H2LE_U32(cchId);
1718
1719 rc = pfnExport(pThis, &cchIdW, sizeof(cchIdW), pvUser);
1720 if (RT_SUCCESS(rc))
1721 rc = pfnExport(pThis, &pMutator->pszId[0], cchId, pvUser);
1722 }
1723 }
1724
1725 /* Write the mutations last. */
1726 if (RT_SUCCESS(rc))
1727 {
1728 RTFUZZEXPORTARGS Args;
1729
1730 Args.pfnExport = pfnExport;
1731 Args.pvUser = pvUser;
1732 rc = RTAvlU64DoWithAll(&pThis->TreeMutations, true /*fFromLeft*/, rtFuzzCtxStateExportMutations, &Args);
1733 }
1734 }
1735
1736 return rc;
1737}
1738
1739
1740RTDECL(int) RTFuzzCtxStateExportToMem(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
1741{
1742 PRTFUZZCTXINT pThis = hFuzzCtx;
1743 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1744 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
1745 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
1746
1747 return VERR_NOT_IMPLEMENTED;
1748}
1749
1750
1751/**
1752 * Export to file callback.
1753 */
1754static DECLCALLBACK(int) rtFuzzCtxStateExportFile(RTFUZZCTX hFuzzCtx, const void *pvBuf, size_t cbWrite, void *pvUser)
1755{
1756 RT_NOREF(hFuzzCtx);
1757
1758 RTFILE hFile = (RTFILE)pvUser;
1759 return RTFileWrite(hFile, pvBuf, cbWrite, NULL);
1760}
1761
1762
1763RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1764{
1765 PRTFUZZCTXINT pThis = hFuzzCtx;
1766 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1767 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1768
1769 RTFILE hFile;
1770 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1771 if (RT_SUCCESS(rc))
1772 {
1773 rc = RTFuzzCtxStateExport(hFuzzCtx, rtFuzzCtxStateExportFile, hFile);
1774 RTFileClose(hFile);
1775 if (RT_FAILURE(rc))
1776 RTFileDelete(pszFilename);
1777 }
1778
1779 return rc;
1780}
1781
1782
1783RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
1784{
1785 PRTFUZZCTXINT pThis = hFuzzCtx;
1786 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1787 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
1788 AssertReturn(cbInput, VERR_INVALID_POINTER);
1789
1790 int rc = VINF_SUCCESS;
1791 void *pvCorpus = NULL;
1792 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbInput, &pvCorpus);
1793 if (RT_LIKELY(pMutation))
1794 {
1795 pMutation->pMutator = &g_MutatorCorpus;
1796 pMutation->cbInput = cbInput;
1797 pMutation->pvInput = pvCorpus;
1798 memcpy(pvCorpus, pvInput, cbInput);
1799 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1800 if (RT_FAILURE(rc))
1801 rtFuzzMutationDestroy(pMutation);
1802 }
1803 else
1804 rc = VERR_NO_MEMORY;
1805
1806 return rc;
1807}
1808
1809
1810RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1811{
1812 PRTFUZZCTXINT pThis = hFuzzCtx;
1813 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1814 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1815
1816 void *pv = NULL;
1817 size_t cb = 0;
1818 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1819 if (RT_SUCCESS(rc))
1820 {
1821 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
1822 RTFileReadAllFree(pv, cb);
1823 }
1824
1825 return rc;
1826}
1827
1828
1829RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
1830{
1831 PRTFUZZCTXINT pThis = hFuzzCtx;
1832 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1833 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
1834
1835 uint64_t cbFile = 0;
1836 void *pvCorpus = NULL;
1837 int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
1838 if (RT_SUCCESS(rc))
1839 {
1840 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbFile, &pvCorpus);
1841 if (RT_LIKELY(pMutation))
1842 {
1843 pMutation->pMutator = &g_MutatorCorpus;
1844 pMutation->cbInput = cbFile;
1845 pMutation->pvInput = pvCorpus;
1846 rc = RTVfsFileRead(hVfsFile, pvCorpus, cbFile, NULL);
1847 if (RT_SUCCESS(rc))
1848 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1849
1850 if (RT_FAILURE(rc))
1851 rtFuzzMutationDestroy(pMutation);
1852 }
1853 }
1854
1855 return rc;
1856}
1857
1858
1859RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
1860{
1861 PRTFUZZCTXINT pThis = hFuzzCtx;
1862 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1863 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
1864
1865 RTDIR hDir;
1866 int rc = RTDirOpen(&hDir, pszDirPath);
1867 if (RT_SUCCESS(rc))
1868 {
1869 for (;;)
1870 {
1871 RTDIRENTRY DirEntry;
1872 rc = RTDirRead(hDir, &DirEntry, NULL);
1873 if (RT_FAILURE(rc))
1874 break;
1875
1876 /* Skip '.', '..' and other non-files. */
1877 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
1878 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1879 continue;
1880 if (RTDirEntryIsStdDotLink(&DirEntry))
1881 continue;
1882
1883 /* Compose the full path, result 'unknown' entries and skip non-files. */
1884 char szFile[RTPATH_MAX];
1885 RT_ZERO(szFile);
1886 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
1887 if (RT_FAILURE(rc))
1888 break;
1889
1890 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
1891 {
1892 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
1893 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1894 continue;
1895 }
1896
1897 /* Okay, it's a file we can add. */
1898 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
1899 if (RT_FAILURE(rc))
1900 break;
1901 }
1902 if (rc == VERR_NO_MORE_FILES)
1903 rc = VINF_SUCCESS;
1904 RTDirClose(hDir);
1905 }
1906
1907 return rc;
1908}
1909
1910
1911RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
1912{
1913 PRTFUZZCTXINT pThis = hFuzzCtx;
1914 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1915
1916 pThis->cbInputMax = cbMax;
1917 return VINF_SUCCESS;
1918}
1919
1920
1921RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
1922{
1923 PRTFUZZCTXINT pThis = hFuzzCtx;
1924 AssertPtrReturn(pThis, 0);
1925
1926 return pThis->cbInputMax;
1927}
1928
1929
1930RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
1931{
1932 PRTFUZZCTXINT pThis = hFuzzCtx;
1933 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1934 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
1935
1936 pThis->fFlagsBehavioral = fFlags;
1937 return VINF_SUCCESS;
1938}
1939
1940
1941RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
1942{
1943 PRTFUZZCTXINT pThis = hFuzzCtx;
1944 AssertPtrReturn(pThis, 0);
1945
1946 return pThis->fFlagsBehavioral;
1947}
1948
1949
1950RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
1951{
1952 PRTFUZZCTXINT pThis = hFuzzCtx;
1953 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1954 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
1955
1956 return VERR_NOT_IMPLEMENTED;
1957}
1958
1959
1960RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
1961{
1962 PRTFUZZCTXINT pThis = hFuzzCtx;
1963 AssertPtrReturn(pThis, NULL);
1964
1965 return NULL;
1966}
1967
1968
1969RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
1970{
1971 PRTFUZZCTXINT pThis = hFuzzCtx;
1972 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1973
1974 RTRandAdvSeed(pThis->hRand, uSeed);
1975 return VINF_SUCCESS;
1976}
1977
1978
1979RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
1980{
1981 int rc = VINF_SUCCESS;
1982 PRTFUZZCTXINT pThis = hFuzzCtx;
1983 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1984 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1985
1986 uint32_t cTries = 0;
1987 PRTFUZZMUTATION pMutationParent = rtFuzzCtxMutationPickRnd(pThis);
1988 do
1989 {
1990 uint32_t idxMutator = RTRandAdvU32Ex(pThis->hRand, 0, pThis->cMutators - 1);
1991 PCRTFUZZMUTATOR pMutator = &pThis->paMutators[idxMutator];
1992 PRTFUZZMUTATION pMutation = NULL;
1993
1994 uint64_t offStart = 0;
1995 if (!(pMutator->fFlags & RTFUZZMUTATOR_F_END_OF_BUF))
1996 offStart = RTRandAdvU64Ex(pThis->hRand, 0, pMutationParent->cbInput - 1);
1997 else
1998 offStart = pMutationParent->cbInput;
1999
2000 rc = pMutator->pfnPrep(pThis, offStart, pMutationParent, &pMutation);
2001 if ( RT_SUCCESS(rc)
2002 && VALID_PTR(pMutation))
2003 {
2004 pMutation->pMutator = pMutator;
2005
2006 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
2007 rtFuzzCtxMutationAdd(pThis, pMutation);
2008
2009 /* Create a new input. */
2010 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZINPUTINT));
2011 if (RT_LIKELY(pInput))
2012 {
2013 pInput->u32Magic = 0; /** @todo */
2014 pInput->cRefs = 1;
2015 pInput->pFuzzer = pThis;
2016 pInput->pMutationTop = pMutation;
2017 RTFuzzCtxRetain(pThis);
2018
2019 rtFuzzMutationRelease(pMutationParent);
2020 *phFuzzInput = pInput;
2021 return rc;
2022 }
2023 else
2024 rc = VERR_NO_MEMORY;
2025 }
2026 } while (++cTries <= 50);
2027
2028 rtFuzzMutationRelease(pMutationParent);
2029 if (RT_SUCCESS(rc))
2030 rc = VERR_INVALID_STATE;
2031
2032 return rc;
2033}
2034
2035
2036RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
2037{
2038 PRTFUZZINPUTINT pThis = hFuzzInput;
2039 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2040 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2041
2042 int rc = VINF_SUCCESS;
2043 if (!pThis->pMutationTop->pvInput)
2044 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2045
2046 if (RT_SUCCESS(rc))
2047 {
2048 *ppv = pThis->pMutationTop->pvInput;
2049 *pcb = pThis->pMutationTop->cbInput;
2050 }
2051
2052 return rc;
2053}
2054
2055
2056RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf)
2057{
2058 PRTFUZZINPUTINT pThis = hFuzzInput;
2059 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2060 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_STREAM, VERR_INVALID_STATE);
2061
2062 RT_NOREF(pvBuf, cbBuf);
2063 return VERR_NOT_IMPLEMENTED;
2064}
2065
2066
2067RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
2068{
2069 PRTFUZZINPUTINT pThis = hFuzzInput;
2070
2071 AssertPtrReturn(pThis, UINT32_MAX);
2072
2073 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
2074 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2075 return cRefs;
2076}
2077
2078
2079RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
2080{
2081 PRTFUZZINPUTINT pThis = hFuzzInput;
2082 if (pThis == NIL_RTFUZZINPUT)
2083 return 0;
2084 AssertPtrReturn(pThis, UINT32_MAX);
2085
2086 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
2087 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2088 if (cRefs == 0)
2089 rtFuzzInputDestroy(pThis);
2090 return cRefs;
2091}
2092
2093
2094RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
2095{
2096 PRTFUZZINPUTINT pThis = hFuzzInput;
2097 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2098 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2099 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
2100 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
2101
2102 int rc = VINF_SUCCESS;
2103 if (!pThis->pMutationTop->pvInput)
2104 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2105
2106 if (RT_SUCCESS(rc))
2107 {
2108 uint8_t abHash[RTMD5_HASH_SIZE];
2109 RTMd5(pThis->pMutationTop->pvInput, pThis->pMutationTop->cbInput, &abHash[0]);
2110 rc = RTMd5ToString(&abHash[0], pszDigest, cchDigest);
2111 }
2112
2113 return rc;
2114}
2115
2116
2117RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
2118{
2119 PRTFUZZINPUTINT pThis = hFuzzInput;
2120 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2121 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2122 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
2123
2124 int rc = VINF_SUCCESS;
2125 if (!pThis->pMutationTop->pvInput)
2126 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2127
2128 if (RT_SUCCESS(rc))
2129 {
2130 RTFILE hFile;
2131 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2132 if (RT_SUCCESS(rc))
2133 {
2134 rc = RTFileWrite(hFile, pThis->pMutationTop->pvInput, pThis->pMutationTop->cbInput, NULL);
2135 AssertRC(rc);
2136 RTFileClose(hFile);
2137
2138 if (RT_FAILURE(rc))
2139 RTFileDelete(pszFilename);
2140 }
2141 }
2142
2143 return rc;
2144}
2145
2146
2147RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
2148{
2149 PRTFUZZINPUTINT pThis = hFuzzInput;
2150 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2151
2152 return rtFuzzCtxMutationAdd(pThis->pFuzzer, pThis->pMutationTop);
2153}
2154
2155
2156RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
2157{
2158 PRTFUZZINPUTINT pThis = hFuzzInput;
2159 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2160
2161#if 0
2162 int rc = VINF_SUCCESS;
2163 PRTFUZZINTERMEDIATE pIntermediate = NULL;
2164 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
2165 &pIntermediate);
2166 if (pInputLoc)
2167 {
2168 AssertPtr(pIntermediate);
2169 Assert(pInputLoc == pThis);
2170
2171 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
2172 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
2173 RTFuzzInputRelease(hFuzzInput);
2174 }
2175 else
2176 rc = VERR_NOT_FOUND;
2177#endif
2178
2179 return VERR_NOT_IMPLEMENTED;
2180}
2181
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette