VirtualBox

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

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

Runtime/fuzz: Add mutators to change possible integers to some interesting ones and to crossover two different mutations. Cache the generated data up to a certain threshold to avoid alaways recreating the whole mutation

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