VirtualBox

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

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

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.5 KB
Line 
1/* $Id: fuzz.cpp 73097 2018-07-12 21:06:33Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, core.
4 */
5
6/*
7 * Copyright (C) 2018 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/ctype.h>
38#include <iprt/dir.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/list.h>
42#include <iprt/md5.h>
43#include <iprt/mem.h>
44#include <iprt/path.h>
45#include <iprt/rand.h>
46#include <iprt/string.h>
47#include <iprt/time.h>
48#include <iprt/vfs.h>
49
50
51#define RTFUZZCTX_MAGIC UINT32_C(0xdeadc0de) /** @todo */
52
53
54/*********************************************************************************************************************************
55* Structures and Typedefs *
56*********************************************************************************************************************************/
57/** Pointer to the internal fuzzer state. */
58typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
59
60/**
61 * A fuzzing input seed.
62 */
63typedef struct RTFUZZINPUTINT
64{
65 /** The AVL tree core. */
66 AVLU64NODECORE Core;
67 /** Node for the global list. */
68 RTLISTNODE NdInputs;
69 /** Reference counter. */
70 volatile uint32_t cRefs;
71/** @todo add magic here (unused padding space on 64-bit hosts). */
72 /** The fuzzer this input belongs to. */
73 PRTFUZZCTXINT pFuzzer;
74 /** Complete MD5 hash of the input data. */
75 uint8_t abMd5Hash[RTMD5_HASH_SIZE];
76 /** Size of the input data. */
77 size_t cbInput;
78 /** Input data - variable in size. */
79 uint8_t abInput[1];
80} RTFUZZINPUTINT;
81/** Pointer to the internal input state. */
82typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
83/** Pointer to an internal input state pointer. */
84typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
85
86
87/**
88 * Intermediate indexing structure.
89 */
90typedef struct RTFUZZINTERMEDIATE
91{
92 /** The AVL tree core. */
93 AVLU64NODECORE Core;
94 /** The AVL tree for indexing the input seeds (keyed by the lower half of the MD5). */
95 AVLU64TREE TreeSeedsLow;
96} RTFUZZINTERMEDIATE;
97/** Pointer to an intermediate indexing state. */
98typedef RTFUZZINTERMEDIATE *PRTFUZZINTERMEDIATE;
99/** Pointer to an intermediate indexing state pointer. */
100typedef PRTFUZZINTERMEDIATE *PPRTFUZZINTERMEDIATE;
101
102/**
103 * The fuzzer state.
104 */
105typedef struct RTFUZZCTXINT
106{
107 /** Magic value for identification. */
108 uint32_t u32Magic;
109 /** Reference counter. */
110 volatile uint32_t cRefs;
111 /** The random number generator. */
112 RTRAND hRand;
113 /** The AVL tree for indexing the input seeds (keyed by the upper half of the MD5). */
114 AVLU64TREE TreeSeedsHigh;
115 /** Sequential list of all inputs. */
116 RTLISTANCHOR LstInputs;
117 /** Number of inputs currently in the tree. */
118 uint32_t cInputs;
119 /** The maximum size of one input seed to generate. */
120 size_t cbInputMax;
121 /** Behavioral flags. */
122 uint32_t fFlagsBehavioral;
123} RTFUZZCTXINT;
124
125
126/**
127 * Available mutators enum.
128 */
129typedef enum RTFUZZCTXMUTATOR
130{
131 /** Invalid mutator, not used. */
132 RTFUZZCTXMUTATOR_INVALID = 0,
133 /** Flips a single bit in the input. */
134 RTFUZZCTXMUTATOR_BIT_FLIP,
135 /** Replaces a single byte in the input. */
136 RTFUZZCTXMUTATOR_BYTE_REPLACE,
137 /** Inserts a byte sequence into the input. */
138 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_INSERT,
139 /** Appends a byte sequence to the input. */
140 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_APPEND,
141 /** Deletes a single byte from the input. */
142 RTFUZZCTXMUTATOR_BYTE_DELETE,
143 /** Deletes a sequence of bytes from the input. */
144 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
145 /** Last valid mutator. */
146 RTFUZZCTXMUTATOR_LAST = RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
147 /** 32bit hack. */
148 RTFUZZCTXMUTATOR_32BIT_HACK = 0x7fffffff
149} RTFUZZCTXMUTATOR;
150/** Pointer to a mutator enum. */
151typedef RTFUZZCTXMUTATOR *PRTFUZZCTXMUTATOR;
152
153
154/**
155 * The fuzzer state to be exported - all members are stored in little endian form.
156 */
157typedef struct RTFUZZCTXSTATE
158{
159 /** Magic value for identification. */
160 uint32_t u32Magic;
161 /** Size of the PRNG state following in bytes. */
162 uint32_t cbPrng;
163 /** Number of input descriptors following. */
164 uint32_t cInputs;
165 /** Behavioral flags. */
166 uint32_t fFlagsBehavioral;
167 /** Maximum input size to generate. */
168 uint64_t cbInputMax;
169} RTFUZZCTXSTATE;
170/** Pointer to a fuzzing context state. */
171typedef RTFUZZCTXSTATE *PRTFUZZCTXSTATE;
172
173
174/**
175 * Mutator callback.
176 *
177 * @returns IPRT status code.
178 * @param pThis The fuzzer context instance.
179 * @param pvBuf The input buffer to mutate.
180 * @param cbBuf Size of the buffer in bytes.
181 * @param ppInputMutated Where to store the pointer to the mutated input success.
182 */
183typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOR(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated);
184/** Pointer to a mutator callback. */
185typedef FNRTFUZZCTXMUTATOR *PFNRTFUZZCTXMUTATOR;
186
187
188/*********************************************************************************************************************************
189* Internal Functions *
190*********************************************************************************************************************************/
191static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
192 PPRTFUZZINPUTINT ppInputMutated);
193static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
194 PPRTFUZZINPUTINT ppInputMutated);
195static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
196 PPRTFUZZINPUTINT ppInputMutated);
197static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
198 PPRTFUZZINPUTINT ppInputMutated);
199static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
200 PPRTFUZZINPUTINT ppInputMutated);
201static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
202 PPRTFUZZINPUTINT ppInputMutated);
203
204
205/*********************************************************************************************************************************
206* Global Variables *
207*********************************************************************************************************************************/
208/**
209 * Array of all available mutators.
210 */
211static PFNRTFUZZCTXMUTATOR const g_apfnMutators[] =
212{
213 NULL,
214 rtFuzzCtxMutatorBitFlip,
215 rtFuzzCtxMutatorByteReplace,
216 rtFuzzCtxMutatorByteSequenceInsert,
217 rtFuzzCtxMutatorByteSequenceAppend,
218 rtFuzzCtxMutatorByteDelete,
219 rtFuzzCtxMutatorByteSequenceDelete,
220 NULL
221};
222
223
224
225/**
226 * Tries to locate an input seed with the given input MD5 seed.
227 *
228 * @returns Pointer to the input seed on success or NULL if not found.
229 * @param pThis The fuzzer context instance.
230 * @param pbMd5Hash The MD5 hash to search for.
231 * @param fExact Flag whether to search for an exact match or return the next best fit if no match exists.
232 * @param ppIntermediate Where to store the pointer to the intermediate layer upon success, optional.
233 */
234static PRTFUZZINPUTINT rtFuzzCtxInputLocate(PRTFUZZCTXINT pThis, uint8_t *pbMd5Hash, bool fExact, PPRTFUZZINTERMEDIATE ppIntermediate)
235{
236 PRTFUZZINPUTINT pInput = NULL;
237 uint64_t u64Md5High = *(uint64_t *)&pbMd5Hash[RTMD5_HASH_SIZE / 2];
238 uint64_t u64Md5Low = *(uint64_t *)&pbMd5Hash[0];
239 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
240 if (!fExact && !pIntermediate)
241 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, true /*fAbove*/);
242 if (!fExact && !pIntermediate)
243 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, false /*fAbove*/);
244
245 if (pIntermediate)
246 {
247 /* 2nd level lookup. */
248 pInput = (PRTFUZZINPUTINT)RTAvlU64Get(&pIntermediate->TreeSeedsLow, u64Md5Low);
249 if (!fExact && !pInput)
250 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, true /*fAbove*/);
251 if (!fExact && !pInput)
252 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, false /*fAbove*/);
253 }
254
255 if (ppIntermediate)
256 *ppIntermediate = pIntermediate;
257
258 return pInput;
259}
260
261
262/**
263 * Adds the given input to the corpus of the given fuzzer context.
264 *
265 * @returns IPRT status code.
266 * @param pThis The fuzzer context instance.
267 * @param pInput The input to add.
268 */
269static int rtFuzzCtxInputAdd(PRTFUZZCTXINT pThis, PRTFUZZINPUTINT pInput)
270{
271 int rc = VINF_SUCCESS;
272 uint64_t u64Md5High = *(uint64_t *)&pInput->abMd5Hash[RTMD5_HASH_SIZE / 2];
273 uint64_t u64Md5Low = *(uint64_t *)&pInput->abMd5Hash[0];
274
275 pInput->Core.Key = u64Md5Low;
276 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
277 if (!pIntermediate)
278 {
279 pIntermediate = (PRTFUZZINTERMEDIATE)RTMemAllocZ(sizeof(*pIntermediate));
280 if (RT_LIKELY(pIntermediate))
281 {
282 pIntermediate->Core.Key = u64Md5High;
283 pIntermediate->TreeSeedsLow = NULL;
284 bool fIns = RTAvlU64Insert(&pThis->TreeSeedsHigh, &pIntermediate->Core);
285 Assert(fIns); RT_NOREF(fIns);
286 }
287 else
288 rc = VERR_NO_MEMORY;
289 }
290
291 if (RT_SUCCESS(rc))
292 {
293 AssertPtr(pIntermediate);
294 bool fIns = RTAvlU64Insert(&pIntermediate->TreeSeedsLow, &pInput->Core);
295 if (!fIns)
296 rc = VERR_ALREADY_EXISTS;
297 else
298 {
299 RTListAppend(&pThis->LstInputs, &pInput->NdInputs);
300 pThis->cInputs++;
301 RTFuzzInputRetain(pInput);
302 }
303 }
304
305 return rc;
306}
307
308
309/**
310 * Returns a random input from the corpus of the given fuzzer context.
311 *
312 * @returns Pointer to a randomly picked input.
313 * @param pThis The fuzzer context instance.
314 */
315static PRTFUZZINPUTINT rtFuzzCtxInputPickRnd(PRTFUZZCTXINT pThis)
316{
317 /* Generate a random MD5 hash and do a non exact localisation. */
318 uint8_t abDigestRnd[RTMD5_HASH_SIZE];
319 RTRandAdvBytes(pThis->hRand, &abDigestRnd[0], sizeof(abDigestRnd));
320
321 return rtFuzzCtxInputLocate(pThis, &abDigestRnd[0], false /*fExact*/, NULL /*ppIntermediate*/);
322}
323
324
325/**
326 * Clones a given input.
327 *
328 * @returns Pointer to the cloned input or NULL if out of memory.
329 * @param pThis The fuzzer context instance.
330 * @param pvBuf The buffer to clone.
331 * @param cbBuf Size of the buffer in bytes.
332 */
333static PRTFUZZINPUTINT rtFuzzCtxInputClone(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf)
334{
335 PRTFUZZINPUTINT pInpClone = (PRTFUZZINPUTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTFUZZINPUTINT, abInput[cbBuf]));
336 if (RT_LIKELY(pInpClone))
337 {
338 pInpClone->cRefs = 1;
339 pInpClone->pFuzzer = pThis,
340 pInpClone->cbInput = cbBuf;
341 memcpy(&pInpClone->abInput[0], pvBuf, cbBuf);
342 }
343
344 return pInpClone;
345}
346
347
348/**
349 * Creates an empty input seed capable of holding the given number of bytes.
350 *
351 * @returns Pointer to the newly created input seed.
352 * @param pThis The fuzzer context instance.
353 * @param cbInput Input seed size in bytes.
354 */
355static PRTFUZZINPUTINT rtFuzzCtxInputCreate(PRTFUZZCTXINT pThis, size_t cbInput)
356{
357 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTFUZZINPUTINT, abInput[cbInput]));
358 if (RT_LIKELY(pInput))
359 {
360 pInput->pFuzzer = pThis;
361 pInput->cRefs = 1;
362 pInput->cbInput = cbInput;
363 }
364
365 return pInput;
366}
367
368
369/**
370 * Destroys the given input.
371 *
372 * @returns nothing.
373 * @param pInput The input to destroy.
374 */
375static void rtFuzzInputDestroy(PRTFUZZINPUTINT pInput)
376{
377 RTMemFree(pInput);
378}
379
380
381/**
382 * Destorys the given fuzzer context freeing all allocated resources.
383 *
384 * @returns nothing.
385 * @param pThis The fuzzer context instance.
386 */
387static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
388{
389 RT_NOREF(pThis);
390}
391
392
393/**
394 * Mutator callback - flips a single bit in the input.
395 */
396static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
397{
398 int rc = VINF_SUCCESS;
399 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pThis, pvBuf, cbBuf);
400 if (RT_LIKELY(pInputMutated))
401 {
402 int32_t iBit = RTRandAdvS32Ex(pThis->hRand, 0, (uint32_t)cbBuf * 8 - 1);
403 ASMBitToggle(&pInputMutated->abInput[0], iBit);
404 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
405 *ppInputMutated = pInputMutated;
406 }
407 else
408 rc = VERR_NO_MEMORY;
409
410 return rc;
411}
412
413
414/**
415 * Mutator callback - replaces a single byte in the input.
416 */
417static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
418{
419 int rc = VINF_SUCCESS;
420 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pThis, pvBuf, cbBuf);
421 if (RT_LIKELY(pInputMutated))
422 {
423 uint8_t *pbBuf = (uint8_t *)pvBuf;
424 uint32_t offByte = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf - 1);
425 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offByte], 1);
426 if (pbBuf[offByte] != pInputMutated->abInput[offByte])
427 {
428 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
429 *ppInputMutated = pInputMutated;
430 }
431 else
432 RTMemFree(pInputMutated);
433 }
434 else
435 rc = VERR_NO_MEMORY;
436
437 return rc;
438}
439
440
441/**
442 * Mutator callback - inserts a byte sequence into the input.
443 */
444static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
445{
446 int rc = VINF_SUCCESS;
447 if (cbBuf < pThis->cbInputMax)
448 {
449 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)cbBuf + 1, (uint32_t)pThis->cbInputMax);
450 size_t cbInsert = cbInputMutated - cbBuf;
451 uint32_t offInsert = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf);
452 uint8_t *pbBuf = (uint8_t *)pvBuf;
453 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
454 if (RT_LIKELY(pInputMutated))
455 {
456 if (offInsert)
457 memcpy(&pInputMutated->abInput[0], pbBuf, offInsert);
458 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offInsert], cbInsert);
459 memcpy(&pInputMutated->abInput[offInsert + cbInsert], &pbBuf[offInsert], cbBuf - offInsert);
460 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
461 *ppInputMutated = pInputMutated;
462 }
463 else
464 rc = VERR_NO_MEMORY;
465 }
466
467 return rc;
468}
469
470
471/**
472 * Mutator callback - appends a byte sequence to the input.
473 */
474static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
475{
476 int rc = VINF_SUCCESS;
477 if (cbBuf < pThis->cbInputMax)
478 {
479 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)cbBuf + 1, (uint32_t)pThis->cbInputMax);
480 size_t cbInsert = cbInputMutated - cbBuf;
481 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
482 if (RT_LIKELY(pInputMutated))
483 {
484 memcpy(&pInputMutated->abInput[0], pvBuf, cbBuf);
485 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[cbBuf], cbInsert);
486 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
487 *ppInputMutated = pInputMutated;
488 }
489 else
490 rc = VERR_NO_MEMORY;
491 }
492
493 return rc;
494}
495
496
497/**
498 * Mutator callback - deletes a single byte in the input.
499 */
500static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
501{
502 int rc = VINF_SUCCESS;
503 if (cbBuf > 1)
504 {
505 uint32_t offDelete = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf - 1);
506 uint8_t *pbBuf = (uint8_t *)pvBuf;
507 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbBuf - 1);
508 if (RT_LIKELY(pInputMutated))
509 {
510 if (offDelete)
511 memcpy(&pInputMutated->abInput[0], pbBuf, offDelete);
512 if (offDelete < cbBuf - 1)
513 memcpy(&pInputMutated->abInput[offDelete], &pbBuf[offDelete + 1], cbBuf - offDelete - 1);
514 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
515 *ppInputMutated = pInputMutated;
516 }
517 else
518 rc = VERR_NO_MEMORY;
519 }
520
521 return rc;
522}
523
524
525/**
526 * Mutator callback - deletes a byte sequence in the input.
527 */
528static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
529{
530 int rc = VINF_SUCCESS;
531 if (cbBuf > 1)
532 {
533 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf - 1);
534 size_t cbDel = cbBuf - cbInputMutated;
535 uint32_t offDel = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)(cbBuf - cbDel));
536 uint8_t *pbBuf = (uint8_t *)pvBuf;
537
538 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
539 if (RT_LIKELY(pInputMutated))
540 {
541 if (offDel)
542 memcpy(&pInputMutated->abInput[0], pbBuf, offDel);
543 memcpy(&pInputMutated->abInput[offDel], &pbBuf[offDel + cbDel], cbBuf - offDel - cbDel);
544 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
545 *ppInputMutated = pInputMutated;
546 }
547 else
548 rc = VERR_NO_MEMORY;
549 }
550
551 return rc;
552}
553
554
555static PRTFUZZCTXINT rtFuzzCtxCreateEmpty(void)
556{
557 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
558 if (RT_LIKELY(pThis))
559 {
560 pThis->u32Magic = RTFUZZCTX_MAGIC;
561 pThis->cRefs = 1;
562 pThis->TreeSeedsHigh = NULL;
563 pThis->cbInputMax = UINT32_MAX;
564 pThis->cInputs = 0;
565 pThis->fFlagsBehavioral = 0;
566 RTListInit(&pThis->LstInputs);
567
568 int rc = RTRandAdvCreateParkMiller(&pThis->hRand);
569 if (RT_SUCCESS(rc))
570 {
571 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
572 return pThis;
573 }
574
575 RTMemFree(pThis);
576 }
577
578 return NULL;
579}
580
581
582RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx)
583{
584 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
585
586 int rc = VINF_SUCCESS;
587 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
588 if (RT_LIKELY(pThis))
589 {
590 *phFuzzCtx = pThis;
591 return VINF_SUCCESS;
592 }
593 else
594 rc = VERR_NO_MEMORY;
595
596 return rc;
597}
598
599
600RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
601{
602 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
603 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
604 AssertReturn(cbState > 0, VERR_INVALID_PARAMETER);
605
606 int rc = VINF_SUCCESS;
607 if (cbState >= sizeof(RTFUZZCTXSTATE))
608 {
609 RTFUZZCTXSTATE StateImport;
610
611 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
612 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
613 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
614 {
615 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
616 if (RT_LIKELY(pThis))
617 {
618 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
619 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
620
621 uint8_t *pbState = (uint8_t *)pvState;
622 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
623 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
624 if (RT_SUCCESS(rc))
625 {
626 /* Go through the inputs and add them. */
627 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
628 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
629
630 uint32_t idx = 0;
631 while ( idx < cInputs
632 && RT_SUCCESS(rc))
633 {
634 size_t cbInput = 0;
635 if (cbState >= sizeof(uint32_t))
636 {
637 memcpy(&cbInput, pbState, sizeof(uint32_t));
638 cbInput = RT_LE2H_U32(cbInput);
639 pbState += sizeof(uint32_t);
640 }
641
642 if ( cbInput
643 && cbInput <= cbState)
644 {
645 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
646 if (RT_LIKELY(pInput))
647 {
648 memcpy(&pInput->abInput[0], pbState, cbInput);
649 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
650 rc = rtFuzzCtxInputAdd(pThis, pInput);
651 if (RT_FAILURE(rc))
652 RTMemFree(pInput);
653 pbState += cbInput;
654 }
655 }
656 else
657 rc = VERR_INVALID_STATE;
658
659 idx++;
660 }
661
662 if (RT_SUCCESS(rc))
663 {
664 *phFuzzCtx = pThis;
665 return VINF_SUCCESS;
666 }
667 }
668
669 rtFuzzCtxDestroy(pThis);
670 }
671 else
672 rc = VERR_NO_MEMORY;
673 }
674 else
675 rc = VERR_INVALID_MAGIC;
676 }
677 else
678 rc = VERR_INVALID_MAGIC;
679
680 return rc;
681}
682
683
684RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
685{
686 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
687 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
688
689 void *pv = NULL;
690 size_t cb = 0;
691 int rc = RTFileReadAll(pszFilename, &pv, &cb);
692 if (RT_SUCCESS(rc))
693 {
694 rc = RTFuzzCtxCreateFromState(phFuzzCtx, pv, cb);
695 RTFileReadAllFree(pv, cb);
696 }
697
698 return rc;
699}
700
701
702RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
703{
704 PRTFUZZCTXINT pThis = hFuzzCtx;
705
706 AssertPtrReturn(pThis, UINT32_MAX);
707
708 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
709 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
710 return cRefs;
711}
712
713
714RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
715{
716 PRTFUZZCTXINT pThis = hFuzzCtx;
717 if (pThis == NIL_RTFUZZCTX)
718 return 0;
719 AssertPtrReturn(pThis, UINT32_MAX);
720
721 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
722 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
723 if (cRefs == 0)
724 rtFuzzCtxDestroy(pThis);
725 return cRefs;
726}
727
728
729RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
730{
731 PRTFUZZCTXINT pThis = hFuzzCtx;
732 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
733 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
734 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
735
736 char aszPrngExport[_4K]; /* Should be plenty of room here. */
737 size_t cbPrng = sizeof(aszPrngExport);
738 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
739 if (RT_SUCCESS(rc))
740 {
741 RTFUZZCTXSTATE StateExport;
742
743 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
744 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
745 StateExport.cInputs = RT_H2LE_U32(pThis->cInputs);
746 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
747 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
748
749 /* Estimate the size of the required state. */
750 size_t cbState = sizeof(StateExport)
751 + cbPrng
752 + pThis->cInputs * ((pThis->cbInputMax < _1M ? pThis->cbInputMax : _64K) + sizeof(uint32_t)); /* For the size indicator before each input. */
753 uint8_t *pbState = (uint8_t *)RTMemAllocZ(cbState);
754 if (RT_LIKELY(pbState))
755 {
756 size_t offState = 0;
757 memcpy(pbState, &StateExport, sizeof(StateExport));
758 offState += sizeof(StateExport);
759 memcpy(&pbState[offState], &aszPrngExport[0], cbPrng);
760 offState += cbPrng;
761
762 /* Export each input. */
763 PRTFUZZINPUTINT pIt;
764 RTListForEach(&pThis->LstInputs, pIt, RTFUZZINPUTINT, NdInputs)
765 {
766 /* Ensure buffer size. */
767 if (offState + pIt->cbInput + sizeof(uint32_t) > cbState)
768 {
769 uint8_t *pbStateNew = (uint8_t *)RTMemRealloc(pbState, cbState + pIt->cbInput + sizeof(uint32_t));
770 if (RT_LIKELY(pbStateNew))
771 {
772 pbState = pbStateNew;
773 cbState += pIt->cbInput + sizeof(uint32_t);
774 }
775 else
776 {
777 rc = VERR_NO_MEMORY;
778 break;
779 }
780 }
781
782 *(uint32_t *)&pbState[offState] = RT_H2LE_U32((uint32_t)pIt->cbInput);
783 offState += sizeof(uint32_t);
784 memcpy(&pbState[offState], &pIt->abInput[0], pIt->cbInput);
785 offState += pIt->cbInput;
786 }
787
788 if (RT_SUCCESS(rc))
789 {
790 *ppvState = pbState;
791 *pcbState = offState;
792 }
793 else
794 RTMemFree(pbState);
795 }
796 else
797 rc = VERR_NO_MEMORY;
798 }
799
800 return rc;
801}
802
803
804RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
805{
806 PRTFUZZCTXINT pThis = hFuzzCtx;
807 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
808 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
809
810 void *pvState = NULL;
811 size_t cbState = 0;
812 int rc = RTFuzzCtxStateExport(hFuzzCtx, &pvState, &cbState);
813 if (RT_SUCCESS(rc))
814 {
815 RTFILE hFile;
816
817 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
818 if (RT_SUCCESS(rc))
819 {
820 rc = RTFileWrite(hFile, pvState, cbState, NULL);
821 RTFileClose(hFile);
822 if (RT_FAILURE(rc))
823 RTFileDelete(pszFilename);
824 }
825
826 RTMemFree(pvState);
827 }
828
829 return rc;
830}
831
832
833RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
834{
835 PRTFUZZCTXINT pThis = hFuzzCtx;
836 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
837 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
838 AssertReturn(cbInput, VERR_INVALID_POINTER);
839
840 /* Generate MD5 checksum and try to locate input. */
841 int rc = VINF_SUCCESS;
842 uint8_t abDigest[RTMD5_HASH_SIZE];
843 RTMd5(pvInput, cbInput, &abDigest[0]);
844
845 PRTFUZZINPUTINT pInput = rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/);
846 if (!pInput)
847 {
848 pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTFUZZINPUTINT, abInput[cbInput]));
849 if (RT_LIKELY(pInput))
850 {
851 pInput->cRefs = 1;
852 pInput->pFuzzer = pThis;
853 pInput->cbInput = cbInput;
854 memcpy(&pInput->abInput[0], pvInput, cbInput);
855 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
856 rc = rtFuzzCtxInputAdd(pThis, pInput);
857 if (RT_FAILURE(rc))
858 RTMemFree(pInput);
859 }
860 else
861 rc = VERR_NO_MEMORY;
862 }
863 else
864 rc = VERR_ALREADY_EXISTS;
865
866 return rc;
867}
868
869
870RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
871{
872 PRTFUZZCTXINT pThis = hFuzzCtx;
873 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
874 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
875
876 void *pv = NULL;
877 size_t cb = 0;
878 int rc = RTFileReadAll(pszFilename, &pv, &cb);
879 if (RT_SUCCESS(rc))
880 {
881 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
882 RTFileReadAllFree(pv, cb);
883 }
884
885 return rc;
886}
887
888
889RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
890{
891 PRTFUZZCTXINT pThis = hFuzzCtx;
892 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
893 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
894
895 uint64_t cbFile = 0;
896 int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
897 if (RT_SUCCESS(rc))
898 {
899 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTFUZZINPUTINT, abInput[cbFile]));
900 if (RT_LIKELY(pInput))
901 {
902 pInput->cRefs = 1;
903 pInput->pFuzzer = pThis;
904 pInput->cbInput = cbFile;
905
906 rc = RTVfsFileRead(hVfsFile, &pInput->abInput[0], cbFile, NULL);
907 if (RT_SUCCESS(rc))
908 {
909 /* Generate MD5 checksum and try to locate input. */
910 uint8_t abDigest[RTMD5_HASH_SIZE];
911 RTMd5(&pInput->abInput[0], cbFile, &abDigest[0]);
912
913 if (!rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/))
914 {
915 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
916 rc = rtFuzzCtxInputAdd(pThis, pInput);
917 }
918 else
919 rc = VERR_ALREADY_EXISTS;
920 }
921
922 if (RT_FAILURE(rc))
923 RTMemFree(pInput);
924 }
925 else
926 rc = VERR_NO_MEMORY;
927 }
928
929 return rc;
930}
931
932
933RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
934{
935 PRTFUZZCTXINT pThis = hFuzzCtx;
936 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
937 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
938
939 RTDIR hDir;
940 int rc = RTDirOpen(&hDir, pszDirPath);
941 if (RT_SUCCESS(rc))
942 {
943 for (;;)
944 {
945 RTDIRENTRY DirEntry;
946 rc = RTDirRead(hDir, &DirEntry, NULL);
947 if (RT_FAILURE(rc))
948 break;
949
950 /* Skip '.', '..' and other non-files. */
951 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
952 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
953 continue;
954 if (RTDirEntryIsStdDotLink(&DirEntry))
955 continue;
956
957 /* Compose the full path, result 'unknown' entries and skip non-files. */
958 char szFile[RTPATH_MAX];
959 RT_ZERO(szFile);
960 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
961 if (RT_FAILURE(rc))
962 break;
963
964 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
965 {
966 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
967 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
968 continue;
969 }
970
971 /* Okay, it's a file we can add. */
972 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
973 if (RT_FAILURE(rc))
974 break;
975 }
976 if (rc == VERR_NO_MORE_FILES)
977 rc = VINF_SUCCESS;
978 RTDirClose(hDir);
979 }
980
981 return rc;
982}
983
984
985RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
986{
987 PRTFUZZCTXINT pThis = hFuzzCtx;
988 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
989
990 pThis->cbInputMax = cbMax;
991 return VINF_SUCCESS;
992}
993
994
995RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
996{
997 PRTFUZZCTXINT pThis = hFuzzCtx;
998 AssertPtrReturn(pThis, 0);
999
1000 return pThis->cbInputMax;
1001}
1002
1003
1004RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
1005{
1006 PRTFUZZCTXINT pThis = hFuzzCtx;
1007 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1008 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
1009
1010 pThis->fFlagsBehavioral = fFlags;
1011 return VINF_SUCCESS;
1012}
1013
1014
1015RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
1016{
1017 PRTFUZZCTXINT pThis = hFuzzCtx;
1018 AssertPtrReturn(pThis, 0);
1019
1020 return pThis->fFlagsBehavioral;
1021}
1022
1023
1024RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
1025{
1026 PRTFUZZCTXINT pThis = hFuzzCtx;
1027 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1028 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
1029
1030 return VERR_NOT_IMPLEMENTED;
1031}
1032
1033
1034RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
1035{
1036 PRTFUZZCTXINT pThis = hFuzzCtx;
1037 AssertPtrReturn(pThis, NULL);
1038
1039 return NULL;
1040}
1041
1042
1043RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
1044{
1045 PRTFUZZCTXINT pThis = hFuzzCtx;
1046 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1047
1048 RTRandAdvSeed(pThis->hRand, uSeed);
1049 return VINF_SUCCESS;
1050}
1051
1052
1053RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
1054{
1055 int rc = VINF_SUCCESS;
1056 PRTFUZZCTXINT pThis = hFuzzCtx;
1057 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1058 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1059
1060 uint32_t cTries = 0;
1061 PRTFUZZINPUTINT pSrc = rtFuzzCtxInputPickRnd(pThis);
1062 do
1063 {
1064 RTFUZZCTXMUTATOR enmMutator = (RTFUZZCTXMUTATOR)RTRandAdvU32Ex(pThis->hRand, 1, RTFUZZCTXMUTATOR_LAST);
1065 PRTFUZZINPUTINT pInput = NULL;
1066 rc = g_apfnMutators[enmMutator](pThis, &pSrc->abInput[0], pSrc->cbInput, &pInput);
1067 if ( RT_SUCCESS(rc)
1068 && VALID_PTR(pInput))
1069 {
1070 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
1071 rtFuzzCtxInputAdd(pThis, pInput);
1072 *phFuzzInput = pInput;
1073 return rc;
1074 }
1075 } while (++cTries <= 50);
1076
1077 if (RT_SUCCESS(rc))
1078 rc = VERR_INVALID_STATE;
1079
1080 return rc;
1081}
1082
1083
1084RTDECL(int) RTFuzzCtxMutateBuffer(RTFUZZCTX hFuzzCtx, void *pvBuf, size_t cbBuf, PRTFUZZINPUT phFuzzInput)
1085{
1086 int rc = VINF_SUCCESS;
1087 PRTFUZZCTXINT pThis = hFuzzCtx;
1088 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1089 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1090
1091 uint32_t cTries = 0;
1092 do
1093 {
1094 RTFUZZCTXMUTATOR enmMutator = (RTFUZZCTXMUTATOR)RTRandAdvU32Ex(pThis->hRand, 1, RTFUZZCTXMUTATOR_LAST);
1095 PRTFUZZINPUTINT pInput = NULL;
1096 rc = g_apfnMutators[enmMutator](pThis, pvBuf, cbBuf, &pInput);
1097 if ( RT_SUCCESS(rc)
1098 && VALID_PTR(pInput))
1099 {
1100 *phFuzzInput = pInput;
1101 return rc;
1102 }
1103 } while (++cTries <= 50);
1104
1105 if (RT_SUCCESS(rc))
1106 rc = VERR_INVALID_STATE;
1107
1108 return rc;
1109}
1110
1111
1112RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
1113{
1114 PRTFUZZINPUTINT pThis = hFuzzInput;
1115
1116 AssertPtrReturn(pThis, UINT32_MAX);
1117
1118 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1119 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1120 return cRefs;
1121}
1122
1123
1124RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
1125{
1126 PRTFUZZINPUTINT pThis = hFuzzInput;
1127 if (pThis == NIL_RTFUZZINPUT)
1128 return 0;
1129 AssertPtrReturn(pThis, UINT32_MAX);
1130
1131 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1132 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1133 if (cRefs == 0)
1134 rtFuzzInputDestroy(pThis);
1135 return cRefs;
1136}
1137
1138
1139RTDECL(int) RTFuzzInputQueryData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
1140{
1141 PRTFUZZINPUTINT pThis = hFuzzInput;
1142 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1143 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
1144 AssertPtrReturn(pcb, VERR_INVALID_POINTER);
1145
1146 *ppv = &pThis->abInput[0];
1147 *pcb = pThis->cbInput;
1148 return VINF_SUCCESS;
1149}
1150
1151
1152RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
1153{
1154 PRTFUZZINPUTINT pThis = hFuzzInput;
1155 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1156 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
1157 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
1158
1159 return RTMd5ToString(&pThis->abMd5Hash[0], pszDigest, cchDigest);
1160}
1161
1162
1163RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
1164{
1165 PRTFUZZINPUTINT pThis = hFuzzInput;
1166 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1167 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1168
1169 RTFILE hFile;
1170 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1171 if (RT_SUCCESS(rc))
1172 {
1173 rc = RTFileWrite(hFile, &pThis->abInput[0], pThis->cbInput, NULL);
1174 AssertRC(rc);
1175 RTFileClose(hFile);
1176
1177 if (RT_FAILURE(rc))
1178 RTFileDelete(pszFilename);
1179 }
1180
1181 return rc;
1182}
1183
1184
1185RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
1186{
1187 PRTFUZZINPUTINT pThis = hFuzzInput;
1188 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1189
1190 return rtFuzzCtxInputAdd(pThis->pFuzzer, pThis);
1191}
1192
1193
1194RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
1195{
1196 PRTFUZZINPUTINT pThis = hFuzzInput;
1197 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1198
1199 int rc = VINF_SUCCESS;
1200 PRTFUZZINTERMEDIATE pIntermediate = NULL;
1201 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
1202 &pIntermediate);
1203 if (pInputLoc)
1204 {
1205 AssertPtr(pIntermediate);
1206 Assert(pInputLoc == pThis);
1207
1208 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
1209 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
1210 RTFuzzInputRelease(hFuzzInput);
1211 }
1212 else
1213 rc = VERR_NOT_FOUND;
1214
1215 return rc;
1216}
1217
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