VirtualBox

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

Last change on this file was 99803, checked in by vboxsync, 12 months ago

Runtime/fuzz.cpp: Fix assertion, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use