VirtualBox

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

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

Runtime/fuzz: Some more statistics, add possibility to configure the environment of the target process through the job config, add possibility to read SanitizerCoverage generated reports to scan for changes in executed paths for inputs to evaluate which mutations are interesting for further use

  • 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 77693 2019-03-13 21:24:29Z 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.215389.xyz. 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 PRTFUZZMEMHDR pMemHdr = ((PRTFUZZMEMHDR)pv) - 1;
563
564 size_t cbIgn = ASMAtomicSubZ(&pThis->cbMemTotal, pMemHdr->cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
565 RTMemFree(pMemHdr);
566}
567
568
569/**
570 * Frees the cached inputs until the given amount is free.
571 *
572 * @returns Whether the amount of memory is free.
573 * @param pThis The fuzzer context instance.
574 * @param cb How many bytes to reclaim
575 */
576static bool rtFuzzCtxMutationAllocReclaim(PRTFUZZCTXINT pThis, size_t cb)
577{
578 while ( !RTListIsEmpty(&pThis->LstMutationsAlloc)
579 && pThis->cbMutationsAlloc + cb > pThis->cbMutationsAllocMax)
580 {
581 PRTFUZZMUTATION pMutation = RTListGetLast(&pThis->LstMutationsAlloc, RTFUZZMUTATION, NdAlloc);
582 AssertPtr(pMutation);
583 AssertPtr(pMutation->pvInput);
584
585 rtFuzzCtxMemoryFree(pThis, pMutation->pvInput);
586 pThis->cbMutationsAlloc -= pMutation->cbAlloc;
587 pMutation->pvInput = NULL;
588 pMutation->cbAlloc = 0;
589 pMutation->fCached = false;
590 RTListNodeRemove(&pMutation->NdAlloc);
591 }
592
593 return pThis->cbMutationsAlloc + cb <= pThis->cbMutationsAllocMax;
594}
595
596
597/**
598 * Updates the cache status of the given mutation.
599 *
600 * @returns nothing.
601 * @param pThis The fuzzer context instance.
602 * @param pMutation The mutation to update.
603 */
604static void rtFuzzCtxMutationMaybeEnterCache(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
605{
606 RTCritSectEnter(&pThis->CritSectAlloc);
607
608 /* Initial corpus mutations are not freed. */
609 if ( pMutation->pvInput
610 && pMutation->pMutator != &g_MutatorCorpus)
611 {
612 Assert(!pMutation->fCached);
613
614 if (rtFuzzCtxMutationAllocReclaim(pThis, pMutation->cbAlloc))
615 {
616 RTListPrepend(&pThis->LstMutationsAlloc, &pMutation->NdAlloc);
617 pThis->cbMutationsAlloc += pMutation->cbAlloc;
618 pMutation->fCached = true;
619 }
620 else
621 {
622 rtFuzzCtxMemoryFree(pThis, pMutation->pvInput);
623 pMutation->pvInput = NULL;
624 pMutation->cbAlloc = 0;
625 pMutation->fCached = false;
626 }
627 }
628 RTCritSectLeave(&pThis->CritSectAlloc);
629}
630
631
632/**
633 * Removes a cached mutation from the cache.
634 *
635 * @returns nothing.
636 * @param pThis The fuzzer context instance.
637 * @param pMutation The mutation to remove.
638 */
639static void rtFuzzCtxMutationCacheRemove(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
640{
641 RTCritSectEnter(&pThis->CritSectAlloc);
642 if (pMutation->fCached)
643 {
644 RTListNodeRemove(&pMutation->NdAlloc);
645 pThis->cbMutationsAlloc -= pMutation->cbAlloc;
646 pMutation->fCached = false;
647 }
648 RTCritSectLeave(&pThis->CritSectAlloc);
649}
650
651
652/**
653 * Destroys the given mutation.
654 *
655 * @returns nothing.
656 * @param pMutation The mutation to destroy.
657 */
658static void rtFuzzMutationDestroy(PRTFUZZMUTATION pMutation)
659{
660 if (pMutation->pvInput)
661 {
662 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation->pvInput);
663 if (pMutation->fCached)
664 {
665 RTCritSectEnter(&pMutation->pFuzzer->CritSectAlloc);
666 RTListNodeRemove(&pMutation->NdAlloc);
667 pMutation->pFuzzer->cbMutationsAlloc -= pMutation->cbAlloc;
668 RTCritSectLeave(&pMutation->pFuzzer->CritSectAlloc);
669 }
670 pMutation->pvInput = NULL;
671 pMutation->cbAlloc = 0;
672 pMutation->fCached = false;
673 }
674 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation);
675}
676
677
678/**
679 * Retains an external reference to the given mutation.
680 *
681 * @returns New reference count on success.
682 * @param pMutation The mutation to retain.
683 */
684static uint32_t rtFuzzMutationRetain(PRTFUZZMUTATION pMutation)
685{
686 uint32_t cRefs = ASMAtomicIncU32(&pMutation->cRefs);
687 AssertMsg( ( cRefs > 1
688 || pMutation->fInTree)
689 && cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
690
691 if (cRefs == 1)
692 rtFuzzCtxMutationCacheRemove(pMutation->pFuzzer, pMutation);
693 return cRefs;
694}
695
696
697/**
698 * Releases an external reference from the given mutation.
699 *
700 * @returns New reference count on success.
701 * @param pMutation The mutation to retain.
702 */
703static uint32_t rtFuzzMutationRelease(PRTFUZZMUTATION pMutation)
704{
705 uint32_t cRefs = ASMAtomicDecU32(&pMutation->cRefs);
706 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
707
708 if (cRefs == 0)
709 {
710 rtFuzzCtxMutationMaybeEnterCache(pMutation->pFuzzer, pMutation);
711
712 if (!pMutation->fInTree)
713 rtFuzzMutationDestroy(pMutation);
714 }
715
716 return cRefs;
717}
718
719
720/**
721 * Adds the given mutation to the corpus of the given fuzzer context.
722 *
723 * @returns IPRT status code.
724 * @param pThis The fuzzer context instance.
725 * @param pMutation The mutation to add.
726 */
727static int rtFuzzCtxMutationAdd(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
728{
729 int rc = VINF_SUCCESS;
730
731 pMutation->Core.Key = ASMAtomicIncU64(&pThis->cMutations);
732 rc = RTSemRWRequestWrite(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
733 AssertRC(rc); RT_NOREF(rc);
734 bool fIns = RTAvlU64Insert(&pThis->TreeMutations, &pMutation->Core);
735 Assert(fIns); RT_NOREF(fIns);
736 rc = RTSemRWReleaseWrite(pThis->hSemRwMutations);
737 AssertRC(rc); RT_NOREF(rc);
738
739 pMutation->fInTree = true;
740 return rc;
741}
742
743
744/**
745 * Locates the mutation with the given key.
746 *
747 * @returns Pointer to the mutation if found or NULL otherwise.
748 * @param pThis The fuzzer context instance.
749 * @param uKey The key to locate.
750 */
751static PRTFUZZMUTATION rtFuzzCtxMutationLocate(PRTFUZZCTXINT pThis, uint64_t uKey)
752{
753 int rc = RTSemRWRequestRead(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
754 AssertRC(rc); RT_NOREF(rc);
755
756 /*
757 * Using best fit getter here as there might be a racing mutation insertion and the mutation counter has increased
758 * already but the mutation is not yet in the tree.
759 */
760 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)RTAvlU64GetBestFit(&pThis->TreeMutations, uKey, false /*fAbove*/);
761 if (RT_LIKELY(pMutation))
762 rtFuzzMutationRetain(pMutation);
763
764 rc = RTSemRWReleaseRead(pThis->hSemRwMutations);
765 AssertRC(rc); RT_NOREF(rc);
766
767 return pMutation;
768}
769
770
771/**
772 * Returns a random mutation from the corpus of the given fuzzer context.
773 *
774 * @returns Pointer to a randomly picked mutation (reference count is increased).
775 * @param pThis The fuzzer context instance.
776 */
777static PRTFUZZMUTATION rtFuzzCtxMutationPickRnd(PRTFUZZCTXINT pThis)
778{
779 uint64_t idxMutation = RTRandAdvU64Ex(pThis->hRand, 1, ASMAtomicReadU64(&pThis->cMutations));
780 return rtFuzzCtxMutationLocate(pThis, idxMutation);
781}
782
783
784/**
785 * Creates a new mutation capable of holding the additional number of bytes.
786 *
787 * @returns Pointer to the newly created mutation or NULL if out of memory.
788 * @param pThis The fuzzer context instance.
789 * @param offMutation The starting offset for the mutation.
790 * @param pMutationParent The parent mutation, can be NULL.
791 * @param cbAdditional Additional number of bytes to allocate after the core structure.
792 * @param ppvMutation Where to store the pointer to the mutation dependent data on success.
793 */
794static PRTFUZZMUTATION rtFuzzMutationCreate(PRTFUZZCTXINT pThis, uint64_t offMutation, PRTFUZZMUTATION pMutationParent,
795 size_t cbAdditional, void **ppvMutation)
796{
797 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZMUTATION) + cbAdditional);
798 if (RT_LIKELY(pMutation))
799 {
800 pMutation->u32Magic = 0; /** @todo */
801 pMutation->pFuzzer = pThis;
802 pMutation->cRefs = 1;
803 pMutation->iLvl = 0;
804 pMutation->offMutation = offMutation;
805 pMutation->pMutationParent = pMutationParent;
806 pMutation->cbMutation = cbAdditional;
807 pMutation->fInTree = false;
808 pMutation->fCached = false;
809 pMutation->pvInput = NULL;
810 pMutation->cbInput = 0;
811 pMutation->cbAlloc = 0;
812
813 if (pMutationParent)
814 pMutation->iLvl = pMutationParent->iLvl + 1;
815 if (ppvMutation)
816 *ppvMutation = &pMutation->abMutation[0];
817 }
818
819 return pMutation;
820}
821
822
823/**
824 * Destroys the given fuzzer context freeing all allocated resources.
825 *
826 * @returns nothing.
827 * @param pThis The fuzzer context instance.
828 */
829static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
830{
831 RT_NOREF(pThis);
832}
833
834
835/**
836 * Creates the final input data applying all accumulated mutations.
837 *
838 * @returns IPRT status code.
839 * @param pMutation The mutation to finalize.
840 */
841static int rtFuzzMutationDataFinalize(PRTFUZZMUTATION pMutation)
842{
843 if (pMutation->pvInput)
844 return VINF_SUCCESS;
845
846 /* Traverse the mutations top to bottom and insert into the array. */
847 int rc = VINF_SUCCESS;
848 uint32_t idx = pMutation->iLvl + 1;
849 PRTFUZZMUTATION *papMutations = (PRTFUZZMUTATION *)RTMemTmpAlloc(idx * sizeof(PCRTFUZZMUTATION));
850 if (RT_LIKELY(papMutations))
851 {
852 PRTFUZZMUTATION pMutationCur = pMutation;
853 size_t cbAlloc = 0;
854
855 /*
856 * As soon as a mutation with allocated input data is encountered the insertion is
857 * stopped as it contains all necessary mutated inputs we can start from.
858 */
859 while (idx > 0)
860 {
861 rtFuzzMutationRetain(pMutationCur);
862 papMutations[idx - 1] = pMutationCur;
863 cbAlloc = RT_MAX(cbAlloc, pMutationCur->cbInput);
864 if (pMutationCur->pvInput)
865 {
866 idx--;
867 break;
868 }
869 pMutationCur = pMutationCur->pMutationParent;
870 idx--;
871 }
872
873 pMutation->cbAlloc = cbAlloc;
874 uint8_t *pbBuf = (uint8_t *)rtFuzzCtxMemoryAlloc(pMutation->pFuzzer, cbAlloc);
875 if (RT_LIKELY(pbBuf))
876 {
877 pMutation->pvInput = pbBuf;
878
879 /* Copy the initial input data. */
880 size_t cbInputNow = papMutations[idx]->cbInput;
881 memcpy(pbBuf, papMutations[idx]->pvInput, cbInputNow);
882 rtFuzzMutationRelease(papMutations[idx]);
883
884 for (uint32_t i = idx + 1; i < pMutation->iLvl + 1; i++)
885 {
886 PRTFUZZMUTATION pCur = papMutations[i];
887 pCur->pMutator->pfnExec(pCur->pFuzzer, pCur, (void *)&pCur->abMutation[0],
888 pbBuf + pCur->offMutation,
889 cbInputNow - pCur->offMutation);
890
891 cbInputNow = pCur->cbInput;
892 rtFuzzMutationRelease(pCur);
893 }
894
895 Assert(cbInputNow == pMutation->cbInput);
896 }
897 else
898 rc = VERR_NO_MEMORY;
899
900 RTMemTmpFree(papMutations);
901 }
902 else
903 rc = VERR_NO_MEMORY;
904
905 return rc;
906}
907
908
909/**
910 * Default mutator export callback (just writing the raw data).
911 */
912static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
913 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
914{
915 return pfnExport(pThis, pvMutation, pMutation->cbMutation, pvUser);
916}
917
918
919/**
920 * Default mutator import callback (just reading the raw data).
921 */
922static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
923 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
924{
925 return pfnImport(pThis, pvMutation, pMutation->cbMutation, NULL, pvUser);
926}
927
928
929static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
930 uint8_t *pbBuf, size_t cbBuf)
931{
932 RT_NOREF(pThis, cbBuf, pvMutation);
933 memcpy(pbBuf, pvMutation, pMutation->cbInput);
934 return VINF_SUCCESS;
935}
936
937
938/**
939 * Mutator callback - flips a single bit in the input.
940 */
941static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
942 PPRTFUZZMUTATION ppMutation)
943{
944 int rc = VINF_SUCCESS;
945 uint8_t *pidxBitFlip = 0;
946 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxBitFlip), (void **)&pidxBitFlip);
947 if (RT_LIKELY(pMutation))
948 {
949 pMutation->cbInput = pMutationParent->cbInput; /* Bit flips don't change the input size. */
950 *pidxBitFlip = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, sizeof(uint8_t) * 8 - 1);
951 *ppMutation = pMutation;
952 }
953 else
954 rc = VERR_NO_MEMORY;
955
956 return rc;
957}
958
959
960static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
961 uint8_t *pbBuf, size_t cbBuf)
962{
963 RT_NOREF(pThis, cbBuf, pMutation);
964 uint8_t idxBitFlip = *(uint8_t *)pvMutation;
965 ASMBitToggle(pbBuf, idxBitFlip);
966 return VINF_SUCCESS;
967}
968
969
970/**
971 * Mutator callback - replaces a single byte in the input.
972 */
973static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
974 PPRTFUZZMUTATION ppMutation)
975{
976 int rc = VINF_SUCCESS;
977 uint8_t *pbReplace = 0;
978 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pbReplace), (void **)&pbReplace);
979 if (RT_LIKELY(pMutation))
980 {
981 pMutation->cbInput = pMutationParent->cbInput; /* Byte replacements don't change the input size. */
982 RTRandAdvBytes(pThis->hRand, pbReplace, 1); /** @todo Filter out same values. */
983 *ppMutation = pMutation;
984 }
985 else
986 rc = VERR_NO_MEMORY;
987
988 return rc;
989}
990
991
992static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
993 uint8_t *pbBuf, size_t cbBuf)
994{
995 RT_NOREF(pThis, cbBuf, pMutation);
996 uint8_t bReplace = *(uint8_t *)pvMutation;
997 *pbBuf = bReplace;
998 return VINF_SUCCESS;
999}
1000
1001
1002/**
1003 * Mutator callback - inserts a single byte into the input.
1004 */
1005static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1006 PPRTFUZZMUTATION ppMutation)
1007{
1008 int rc = VINF_SUCCESS;
1009 uint8_t *pbInsert = 0;
1010 if (pMutationParent->cbInput < pThis->cbInputMax)
1011 {
1012 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 1 /*cbAdditional*/, (void **)&pbInsert);
1013 if (RT_LIKELY(pMutation))
1014 {
1015 pMutation->cbInput = pMutationParent->cbInput + 1;
1016 RTRandAdvBytes(pThis->hRand, pbInsert, 1);
1017 *ppMutation = pMutation;
1018 }
1019 else
1020 rc = VERR_NO_MEMORY;
1021 }
1022
1023 return rc;
1024}
1025
1026
1027static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1028 uint8_t *pbBuf, size_t cbBuf)
1029{
1030 RT_NOREF(pThis, pMutation, pvMutation);
1031
1032 /* Just move the residual data one byte to the back. */
1033 memmove(pbBuf + 1, pbBuf, cbBuf);
1034 *pbBuf = *(uint8_t *)pvMutation;
1035 return VINF_SUCCESS;
1036}
1037
1038
1039/**
1040 * Mutator callback - inserts a byte sequence into the input.
1041 */
1042static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1043 PPRTFUZZMUTATION ppMutation)
1044{
1045 int rc = VINF_SUCCESS;
1046 if (pMutationParent->cbInput < pThis->cbInputMax)
1047 {
1048 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, pMutationParent->cbInput + 1, pThis->cbInputMax);
1049 size_t cbInsert = cbInputMutated - pMutationParent->cbInput;
1050 uint8_t *pbAdd = NULL;
1051
1052 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, cbInsert, (void **)&pbAdd);
1053 if (RT_LIKELY(pMutation))
1054 {
1055 pMutation->cbInput = cbInputMutated;
1056 RTRandAdvBytes(pThis->hRand, pbAdd, cbInsert);
1057 *ppMutation = pMutation;
1058 }
1059 else
1060 rc = VERR_NO_MEMORY;
1061 }
1062
1063 return rc;
1064}
1065
1066
1067static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1068 uint8_t *pbBuf, size_t cbBuf)
1069{
1070 RT_NOREF(pThis);
1071 size_t cbInsert = pMutation->cbInput - pMutation->pMutationParent->cbInput;
1072
1073 /* Move any remaining data to the end. */
1074 if (cbBuf)
1075 memmove(pbBuf + cbInsert, pbBuf, cbBuf);
1076
1077 memcpy(pbBuf, pvMutation, cbInsert);
1078 return VINF_SUCCESS;
1079}
1080
1081
1082/**
1083 * Mutator callback - deletes a single byte in the input.
1084 */
1085static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1086 PPRTFUZZMUTATION ppMutation)
1087{
1088 int rc = VINF_SUCCESS;
1089 if (pMutationParent->cbInput - offStart >= 1)
1090 {
1091 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
1092 if (RT_LIKELY(pMutation))
1093 {
1094 pMutation->cbInput = pMutationParent->cbInput - 1;
1095 *ppMutation = pMutation;
1096 }
1097 else
1098 rc = VERR_NO_MEMORY;
1099 }
1100
1101 return rc;
1102}
1103
1104
1105static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1106 uint8_t *pbBuf, size_t cbBuf)
1107{
1108 RT_NOREF(pThis, pMutation, pvMutation);
1109
1110 /* Just move the residual data to the front. */
1111 memmove(pbBuf, pbBuf + 1, cbBuf - 1);
1112 return VINF_SUCCESS;
1113}
1114
1115
1116/**
1117 * Mutator callback - deletes a byte sequence in the input.
1118 */
1119static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1120 PPRTFUZZMUTATION ppMutation)
1121{
1122 int rc = VINF_SUCCESS;
1123 if ( pMutationParent->cbInput > offStart
1124 && pMutationParent->cbInput > 1)
1125 {
1126 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, offStart, pMutationParent->cbInput - 1);
1127
1128 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
1129 if (RT_LIKELY(pMutation))
1130 {
1131 pMutation->cbInput = cbInputMutated;
1132 *ppMutation = pMutation;
1133 }
1134 else
1135 rc = VERR_NO_MEMORY;
1136 }
1137
1138 return rc;
1139}
1140
1141
1142static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1143 uint8_t *pbBuf, size_t cbBuf)
1144{
1145 RT_NOREF(pThis, pvMutation);
1146 Assert(pMutation->pMutationParent->cbInput > pMutation->cbInput);
1147 size_t cbDel = pMutation->pMutationParent->cbInput - pMutation->cbInput;
1148
1149 /* Just move the residual data to the front. */
1150 memmove(pbBuf, pbBuf + cbDel, cbBuf - cbDel);
1151 return VINF_SUCCESS;
1152}
1153
1154
1155/**
1156 * Mutator callback - replaces a possible integer with something interesting.
1157 */
1158static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1159 PPRTFUZZMUTATION ppMutation)
1160{
1161 int rc = VINF_SUCCESS;
1162 PRTFUZZMUTATORINTEGER pMutInt = NULL;
1163 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pMutInt), (void **)&pMutInt);
1164 if (RT_LIKELY(pMutation))
1165 {
1166 size_t cbLeft = pMutationParent->cbInput - offStart;
1167 uint32_t uClassMax = 0;
1168
1169 switch (cbLeft)
1170 {
1171 case 1:
1172 uClassMax = 1;
1173 break;
1174 case 2:
1175 case 3:
1176 uClassMax = 3;
1177 break;
1178 case 4:
1179 case 5:
1180 case 6:
1181 case 7:
1182 uClassMax = 5;
1183 break;
1184 default:
1185 uClassMax = 7;
1186 break;
1187 }
1188
1189 pMutInt->uIntClass = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, uClassMax);
1190 pMutInt->fByteSwap = RT_BOOL(RTRandAdvU32Ex(pThis->hRand, 0, 1));
1191
1192 switch (pMutInt->uIntClass)
1193 {
1194 case 0:
1195 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai8Interesting) - 1);
1196 break;
1197 case 1:
1198 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au8Interesting) - 1);
1199 break;
1200 case 2:
1201 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai16Interesting) - 1);
1202 break;
1203 case 3:
1204 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au16Interesting) - 1);
1205 break;
1206 case 4:
1207 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai32Interesting) - 1);
1208 break;
1209 case 5:
1210 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au32Interesting) - 1);
1211 break;
1212 case 6:
1213 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai64Interesting) - 1);
1214 break;
1215 case 7:
1216 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au64Interesting) - 1);
1217 break;
1218 default:
1219 AssertReleaseFailed();
1220 }
1221
1222 pMutation->cbInput = pMutationParent->cbInput;
1223 *ppMutation = pMutation;
1224 }
1225 else
1226 rc = VERR_NO_MEMORY;
1227
1228 return rc;
1229}
1230
1231
1232static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1233 uint8_t *pbBuf, size_t cbBuf)
1234{
1235 RT_NOREF(pThis, pMutation, cbBuf);
1236 union
1237 {
1238 int8_t i8;
1239 uint8_t u8;
1240 int16_t i16;
1241 uint16_t u16;
1242 int32_t i32;
1243 uint32_t u32;
1244 int64_t i64;
1245 uint64_t u64;
1246 } Int;
1247 PCRTFUZZMUTATORINTEGER pMutInt = (PCRTFUZZMUTATORINTEGER)pvMutation;
1248 size_t cb = 0;
1249
1250 switch (pMutInt->uIntClass)
1251 {
1252 case 0:
1253 Int.i8 = s_ai8Interesting[pMutInt->idxInt];
1254 cb = 1;
1255 break;
1256 case 1:
1257 Int.u8 = s_au8Interesting[pMutInt->idxInt];
1258 cb = 1;
1259 break;
1260 case 2:
1261 Int.i16 = s_ai16Interesting[pMutInt->idxInt];
1262 cb = 2;
1263 if (pMutInt->fByteSwap)
1264 Int.u16 = RT_BSWAP_U16(Int.u16);
1265 break;
1266 case 3:
1267 Int.u16 = s_au16Interesting[pMutInt->idxInt];
1268 cb = 2;
1269 if (pMutInt->fByteSwap)
1270 Int.u16 = RT_BSWAP_U16(Int.u16);
1271 break;
1272 case 4:
1273 Int.i32 = s_ai32Interesting[pMutInt->idxInt];
1274 cb = 4;
1275 if (pMutInt->fByteSwap)
1276 Int.u32 = RT_BSWAP_U32(Int.u32);
1277 break;
1278 case 5:
1279 Int.u32 = s_au32Interesting[pMutInt->idxInt];
1280 cb = 4;
1281 if (pMutInt->fByteSwap)
1282 Int.u32 = RT_BSWAP_U32(Int.u32);
1283 break;
1284 case 6:
1285 Int.i64 = s_ai64Interesting[pMutInt->idxInt];
1286 cb = 8;
1287 if (pMutInt->fByteSwap)
1288 Int.u64 = RT_BSWAP_U64(Int.u64);
1289 break;
1290 case 7:
1291 Int.u64 = s_au64Interesting[pMutInt->idxInt];
1292 cb = 8;
1293 if (pMutInt->fByteSwap)
1294 Int.u64 = RT_BSWAP_U64(Int.u64);
1295 break;
1296 default:
1297 AssertReleaseFailed();
1298 }
1299
1300 memcpy(pbBuf, &Int, cb);
1301 return VINF_SUCCESS;
1302}
1303
1304
1305/**
1306 * Mutator callback - crosses over two mutations at the given point.
1307 */
1308static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1309 PPRTFUZZMUTATION ppMutation)
1310{
1311 int rc = VINF_SUCCESS;
1312
1313 if (pThis->cMutations > 1)
1314 {
1315 uint64_t *pidxMutCrossover = NULL;
1316 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxMutCrossover), (void **)&pidxMutCrossover);
1317 if (RT_LIKELY(pMutation))
1318 {
1319 uint32_t cTries = 10;
1320 PRTFUZZMUTATION pMutCrossover = NULL;
1321 /*
1322 * Pick a random mutation to crossover with (making sure it is not the current one
1323 * or the crossover point is beyond the end of input).
1324 */
1325 do
1326 {
1327 if (pMutCrossover)
1328 rtFuzzMutationRelease(pMutCrossover);
1329 pMutCrossover = rtFuzzCtxMutationPickRnd(pThis);
1330 cTries--;
1331 } while ( ( pMutCrossover == pMutationParent
1332 || offStart >= pMutCrossover->cbInput)
1333 && cTries > 0);
1334
1335 if (cTries)
1336 {
1337 pMutation->cbInput = pMutCrossover->cbInput;
1338 *pidxMutCrossover = pMutCrossover->Core.Key;
1339 *ppMutation = pMutation;
1340 }
1341 else
1342 rtFuzzMutationDestroy(pMutation);
1343
1344 rtFuzzMutationRelease(pMutCrossover);
1345 }
1346 else
1347 rc = VERR_NO_MEMORY;
1348 }
1349
1350 return rc;
1351}
1352
1353
1354static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1355 uint8_t *pbBuf, size_t cbBuf)
1356{
1357 RT_NOREF(cbBuf);
1358 uint64_t idxMutCrossover = *(uint64_t *)pvMutation;
1359
1360 PRTFUZZMUTATION pMutCrossover = rtFuzzCtxMutationLocate(pThis, idxMutCrossover);
1361 int rc = rtFuzzMutationDataFinalize(pMutCrossover);
1362 if (RT_SUCCESS(rc))
1363 {
1364 memcpy(pbBuf, (uint8_t *)pMutCrossover->pvInput + pMutation->offMutation,
1365 pMutCrossover->cbInput - pMutation->offMutation);
1366 rtFuzzMutationRelease(pMutCrossover);
1367 }
1368
1369 return rc;
1370}
1371
1372
1373static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1374 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1375{
1376 RT_NOREF(pMutation);
1377
1378 uint64_t idxMutCrossover = *(uint64_t *)pvMutation;
1379 idxMutCrossover = RT_H2LE_U64(idxMutCrossover);
1380 return pfnExport(pThis, &idxMutCrossover, sizeof(idxMutCrossover), pvUser);
1381}
1382
1383
1384static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverImport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
1385 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
1386{
1387 RT_NOREF(pMutation);
1388
1389 uint64_t uKey = 0;
1390 int rc = pfnImport(pThis, &uKey, sizeof(uKey), NULL, pvUser);
1391 if (RT_SUCCESS(rc))
1392 {
1393 uKey = RT_LE2H_U64(uKey);
1394 *(uint64_t *)pvMutation = uKey;
1395 }
1396
1397 return rc;
1398}
1399
1400
1401/**
1402 * Creates an empty fuzzing context.
1403 *
1404 * @returns IPRT status code.
1405 * @param ppThis Where to store the pointer to the internal fuzzing context instance on success.
1406 * @param enmType Fuzzing context type.
1407 */
1408static int rtFuzzCtxCreateEmpty(PRTFUZZCTXINT *ppThis, RTFUZZCTXTYPE enmType)
1409{
1410 int rc;
1411 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
1412 if (RT_LIKELY(pThis))
1413 {
1414 pThis->u32Magic = RTFUZZCTX_MAGIC;
1415 pThis->cRefs = 1;
1416 pThis->enmType = enmType;
1417 pThis->TreeMutations = NULL;
1418 pThis->cbInputMax = UINT32_MAX;
1419 pThis->cMutations = 0;
1420 pThis->fFlagsBehavioral = 0;
1421 pThis->cbMutationsAllocMax = _1G;
1422 pThis->cbMemTotal = 0;
1423 RTListInit(&pThis->LstMutationsAlloc);
1424
1425 /* Copy the default mutator descriptors over. */
1426 pThis->paMutators = (PRTFUZZMUTATOR)RTMemAllocZ(RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
1427 if (RT_LIKELY(pThis->paMutators))
1428 {
1429 pThis->cMutators = RT_ELEMENTS(g_aMutators);
1430 memcpy(&pThis->paMutators[0], &g_aMutators[0], RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
1431
1432 rc = RTSemRWCreate(&pThis->hSemRwMutations);
1433 if (RT_SUCCESS(rc))
1434 {
1435 rc = RTCritSectInit(&pThis->CritSectAlloc);
1436 if (RT_SUCCESS(rc))
1437 {
1438 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
1439 if (RT_SUCCESS(rc))
1440 {
1441 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
1442 *ppThis = pThis;
1443 return VINF_SUCCESS;
1444 }
1445
1446 RTCritSectDelete(&pThis->CritSectAlloc);
1447 }
1448
1449 RTSemRWDestroy(pThis->hSemRwMutations);
1450 }
1451 }
1452 else
1453 rc = VERR_NO_MEMORY;
1454
1455 RTMemFree(pThis);
1456 }
1457 else
1458 rc = VERR_NO_MEMORY;
1459
1460 return rc;
1461}
1462
1463
1464/**
1465 * Destroys the given fuzzing input.
1466 *
1467 * @returns nothing.
1468 * @param pThis The fuzzing input to destroy.
1469 */
1470static void rtFuzzInputDestroy(PRTFUZZINPUTINT pThis)
1471{
1472 PRTFUZZCTXINT pFuzzer = pThis->pFuzzer;
1473
1474 rtFuzzMutationRelease(pThis->pMutationTop);
1475 rtFuzzCtxMemoryFree(pFuzzer, pThis);
1476 RTFuzzCtxRelease(pFuzzer);
1477}
1478
1479
1480RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType)
1481{
1482 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1483
1484 return rtFuzzCtxCreateEmpty(phFuzzCtx, enmType);
1485}
1486
1487
1488RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
1489{
1490 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1491 AssertPtrReturn(pfnImport, VERR_INVALID_POINTER);
1492
1493#if 0
1494 int rc = VINF_SUCCESS;
1495 if (cbState >= sizeof(RTFUZZCTXSTATE))
1496 {
1497 RTFUZZCTXSTATE StateImport;
1498
1499 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
1500 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
1501 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
1502 {
1503 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
1504 if (RT_LIKELY(pThis))
1505 {
1506 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
1507 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
1508
1509 uint8_t *pbState = (uint8_t *)pvState;
1510 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
1511 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
1512 if (RT_SUCCESS(rc))
1513 {
1514 /* Go through the inputs and add them. */
1515 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
1516 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
1517
1518 uint32_t idx = 0;
1519 while ( idx < cInputs
1520 && RT_SUCCESS(rc))
1521 {
1522 size_t cbInput = 0;
1523 if (cbState >= sizeof(uint32_t))
1524 {
1525 memcpy(&cbInput, pbState, sizeof(uint32_t));
1526 cbInput = RT_LE2H_U32(cbInput);
1527 pbState += sizeof(uint32_t);
1528 }
1529
1530 if ( cbInput
1531 && cbInput <= cbState)
1532 {
1533 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
1534 if (RT_LIKELY(pInput))
1535 {
1536 memcpy(&pInput->abInput[0], pbState, cbInput);
1537 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
1538 rc = rtFuzzCtxInputAdd(pThis, pInput);
1539 if (RT_FAILURE(rc))
1540 RTMemFree(pInput);
1541 pbState += cbInput;
1542 }
1543 }
1544 else
1545 rc = VERR_INVALID_STATE;
1546
1547 idx++;
1548 }
1549
1550 if (RT_SUCCESS(rc))
1551 {
1552 *phFuzzCtx = pThis;
1553 return VINF_SUCCESS;
1554 }
1555 }
1556
1557 rtFuzzCtxDestroy(pThis);
1558 }
1559 else
1560 rc = VERR_NO_MEMORY;
1561 }
1562 else
1563 rc = VERR_INVALID_MAGIC;
1564 }
1565 else
1566 rc = VERR_INVALID_MAGIC;
1567
1568 return rc;
1569#else
1570 RT_NOREF(pvUser);
1571 return VERR_NOT_IMPLEMENTED;
1572#endif
1573}
1574
1575
1576RTDECL(int) RTFuzzCtxCreateFromStateMem(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
1577{
1578 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1579 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
1580 AssertPtrReturn(cbState, VERR_INVALID_POINTER);
1581
1582 return VERR_NOT_IMPLEMENTED;
1583}
1584
1585
1586RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
1587{
1588 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1589 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1590
1591 void *pv = NULL;
1592 size_t cb = 0;
1593 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1594 if (RT_SUCCESS(rc))
1595 {
1596 rc = RTFuzzCtxCreateFromStateMem(phFuzzCtx, pv, cb);
1597 RTFileReadAllFree(pv, cb);
1598 }
1599
1600 return rc;
1601}
1602
1603
1604RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
1605{
1606 PRTFUZZCTXINT pThis = hFuzzCtx;
1607
1608 AssertPtrReturn(pThis, UINT32_MAX);
1609
1610 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1611 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1612 return cRefs;
1613}
1614
1615
1616RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
1617{
1618 PRTFUZZCTXINT pThis = hFuzzCtx;
1619 if (pThis == NIL_RTFUZZCTX)
1620 return 0;
1621 AssertPtrReturn(pThis, UINT32_MAX);
1622
1623 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1624 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1625 if (cRefs == 0)
1626 rtFuzzCtxDestroy(pThis);
1627 return cRefs;
1628}
1629
1630
1631RTDECL(int) RTFuzzCtxQueryStats(RTFUZZCTX hFuzzCtx, PRTFUZZCTXSTATS pStats)
1632{
1633 PRTFUZZCTXINT pThis = hFuzzCtx;
1634 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1635 AssertPtrReturn(pStats, VERR_INVALID_POINTER);
1636
1637 pStats->cbMemory = ASMAtomicReadZ(&pThis->cbMemTotal);
1638 pStats->cMutations = ASMAtomicReadU64(&pThis->cMutations);
1639 return VINF_SUCCESS;
1640}
1641
1642
1643/**
1644 * Fuzzing context export callback for a single mutation.
1645 */
1646static DECLCALLBACK(int) rtFuzzCtxStateExportMutations(PAVLU64NODECORE pCore, void *pvParam)
1647{
1648 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)pCore;
1649 PCRTFUZZMUTATOR pMutator = pMutation->pMutator;
1650 PCRTFUZZEXPORTARGS pArgs = (PCRTFUZZEXPORTARGS)pvParam;
1651 RTFUZZMUTATIONSTATE MutationState;
1652
1653 MutationState.u64Id = RT_H2LE_U64(pMutation->Core.Key);
1654 if (pMutation->pMutationParent)
1655 MutationState.u64IdParent = RT_H2LE_U64(pMutation->pMutationParent->Core.Key);
1656 else
1657 MutationState.u64IdParent = RT_H2LE_U64(0);
1658 MutationState.u64OffMutation = RT_H2LE_U64(pMutation->offMutation);
1659 MutationState.cbInput = RT_H2LE_U64((uint64_t)pMutation->cbInput);
1660 MutationState.cbMutation = RT_H2LE_U64((uint64_t)pMutation->cbMutation);
1661 MutationState.u32IdMutator = RT_H2LE_U32(pMutator->uMutator);
1662 MutationState.iLvl = RT_H2LE_U32(pMutation->iLvl);
1663 MutationState.u32Magic = RT_H2LE_U32(pMutation->u32Magic);
1664
1665 int rc = pArgs->pfnExport(pMutation->pFuzzer, &MutationState, sizeof(MutationState), pArgs->pvUser);
1666 if ( RT_SUCCESS(rc)
1667 && pMutator->pfnExport)
1668 rc = pMutator->pfnExport(pMutation->pFuzzer, pMutation, &pMutation->abMutation[0], pArgs->pfnExport, pArgs->pvUser);
1669 return rc;
1670}
1671
1672
1673RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1674{
1675 PRTFUZZCTXINT pThis = hFuzzCtx;
1676 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1677 AssertPtrReturn(pfnExport, VERR_INVALID_POINTER);
1678
1679 char aszPrngExport[_4K]; /* Should be plenty of room here. */
1680 size_t cbPrng = sizeof(aszPrngExport);
1681 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
1682 if (RT_SUCCESS(rc))
1683 {
1684 RTFUZZCTXSTATE StateExport;
1685
1686 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
1687 switch (pThis->enmType)
1688 {
1689 case RTFUZZCTXTYPE_BLOB:
1690 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_BLOB);
1691 break;
1692 case RTFUZZCTXTYPE_STREAM:
1693 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_STREAM);
1694 break;
1695 default:
1696 AssertFailed();
1697 break;
1698 }
1699 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
1700 StateExport.cMutations = RT_H2LE_U32(pThis->cMutations);
1701 StateExport.cMutators = RT_H2LE_U32(pThis->cMutators);
1702 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
1703 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
1704
1705 /* Write the context state and PRNG state first. */
1706 rc = pfnExport(pThis, &StateExport, sizeof(StateExport), pvUser);
1707 if (RT_SUCCESS(rc))
1708 rc = pfnExport(pThis, &aszPrngExport[0], cbPrng, pvUser);
1709 if (RT_SUCCESS(rc))
1710 {
1711 /* Write the mutator descriptors next. */
1712 for (uint32_t i = 0; i < pThis->cMutators && RT_SUCCESS(rc); i++)
1713 {
1714 PRTFUZZMUTATOR pMutator = &pThis->paMutators[i];
1715 uint32_t cchId = (uint32_t)strlen(pMutator->pszId) + 1;
1716 uint32_t cchIdW = RT_H2LE_U32(cchId);
1717
1718 rc = pfnExport(pThis, &cchIdW, sizeof(cchIdW), pvUser);
1719 if (RT_SUCCESS(rc))
1720 rc = pfnExport(pThis, &pMutator->pszId[0], cchId, pvUser);
1721 }
1722 }
1723
1724 /* Write the mutations last. */
1725 if (RT_SUCCESS(rc))
1726 {
1727 RTFUZZEXPORTARGS Args;
1728
1729 Args.pfnExport = pfnExport;
1730 Args.pvUser = pvUser;
1731 rc = RTAvlU64DoWithAll(&pThis->TreeMutations, true /*fFromLeft*/, rtFuzzCtxStateExportMutations, &Args);
1732 }
1733 }
1734
1735 return rc;
1736}
1737
1738
1739RTDECL(int) RTFuzzCtxStateExportToMem(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
1740{
1741 PRTFUZZCTXINT pThis = hFuzzCtx;
1742 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1743 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
1744 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
1745
1746 return VERR_NOT_IMPLEMENTED;
1747}
1748
1749
1750/**
1751 * Export to file callback.
1752 */
1753static DECLCALLBACK(int) rtFuzzCtxStateExportFile(RTFUZZCTX hFuzzCtx, const void *pvBuf, size_t cbWrite, void *pvUser)
1754{
1755 RT_NOREF(hFuzzCtx);
1756
1757 RTFILE hFile = (RTFILE)pvUser;
1758 return RTFileWrite(hFile, pvBuf, cbWrite, NULL);
1759}
1760
1761
1762RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1763{
1764 PRTFUZZCTXINT pThis = hFuzzCtx;
1765 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1766 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1767
1768 RTFILE hFile;
1769 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1770 if (RT_SUCCESS(rc))
1771 {
1772 rc = RTFuzzCtxStateExport(hFuzzCtx, rtFuzzCtxStateExportFile, hFile);
1773 RTFileClose(hFile);
1774 if (RT_FAILURE(rc))
1775 RTFileDelete(pszFilename);
1776 }
1777
1778 return rc;
1779}
1780
1781
1782RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
1783{
1784 PRTFUZZCTXINT pThis = hFuzzCtx;
1785 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1786 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
1787 AssertReturn(cbInput, VERR_INVALID_POINTER);
1788
1789 int rc = VINF_SUCCESS;
1790 void *pvCorpus = NULL;
1791 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbInput, &pvCorpus);
1792 if (RT_LIKELY(pMutation))
1793 {
1794 pMutation->pMutator = &g_MutatorCorpus;
1795 pMutation->cbInput = cbInput;
1796 pMutation->pvInput = pvCorpus;
1797 memcpy(pvCorpus, pvInput, cbInput);
1798 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1799 if (RT_FAILURE(rc))
1800 rtFuzzMutationDestroy(pMutation);
1801 }
1802 else
1803 rc = VERR_NO_MEMORY;
1804
1805 return rc;
1806}
1807
1808
1809RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1810{
1811 PRTFUZZCTXINT pThis = hFuzzCtx;
1812 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1813 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1814
1815 void *pv = NULL;
1816 size_t cb = 0;
1817 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1818 if (RT_SUCCESS(rc))
1819 {
1820 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
1821 RTFileReadAllFree(pv, cb);
1822 }
1823
1824 return rc;
1825}
1826
1827
1828RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
1829{
1830 PRTFUZZCTXINT pThis = hFuzzCtx;
1831 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1832 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
1833
1834 uint64_t cbFile = 0;
1835 void *pvCorpus = NULL;
1836 int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
1837 if (RT_SUCCESS(rc))
1838 {
1839 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbFile, &pvCorpus);
1840 if (RT_LIKELY(pMutation))
1841 {
1842 pMutation->pMutator = &g_MutatorCorpus;
1843 pMutation->cbInput = cbFile;
1844 pMutation->pvInput = pvCorpus;
1845 rc = RTVfsFileRead(hVfsFile, pvCorpus, cbFile, NULL);
1846 if (RT_SUCCESS(rc))
1847 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1848
1849 if (RT_FAILURE(rc))
1850 rtFuzzMutationDestroy(pMutation);
1851 }
1852 }
1853
1854 return rc;
1855}
1856
1857
1858RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
1859{
1860 PRTFUZZCTXINT pThis = hFuzzCtx;
1861 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1862 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
1863
1864 RTDIR hDir;
1865 int rc = RTDirOpen(&hDir, pszDirPath);
1866 if (RT_SUCCESS(rc))
1867 {
1868 for (;;)
1869 {
1870 RTDIRENTRY DirEntry;
1871 rc = RTDirRead(hDir, &DirEntry, NULL);
1872 if (RT_FAILURE(rc))
1873 break;
1874
1875 /* Skip '.', '..' and other non-files. */
1876 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
1877 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1878 continue;
1879 if (RTDirEntryIsStdDotLink(&DirEntry))
1880 continue;
1881
1882 /* Compose the full path, result 'unknown' entries and skip non-files. */
1883 char szFile[RTPATH_MAX];
1884 RT_ZERO(szFile);
1885 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
1886 if (RT_FAILURE(rc))
1887 break;
1888
1889 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
1890 {
1891 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
1892 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1893 continue;
1894 }
1895
1896 /* Okay, it's a file we can add. */
1897 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
1898 if (RT_FAILURE(rc))
1899 break;
1900 }
1901 if (rc == VERR_NO_MORE_FILES)
1902 rc = VINF_SUCCESS;
1903 RTDirClose(hDir);
1904 }
1905
1906 return rc;
1907}
1908
1909
1910RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
1911{
1912 PRTFUZZCTXINT pThis = hFuzzCtx;
1913 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1914
1915 pThis->cbInputMax = cbMax;
1916 return VINF_SUCCESS;
1917}
1918
1919
1920RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
1921{
1922 PRTFUZZCTXINT pThis = hFuzzCtx;
1923 AssertPtrReturn(pThis, 0);
1924
1925 return pThis->cbInputMax;
1926}
1927
1928
1929RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
1930{
1931 PRTFUZZCTXINT pThis = hFuzzCtx;
1932 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1933 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
1934
1935 pThis->fFlagsBehavioral = fFlags;
1936 return VINF_SUCCESS;
1937}
1938
1939
1940RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
1941{
1942 PRTFUZZCTXINT pThis = hFuzzCtx;
1943 AssertPtrReturn(pThis, 0);
1944
1945 return pThis->fFlagsBehavioral;
1946}
1947
1948
1949RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
1950{
1951 PRTFUZZCTXINT pThis = hFuzzCtx;
1952 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1953 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
1954
1955 return VERR_NOT_IMPLEMENTED;
1956}
1957
1958
1959RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
1960{
1961 PRTFUZZCTXINT pThis = hFuzzCtx;
1962 AssertPtrReturn(pThis, NULL);
1963
1964 return NULL;
1965}
1966
1967
1968RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
1969{
1970 PRTFUZZCTXINT pThis = hFuzzCtx;
1971 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1972
1973 RTRandAdvSeed(pThis->hRand, uSeed);
1974 return VINF_SUCCESS;
1975}
1976
1977
1978RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
1979{
1980 int rc = VINF_SUCCESS;
1981 PRTFUZZCTXINT pThis = hFuzzCtx;
1982 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1983 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1984
1985 uint32_t cTries = 0;
1986 PRTFUZZMUTATION pMutationParent = rtFuzzCtxMutationPickRnd(pThis);
1987 do
1988 {
1989 uint32_t idxMutator = RTRandAdvU32Ex(pThis->hRand, 0, pThis->cMutators - 1);
1990 PCRTFUZZMUTATOR pMutator = &pThis->paMutators[idxMutator];
1991 PRTFUZZMUTATION pMutation = NULL;
1992
1993 uint64_t offStart = 0;
1994 if (!(pMutator->fFlags & RTFUZZMUTATOR_F_END_OF_BUF))
1995 offStart = RTRandAdvU64Ex(pThis->hRand, 0, pMutationParent->cbInput - 1);
1996 else
1997 offStart = pMutationParent->cbInput;
1998
1999 rc = pMutator->pfnPrep(pThis, offStart, pMutationParent, &pMutation);
2000 if ( RT_SUCCESS(rc)
2001 && VALID_PTR(pMutation))
2002 {
2003 pMutation->pMutator = pMutator;
2004
2005 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
2006 rtFuzzCtxMutationAdd(pThis, pMutation);
2007
2008 /* Create a new input. */
2009 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZINPUTINT));
2010 if (RT_LIKELY(pInput))
2011 {
2012 pInput->u32Magic = 0; /** @todo */
2013 pInput->cRefs = 1;
2014 pInput->pFuzzer = pThis;
2015 pInput->pMutationTop = pMutation;
2016 RTFuzzCtxRetain(pThis);
2017
2018 rtFuzzMutationRelease(pMutationParent);
2019 *phFuzzInput = pInput;
2020 return rc;
2021 }
2022 else
2023 rc = VERR_NO_MEMORY;
2024 }
2025 } while (++cTries <= 50);
2026
2027 rtFuzzMutationRelease(pMutationParent);
2028 if (RT_SUCCESS(rc))
2029 rc = VERR_INVALID_STATE;
2030
2031 return rc;
2032}
2033
2034
2035RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
2036{
2037 PRTFUZZINPUTINT pThis = hFuzzInput;
2038 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2039 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2040
2041 int rc = VINF_SUCCESS;
2042 if (!pThis->pMutationTop->pvInput)
2043 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2044
2045 if (RT_SUCCESS(rc))
2046 {
2047 *ppv = pThis->pMutationTop->pvInput;
2048 *pcb = pThis->pMutationTop->cbInput;
2049 }
2050
2051 return rc;
2052}
2053
2054
2055RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf)
2056{
2057 PRTFUZZINPUTINT pThis = hFuzzInput;
2058 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2059 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_STREAM, VERR_INVALID_STATE);
2060
2061 RT_NOREF(pvBuf, cbBuf);
2062 return VERR_NOT_IMPLEMENTED;
2063}
2064
2065
2066RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
2067{
2068 PRTFUZZINPUTINT pThis = hFuzzInput;
2069
2070 AssertPtrReturn(pThis, UINT32_MAX);
2071
2072 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
2073 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2074 return cRefs;
2075}
2076
2077
2078RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
2079{
2080 PRTFUZZINPUTINT pThis = hFuzzInput;
2081 if (pThis == NIL_RTFUZZINPUT)
2082 return 0;
2083 AssertPtrReturn(pThis, UINT32_MAX);
2084
2085 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
2086 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2087 if (cRefs == 0)
2088 rtFuzzInputDestroy(pThis);
2089 return cRefs;
2090}
2091
2092
2093RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
2094{
2095 PRTFUZZINPUTINT pThis = hFuzzInput;
2096 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2097 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2098 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
2099 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
2100
2101 int rc = VINF_SUCCESS;
2102 if (!pThis->pMutationTop->pvInput)
2103 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2104
2105 if (RT_SUCCESS(rc))
2106 {
2107 uint8_t abHash[RTMD5_HASH_SIZE];
2108 RTMd5(pThis->pMutationTop->pvInput, pThis->pMutationTop->cbInput, &abHash[0]);
2109 rc = RTMd5ToString(&abHash[0], pszDigest, cchDigest);
2110 }
2111
2112 return rc;
2113}
2114
2115
2116RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
2117{
2118 PRTFUZZINPUTINT pThis = hFuzzInput;
2119 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2120 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2121 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
2122
2123 int rc = VINF_SUCCESS;
2124 if (!pThis->pMutationTop->pvInput)
2125 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2126
2127 if (RT_SUCCESS(rc))
2128 {
2129 RTFILE hFile;
2130 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2131 if (RT_SUCCESS(rc))
2132 {
2133 rc = RTFileWrite(hFile, pThis->pMutationTop->pvInput, pThis->pMutationTop->cbInput, NULL);
2134 AssertRC(rc);
2135 RTFileClose(hFile);
2136
2137 if (RT_FAILURE(rc))
2138 RTFileDelete(pszFilename);
2139 }
2140 }
2141
2142 return rc;
2143}
2144
2145
2146RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
2147{
2148 PRTFUZZINPUTINT pThis = hFuzzInput;
2149 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2150
2151 return rtFuzzCtxMutationAdd(pThis->pFuzzer, pThis->pMutationTop);
2152}
2153
2154
2155RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
2156{
2157 PRTFUZZINPUTINT pThis = hFuzzInput;
2158 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2159
2160#if 0
2161 int rc = VINF_SUCCESS;
2162 PRTFUZZINTERMEDIATE pIntermediate = NULL;
2163 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
2164 &pIntermediate);
2165 if (pInputLoc)
2166 {
2167 AssertPtr(pIntermediate);
2168 Assert(pInputLoc == pThis);
2169
2170 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
2171 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
2172 RTFuzzInputRelease(hFuzzInput);
2173 }
2174 else
2175 rc = VERR_NOT_FOUND;
2176#endif
2177
2178 return VERR_NOT_IMPLEMENTED;
2179}
2180
Note: See TracBrowser for help on using the repository browser.

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