VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fuzz/fuzz-target-recorder.cpp@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: fuzz-target-recorder.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, target state recorder.
4 */
5
6/*
7 * Copyright (C) 2019-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/crc.h>
48#include <iprt/ctype.h>
49#include <iprt/err.h>
50#include <iprt/file.h>
51#include <iprt/list.h>
52#include <iprt/mem.h>
53#include <iprt/path.h>
54#include <iprt/pipe.h>
55#include <iprt/process.h>
56#include <iprt/semaphore.h>
57#include <iprt/string.h>
58
59
60
61/*********************************************************************************************************************************
62* Structures and Typedefs *
63*********************************************************************************************************************************/
64/** Pointer to the internal fuzzed target recorder state. */
65typedef struct RTFUZZTGTRECINT *PRTFUZZTGTRECINT;
66
67
68/**
69 * Stdout/Stderr buffer.
70 */
71typedef struct RTFUZZTGTSTDOUTERRBUF
72{
73 /** Current amount buffered. */
74 size_t cbBuf;
75 /** Maxmium amount to buffer. */
76 size_t cbBufMax;
77 /** Base pointer to the data buffer. */
78 uint8_t *pbBase;
79} RTFUZZTGTSTDOUTERRBUF;
80/** Pointer to a stdout/stderr buffer. */
81typedef RTFUZZTGTSTDOUTERRBUF *PRTFUZZTGTSTDOUTERRBUF;
82
83
84/**
85 * Internal fuzzed target state.
86 */
87typedef struct RTFUZZTGTSTATEINT
88{
89 /** Node for the list of states. */
90 RTLISTNODE NdStates;
91 /** Checksum for the state. */
92 uint64_t uChkSum;
93 /** Magic identifying the structure. */
94 uint32_t u32Magic;
95 /** Reference counter. */
96 volatile uint32_t cRefs;
97 /** The owning recorder instance. */
98 PRTFUZZTGTRECINT pTgtRec;
99 /** Flag whether the state is finalized. */
100 bool fFinalized;
101 /** Flag whether the state is contained in the recorded set. */
102 bool fInRecSet;
103 /** The stdout data buffer. */
104 RTFUZZTGTSTDOUTERRBUF StdOutBuf;
105 /** The stderr data buffer. */
106 RTFUZZTGTSTDOUTERRBUF StdErrBuf;
107 /** Process status. */
108 RTPROCSTATUS ProcSts;
109 /** Coverage report buffer. */
110 void *pvCovReport;
111 /** Size of the coverage report in bytes. */
112 size_t cbCovReport;
113 /** Number of traced edges. */
114 size_t cEdges;
115} RTFUZZTGTSTATEINT;
116/** Pointer to an internal fuzzed target state. */
117typedef RTFUZZTGTSTATEINT *PRTFUZZTGTSTATEINT;
118
119
120/**
121 * Recorder states node in the AVL tree.
122 */
123typedef struct RTFUZZTGTRECNODE
124{
125 /** The AVL tree core (keyed by checksum). */
126 AVLU64NODECORE Core;
127 /** The list anchor for the individual states. */
128 RTLISTANCHOR LstStates;
129} RTFUZZTGTRECNODE;
130/** Pointer to a recorder states node. */
131typedef RTFUZZTGTRECNODE *PRTFUZZTGTRECNODE;
132
133
134/**
135 * Edge information node.
136 */
137typedef struct RTFUZZTGTEDGE
138{
139 /** The AVL tree core (keyed by offset). */
140 AVLU64NODECORE Core;
141 /** Number of times the edge was hit. */
142 volatile uint64_t cHits;
143} RTFUZZTGTEDGE;
144/** Pointer to a edge information node. */
145typedef RTFUZZTGTEDGE *PRTFUZZTGTEDGE;
146
147
148/**
149 * Internal fuzzed target recorder state.
150 */
151typedef struct RTFUZZTGTRECINT
152{
153 /** Magic value for identification. */
154 uint32_t u32Magic;
155 /** Reference counter. */
156 volatile uint32_t cRefs;
157 /** Flags passed when the recorder was created. */
158 uint32_t fRecFlags;
159 /** Semaphore protecting the states tree. */
160 RTSEMRW hSemRwStates;
161 /** The AVL tree for indexing the recorded state (keyed by stdout/stderr buffer size). */
162 AVLU64TREE TreeStates;
163 /** Semaphore protecting the edges tree. */
164 RTSEMRW hSemRwEdges;
165 /** The AVL tree for discovered edges when coverage reports are collected. */
166 AVLU64TREE TreeEdges;
167 /** Number of edges discovered so far. */
168 volatile uint64_t cEdges;
169 /** The discovered offset width. */
170 volatile uint32_t cbCovOff;
171} RTFUZZTGTRECINT;
172
173
174/** SanCov magic for 64bit offsets. */
175#define SANCOV_MAGIC_64 UINT64_C(0xc0bfffffffffff64)
176/** SanCov magic for 32bit offsets. */
177#define SANCOV_MAGIC_32 UINT64_C(0xc0bfffffffffff32)
178
179
180/*********************************************************************************************************************************
181* Internal Functions *
182*********************************************************************************************************************************/
183
184/**
185 * Initializes the given stdout/stderr buffer.
186 *
187 * @returns nothing.
188 * @param pBuf The buffer to initialize.
189 */
190static void rtFuzzTgtStdOutErrBufInit(PRTFUZZTGTSTDOUTERRBUF pBuf)
191{
192 pBuf->cbBuf = 0;
193 pBuf->cbBufMax = 0;
194 pBuf->pbBase = NULL;
195}
196
197
198/**
199 * Frees all allocated resources in the given stdout/stderr buffer.
200 *
201 * @returns nothing.
202 * @param pBuf The buffer to free.
203 */
204static void rtFuzzTgtStdOutErrBufFree(PRTFUZZTGTSTDOUTERRBUF pBuf)
205{
206 if (pBuf->pbBase)
207 RTMemFree(pBuf->pbBase);
208}
209
210
211/**
212 * Fills the given stdout/stderr buffer from the given pipe.
213 *
214 * @returns IPRT status code.
215 * @param pBuf The buffer to fill.
216 * @param hPipeRead The pipe to read from.
217 */
218static int rtFuzzTgtStdOutErrBufFillFromPipe(PRTFUZZTGTSTDOUTERRBUF pBuf, RTPIPE hPipeRead)
219{
220 int rc = VINF_SUCCESS;
221
222 size_t cbRead = 0;
223 size_t cbThisRead = 0;
224 do
225 {
226 cbThisRead = pBuf->cbBufMax - pBuf->cbBuf;
227 if (!cbThisRead)
228 {
229 /* Try to increase the buffer. */
230 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pBuf->pbBase, pBuf->cbBufMax + _4K);
231 if (RT_LIKELY(pbNew))
232 {
233 pBuf->cbBufMax += _4K;
234 pBuf->pbBase = pbNew;
235 }
236 cbThisRead = pBuf->cbBufMax - pBuf->cbBuf;
237 }
238
239 if (cbThisRead)
240 {
241 rc = RTPipeRead(hPipeRead, pBuf->pbBase + pBuf->cbBuf, cbThisRead, &cbRead);
242 if (RT_SUCCESS(rc))
243 pBuf->cbBuf += cbRead;
244 }
245 else
246 rc = VERR_NO_MEMORY;
247 } while ( RT_SUCCESS(rc)
248 && cbRead == cbThisRead);
249
250 return rc;
251}
252
253
254/**
255 * Writes the given buffer to the given file.
256 *
257 * @returns IPRT status code.
258 * @param pBuf The buffer to write.
259 * @param pszFilename Where to write the buffer.
260 */
261static int rtFuzzTgtStateStdOutErrBufWriteToFile(PRTFUZZTGTSTDOUTERRBUF pBuf, const char *pszFilename)
262{
263 RTFILE hFile;
264 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
265 if (RT_SUCCESS(rc))
266 {
267 rc = RTFileWrite(hFile, pBuf->pbBase, pBuf->cbBuf, NULL);
268 AssertRC(rc);
269 RTFileClose(hFile);
270
271 if (RT_FAILURE(rc))
272 RTFileDelete(pszFilename);
273 }
274
275 return rc;
276}
277
278
279/**
280 * Scans the given target state for newly discovered edges in the coverage report.
281 *
282 * @returns IPRT status code.
283 * @param pThis The fuzzer target recorder instance.
284 * @param pTgtState The target state to check.
285 */
286static int rtFuzzTgtRecScanStateForNewEdges(PRTFUZZTGTRECINT pThis, PRTFUZZTGTSTATEINT pTgtState)
287{
288 int rc = VINF_SUCCESS;
289
290 if (pTgtState->pvCovReport)
291 {
292 rc = RTSemRWRequestRead(pThis->hSemRwEdges, RT_INDEFINITE_WAIT); AssertRC(rc);
293
294 uint32_t cbCovOff = ASMAtomicReadU32(&pThis->cbCovOff);
295 Assert(cbCovOff != 0);
296
297 uint8_t *pbCovCur = (uint8_t *)pTgtState->pvCovReport;
298 size_t cEdgesLeft = pTgtState->cbCovReport / cbCovOff;
299 while (cEdgesLeft)
300 {
301 uint64_t offCur = cbCovOff == sizeof(uint64_t)
302 ? *(uint64_t *)pbCovCur
303 : *(uint32_t *)pbCovCur;
304
305 PRTFUZZTGTEDGE pEdge = (PRTFUZZTGTEDGE)RTAvlU64Get(&pThis->TreeEdges, offCur);
306 if (!pEdge)
307 {
308 /* New edge discovered, allocate and add. */
309 rc = RTSemRWReleaseRead(pThis->hSemRwEdges); AssertRC(rc);
310
311 pEdge = (PRTFUZZTGTEDGE)RTMemAllocZ(sizeof(RTFUZZTGTEDGE));
312 if (RT_LIKELY(pEdge))
313 {
314 pEdge->Core.Key = offCur;
315 pEdge->cHits = 1;
316 rc = RTSemRWRequestWrite(pThis->hSemRwEdges, RT_INDEFINITE_WAIT); AssertRC(rc);
317
318 bool fIns = RTAvlU64Insert(&pThis->TreeEdges, &pEdge->Core);
319 if (!fIns)
320 {
321 /* Someone raced us, free and query again. */
322 RTMemFree(pEdge);
323 pEdge = (PRTFUZZTGTEDGE)RTAvlU64Get(&pThis->TreeEdges, offCur);
324 AssertPtr(pEdge);
325
326 ASMAtomicIncU64(&pEdge->cHits);
327 }
328 else
329 ASMAtomicIncU64(&pThis->cEdges);
330
331 rc = RTSemRWReleaseWrite(pThis->hSemRwEdges); AssertRC(rc);
332 rc = RTSemRWRequestRead(pThis->hSemRwEdges, RT_INDEFINITE_WAIT); AssertRC(rc);
333 }
334 else
335 {
336 rc = RTSemRWRequestRead(pThis->hSemRwEdges, RT_INDEFINITE_WAIT);
337 AssertRC(rc);
338
339 rc = VERR_NO_MEMORY;
340 break;
341 }
342 }
343 else
344 ASMAtomicIncU64(&pEdge->cHits);
345
346 pbCovCur += cbCovOff;
347 cEdgesLeft--;
348 }
349
350 rc = RTSemRWReleaseRead(pThis->hSemRwEdges); AssertRC(rc);
351 }
352
353 return rc;
354}
355
356
357/**
358 * Destorys the given fuzzer target recorder freeing all allocated resources.
359 *
360 * @returns nothing.
361 * @param pThis The fuzzer target recorder instance.
362 */
363static void rtFuzzTgtRecDestroy(PRTFUZZTGTRECINT pThis)
364{
365 RT_NOREF(pThis);
366}
367
368
369/**
370 * Destroys the given fuzzer target state freeing all allocated resources.
371 *
372 * @returns nothing.
373 * @param pThis The fuzzed target state instance.
374 */
375static void rtFuzzTgtStateDestroy(PRTFUZZTGTSTATEINT pThis)
376{
377 pThis->u32Magic = ~(uint32_t)0; /** @todo Dead magic */
378 rtFuzzTgtStdOutErrBufFree(&pThis->StdOutBuf);
379 rtFuzzTgtStdOutErrBufFree(&pThis->StdErrBuf);
380 RTMemFree(pThis);
381}
382
383
384/**
385 * Compares two given target states, checking whether they match.
386 *
387 * @returns Flag whether the states are identical.
388 * @param pThis Target state 1.
389 * @param pThat Target state 2.
390 */
391static bool rtFuzzTgtStateDoMatch(PRTFUZZTGTSTATEINT pThis, PRTFUZZTGTSTATEINT pThat)
392{
393 PRTFUZZTGTRECINT pTgtRec = pThis->pTgtRec;
394 Assert(pTgtRec == pThat->pTgtRec);
395
396 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_STDOUT)
397 && ( pThis->StdOutBuf.cbBuf != pThat->StdOutBuf.cbBuf
398 || ( pThis->StdOutBuf.cbBuf > 0
399 && memcmp(pThis->StdOutBuf.pbBase, pThat->StdOutBuf.pbBase, pThis->StdOutBuf.cbBuf))))
400 return false;
401
402 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_STDERR)
403 && ( pThis->StdErrBuf.cbBuf != pThat->StdErrBuf.cbBuf
404 || ( pThis->StdErrBuf.cbBuf > 0
405 && memcmp(pThis->StdErrBuf.pbBase, pThat->StdErrBuf.pbBase, pThis->StdErrBuf.cbBuf))))
406 return false;
407
408 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_PROCSTATUS)
409 && memcmp(&pThis->ProcSts, &pThat->ProcSts, sizeof(RTPROCSTATUS)))
410 return false;
411
412 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_SANCOV)
413 && ( pThis->cbCovReport != pThat->cbCovReport
414 || ( pThis->cbCovReport > 0
415 && memcmp(pThis->pvCovReport, pThat->pvCovReport, pThis->cbCovReport))))
416 return false;
417
418 return true;
419}
420
421
422RTDECL(int) RTFuzzTgtRecorderCreate(PRTFUZZTGTREC phFuzzTgtRec, uint32_t fRecFlags)
423{
424 AssertPtrReturn(phFuzzTgtRec, VERR_INVALID_POINTER);
425 AssertReturn(!(fRecFlags & ~RTFUZZTGT_REC_STATE_F_VALID), VERR_INVALID_PARAMETER);
426
427 int rc;
428 PRTFUZZTGTRECINT pThis = (PRTFUZZTGTRECINT)RTMemAllocZ(sizeof(*pThis));
429 if (RT_LIKELY(pThis))
430 {
431 pThis->u32Magic = 0; /** @todo */
432 pThis->cRefs = 1;
433 pThis->TreeStates = NULL;
434 pThis->TreeEdges = NULL;
435 pThis->cbCovOff = 0;
436 pThis->fRecFlags = fRecFlags;
437
438 rc = RTSemRWCreate(&pThis->hSemRwStates);
439 if (RT_SUCCESS(rc))
440 {
441 rc = RTSemRWCreate(&pThis->hSemRwEdges);
442 if (RT_SUCCESS(rc))
443 {
444 *phFuzzTgtRec = pThis;
445 return VINF_SUCCESS;
446 }
447
448 RTSemRWDestroy(pThis->hSemRwStates);
449 }
450
451 RTMemFree(pThis);
452 }
453 else
454 rc = VERR_NO_MEMORY;
455
456 return rc;
457}
458
459
460RTDECL(uint32_t) RTFuzzTgtRecorderRetain(RTFUZZTGTREC hFuzzTgtRec)
461{
462 PRTFUZZTGTRECINT pThis = hFuzzTgtRec;
463
464 AssertPtrReturn(pThis, UINT32_MAX);
465
466 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
467 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
468 return cRefs;
469}
470
471
472RTDECL(uint32_t) RTFuzzTgtRecorderRelease(RTFUZZTGTREC hFuzzTgtRec)
473{
474 PRTFUZZTGTRECINT pThis = hFuzzTgtRec;
475 if (pThis == NIL_RTFUZZTGTREC)
476 return 0;
477 AssertPtrReturn(pThis, UINT32_MAX);
478
479 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
480 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
481 if (cRefs == 0)
482 rtFuzzTgtRecDestroy(pThis);
483 return cRefs;
484}
485
486
487RTDECL(int) RTFuzzTgtRecorderCreateNewState(RTFUZZTGTREC hFuzzTgtRec, PRTFUZZTGTSTATE phFuzzTgtState)
488{
489 PRTFUZZTGTRECINT pThis = hFuzzTgtRec;
490 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
491 AssertPtrReturn(phFuzzTgtState, VERR_INVALID_POINTER);
492
493 int rc = VINF_SUCCESS;
494 PRTFUZZTGTSTATEINT pState = (PRTFUZZTGTSTATEINT)RTMemAllocZ(sizeof(*pState));
495 if (RT_LIKELY(pState))
496 {
497 pState->u32Magic = 0; /** @todo */
498 pState->cRefs = 1;
499 pState->pTgtRec = pThis;
500 pState->fFinalized = false;
501 rtFuzzTgtStdOutErrBufInit(&pState->StdOutBuf);
502 rtFuzzTgtStdOutErrBufInit(&pState->StdErrBuf);
503 *phFuzzTgtState = pState;
504 }
505 else
506 rc = VERR_NO_MEMORY;
507
508 return rc;
509}
510
511
512RTDECL(uint32_t) RTFuzzTgtStateRetain(RTFUZZTGTSTATE hFuzzTgtState)
513{
514 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
515
516 AssertPtrReturn(pThis, UINT32_MAX);
517
518 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
519 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
520 return cRefs;
521}
522
523
524RTDECL(uint32_t) RTFuzzTgtStateRelease(RTFUZZTGTSTATE hFuzzTgtState)
525{
526 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
527 if (pThis == NIL_RTFUZZTGTSTATE)
528 return 0;
529 AssertPtrReturn(pThis, UINT32_MAX);
530
531 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
532 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
533 if (cRefs == 0 && !pThis->fInRecSet)
534 rtFuzzTgtStateDestroy(pThis);
535 return cRefs;
536}
537
538
539RTDECL(int) RTFuzzTgtStateReset(RTFUZZTGTSTATE hFuzzTgtState)
540{
541 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
542 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
543
544 /* Clear the buffers. */
545 pThis->StdOutBuf.cbBuf = 0;
546 pThis->StdErrBuf.cbBuf = 0;
547 RT_ZERO(pThis->ProcSts);
548 if (pThis->pvCovReport)
549 RTMemFree(pThis->pvCovReport);
550 pThis->pvCovReport = NULL;
551 pThis->fFinalized = false;
552 return VINF_SUCCESS;
553}
554
555
556RTDECL(int) RTFuzzTgtStateFinalize(RTFUZZTGTSTATE hFuzzTgtState)
557{
558 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
559 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
560
561 /* Create the checksum. */
562 PRTFUZZTGTRECINT pTgtRec = pThis->pTgtRec;
563 uint64_t uChkSum = RTCrc64Start();
564 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_STDOUT)
565 && pThis->StdOutBuf.cbBuf)
566 uChkSum = RTCrc64Process(uChkSum, pThis->StdOutBuf.pbBase, pThis->StdOutBuf.cbBuf);
567 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_STDERR)
568 && pThis->StdErrBuf.cbBuf)
569 uChkSum = RTCrc64Process(uChkSum, pThis->StdErrBuf.pbBase, pThis->StdErrBuf.cbBuf);
570 if (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_PROCSTATUS)
571 uChkSum = RTCrc64Process(uChkSum, &pThis->ProcSts, sizeof(RTPROCSTATUS));
572 if ( (pTgtRec->fRecFlags & RTFUZZTGT_REC_STATE_F_SANCOV)
573 && pThis->pvCovReport)
574 uChkSum = RTCrc64Process(uChkSum, pThis->pvCovReport, pThis->cbCovReport);
575
576 pThis->uChkSum = RTCrc64Finish(uChkSum);
577 pThis->fFinalized = true;
578 return VINF_SUCCESS;
579}
580
581
582RTDECL(int) RTFuzzTgtStateAddToRecorder(RTFUZZTGTSTATE hFuzzTgtState)
583{
584 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
585 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
586
587 if (!pThis->fFinalized)
588 {
589 int rc = RTFuzzTgtStateFinalize(pThis);
590 if (RT_FAILURE(rc))
591 return rc;
592 }
593
594 PRTFUZZTGTRECINT pTgtRec = pThis->pTgtRec;
595
596 /* Try to find a node matching the stdout and sterr sizes first. */
597 int rc = RTSemRWRequestRead(pTgtRec->hSemRwStates, RT_INDEFINITE_WAIT); AssertRC(rc);
598 PRTFUZZTGTRECNODE pNode = (PRTFUZZTGTRECNODE)RTAvlU64Get(&pTgtRec->TreeStates, pThis->uChkSum);
599 if (pNode)
600 {
601 /* Traverse the states and check if any matches the stdout and stderr buffers exactly. */
602 PRTFUZZTGTSTATEINT pIt;
603 bool fMatchFound = false;
604 RTListForEach(&pNode->LstStates, pIt, RTFUZZTGTSTATEINT, NdStates)
605 {
606 if (rtFuzzTgtStateDoMatch(pThis, pIt))
607 {
608 fMatchFound = true;
609 break;
610 }
611 }
612
613 rc = RTSemRWReleaseRead(pTgtRec->hSemRwStates); AssertRC(rc);
614 if (!fMatchFound)
615 {
616 rc = RTSemRWRequestWrite(pTgtRec->hSemRwStates, RT_INDEFINITE_WAIT); AssertRC(rc);
617 RTListAppend(&pNode->LstStates, &pThis->NdStates);
618 rc = RTSemRWReleaseWrite(pTgtRec->hSemRwStates); AssertRC(rc);
619 pThis->fInRecSet = true;
620 }
621 else
622 rc = VERR_ALREADY_EXISTS;
623 }
624 else
625 {
626 rc = RTSemRWReleaseRead(pTgtRec->hSemRwStates); AssertRC(rc);
627
628 /* No node found, create new one and insert in to the tree right away. */
629 pNode = (PRTFUZZTGTRECNODE)RTMemAllocZ(sizeof(*pNode));
630 if (RT_LIKELY(pNode))
631 {
632 pNode->Core.Key = pThis->uChkSum;
633 RTListInit(&pNode->LstStates);
634 RTListAppend(&pNode->LstStates, &pThis->NdStates);
635 rc = RTSemRWRequestWrite(pTgtRec->hSemRwStates, RT_INDEFINITE_WAIT); AssertRC(rc);
636 bool fIns = RTAvlU64Insert(&pTgtRec->TreeStates, &pNode->Core);
637 if (!fIns)
638 {
639 /* Someone raced us, get the new node and append there. */
640 RTMemFree(pNode);
641 pNode = (PRTFUZZTGTRECNODE)RTAvlU64Get(&pTgtRec->TreeStates, pThis->uChkSum);
642 AssertPtr(pNode);
643 RTListAppend(&pNode->LstStates, &pThis->NdStates);
644 }
645 rc = RTSemRWReleaseWrite(pTgtRec->hSemRwStates); AssertRC(rc);
646 pThis->fInRecSet = true;
647 }
648 else
649 rc = VERR_NO_MEMORY;
650 }
651
652 if ( RT_SUCCESS(rc)
653 && pThis->fInRecSet)
654 rc = rtFuzzTgtRecScanStateForNewEdges(pTgtRec, pThis);
655
656 return rc;
657}
658
659
660RTDECL(int) RTFuzzTgtStateAppendStdoutFromBuf(RTFUZZTGTSTATE hFuzzTgtState, const void *pvStdOut, size_t cbStdOut)
661{
662 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
663 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
664 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
665
666 RT_NOREF(pvStdOut, cbStdOut);
667 return VERR_NOT_IMPLEMENTED;
668}
669
670
671RTDECL(int) RTFuzzTgtStateAppendStderrFromBuf(RTFUZZTGTSTATE hFuzzTgtState, const void *pvStdErr, size_t cbStdErr)
672{
673 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
674 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
675 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
676
677 RT_NOREF(pvStdErr, cbStdErr);
678 return VERR_NOT_IMPLEMENTED;
679}
680
681
682RTDECL(int) RTFuzzTgtStateAppendStdoutFromPipe(RTFUZZTGTSTATE hFuzzTgtState, RTPIPE hPipe)
683{
684 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
685 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
686 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
687
688 return rtFuzzTgtStdOutErrBufFillFromPipe(&pThis->StdOutBuf, hPipe);
689}
690
691
692RTDECL(int) RTFuzzTgtStateAppendStderrFromPipe(RTFUZZTGTSTATE hFuzzTgtState, RTPIPE hPipe)
693{
694 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
695 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
696 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
697
698 return rtFuzzTgtStdOutErrBufFillFromPipe(&pThis->StdErrBuf, hPipe);
699}
700
701
702RTDECL(int) RTFuzzTgtStateAddSanCovReportFromFile(RTFUZZTGTSTATE hFuzzTgtState, const char *pszFilename)
703{
704 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
705 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
706 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
707 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
708
709 uint8_t *pbSanCov = NULL;
710 size_t cbSanCov = 0;
711 int rc = RTFileReadAll(pszFilename, (void **)&pbSanCov, &cbSanCov);
712 if (RT_SUCCESS(rc))
713 {
714 /* Check for the magic identifying whether the offsets are 32bit or 64bit. */
715 if ( cbSanCov >= sizeof(uint64_t)
716 && ( *(uint64_t *)pbSanCov == SANCOV_MAGIC_64
717 || *(uint64_t *)pbSanCov == SANCOV_MAGIC_32))
718 {
719 uint32_t cbCovOff = sizeof(uint32_t);
720 if (*(uint64_t *)pbSanCov == SANCOV_MAGIC_64)
721 cbCovOff = sizeof(uint64_t);
722
723 uint32_t cbCovDet = ASMAtomicReadU32(&pThis->pTgtRec->cbCovOff);
724 if (!cbCovDet)
725 {
726 /* Set the detected offset width. */
727 if (!ASMAtomicCmpXchgU32(&pThis->pTgtRec->cbCovOff, cbCovOff, 0))
728 {
729 /* Someone raced us, check again. */
730 cbCovDet = ASMAtomicReadU32(&pThis->pTgtRec->cbCovOff);
731 Assert(cbCovDet != 0);
732 }
733 else
734 cbCovDet = cbCovOff;
735 }
736
737 if (cbCovDet == cbCovOff)
738 {
739 /*
740 * Just copy the offsets into the state for now. Now further analysis
741 * is happening right now, just checking whether the content changed for
742 * the states.to spot newly discovered edges.
743 */
744 pThis->cbCovReport = cbSanCov - sizeof(uint64_t);
745 pThis->pvCovReport = RTMemDup(pbSanCov + sizeof(uint64_t), pThis->cbCovReport);
746 if (!pThis->pvCovReport)
747 {
748 pThis->cbCovReport = 0;
749 rc = VERR_NO_MEMORY;
750 }
751 }
752 else
753 rc = VERR_INVALID_STATE; /* Mixing 32bit and 64bit offsets shouldn't happen, is not supported. */
754 }
755 else
756 rc = VERR_INVALID_STATE;
757 RTFileReadAllFree(pbSanCov, cbSanCov);
758 }
759 return rc;
760}
761
762
763RTDECL(int) RTFuzzTgtStateAddProcSts(RTFUZZTGTSTATE hFuzzTgtState, PCRTPROCSTATUS pProcSts)
764{
765 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
766 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
767 AssertPtrReturn(pProcSts, VERR_INVALID_POINTER);
768 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
769
770 pThis->ProcSts = *pProcSts;
771 return VINF_SUCCESS;
772}
773
774
775RTDECL(int) RTFuzzTgtStateDumpToDir(RTFUZZTGTSTATE hFuzzTgtState, const char *pszDirPath)
776{
777 PRTFUZZTGTSTATEINT pThis = hFuzzTgtState;
778 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
779 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
780 AssertReturn(!pThis->fFinalized, VERR_WRONG_ORDER);
781
782 int rc = VINF_SUCCESS;
783 char szPath[RTPATH_MAX];
784 if (pThis->StdOutBuf.cbBuf)
785 {
786 rc = RTPathJoin(szPath, sizeof(szPath), pszDirPath, "stdout"); AssertRC(rc);
787 if (RT_SUCCESS(rc))
788 rc = rtFuzzTgtStateStdOutErrBufWriteToFile(&pThis->StdOutBuf, &szPath[0]);
789 }
790
791 if ( RT_SUCCESS(rc)
792 && pThis->StdErrBuf.cbBuf)
793 {
794 rc = RTPathJoin(szPath, sizeof(szPath), pszDirPath, "stderr"); AssertRC(rc);
795 if (RT_SUCCESS(rc))
796 rc = rtFuzzTgtStateStdOutErrBufWriteToFile(&pThis->StdErrBuf, &szPath[0]);
797 }
798
799 return rc;
800}
801
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use