git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / zstd-1.5.6 / tests / fuzz / decompress_cross_format.c
CommitLineData
f535537f 1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
9 */
10
11// This fuzz target validates decompression of magicless-format compressed data.
12
13#include <stddef.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include "fuzz_helpers.h"
18#define ZSTD_STATIC_LINKING_ONLY
19#include "zstd.h"
20#include "fuzz_data_producer.h"
21
22static ZSTD_DCtx *dctx = NULL;
23
24int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
25{
26 // Give a random portion of src data to the producer, to use for parameter generation.
27 // The rest will be interpreted as magicless compressed data.
28 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
29 size_t magiclessSize = FUZZ_dataProducer_reserveDataPrefix(producer);
30 const uint8_t* const magiclessSrc = src;
31 size_t const dstSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
32 uint8_t* const standardDst = (uint8_t*)FUZZ_malloc(dstSize);
33 uint8_t* const magiclessDst = (uint8_t*)FUZZ_malloc(dstSize);
34
35 // Create standard-format src from magicless-format src
36 const uint32_t zstd_magic = ZSTD_MAGICNUMBER;
37 size_t standardSize = sizeof(zstd_magic) + magiclessSize;
38 uint8_t* const standardSrc = (uint8_t*)FUZZ_malloc(standardSize);
39 memcpy(standardSrc, &zstd_magic, sizeof(zstd_magic)); // assume fuzzing on little-endian machine
40 memcpy(standardSrc + sizeof(zstd_magic), magiclessSrc, magiclessSize);
41
42 // Truncate to a single frame
43 {
44 const size_t standardFrameCompressedSize = ZSTD_findFrameCompressedSize(standardSrc, standardSize);
45 if (ZSTD_isError(standardFrameCompressedSize)) {
46 goto cleanup_and_return;
47 }
48 standardSize = standardFrameCompressedSize;
49 magiclessSize = standardFrameCompressedSize - sizeof(zstd_magic);
50 }
51
52 // Create DCtx if needed
53 if (!dctx) {
54 dctx = ZSTD_createDCtx();
55 FUZZ_ASSERT(dctx);
56 }
57
58 // Test one-shot decompression
59 {
60 FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
61 FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1));
62 const size_t standardRet = ZSTD_decompressDCtx(
63 dctx, standardDst, dstSize, standardSrc, standardSize);
64
65 FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
66 FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless));
67 const size_t magiclessRet = ZSTD_decompressDCtx(
68 dctx, magiclessDst, dstSize, magiclessSrc, magiclessSize);
69
70 // Standard accepts => magicless should accept
71 if (!ZSTD_isError(standardRet)) FUZZ_ZASSERT(magiclessRet);
72
73 // Magicless accepts => standard should accept
74 // NOTE: this is nice-to-have, please disable this check if it is difficult to satisfy.
75 if (!ZSTD_isError(magiclessRet)) FUZZ_ZASSERT(standardRet);
76
77 // If both accept, decompressed size and data should match
78 if (!ZSTD_isError(standardRet) && !ZSTD_isError(magiclessRet)) {
79 FUZZ_ASSERT(standardRet == magiclessRet);
80 if (standardRet > 0) {
81 FUZZ_ASSERT(
82 memcmp(standardDst, magiclessDst, standardRet) == 0
83 );
84 }
85 }
86 }
87
88 // Test streaming decompression
89 {
90 ZSTD_inBuffer standardIn = { standardSrc, standardSize, 0 };
91 ZSTD_inBuffer magiclessIn = { magiclessSrc, magiclessSize, 0 };
92 ZSTD_outBuffer standardOut = { standardDst, dstSize, 0 };
93 ZSTD_outBuffer magiclessOut = { magiclessDst, dstSize, 0 };
94
95 FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
96 FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1));
97 const size_t standardRet = ZSTD_decompressStream(dctx, &standardOut, &standardIn);
98
99 FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
100 FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless));
101 const size_t magiclessRet = ZSTD_decompressStream(dctx, &magiclessOut, &magiclessIn);
102
103 // Standard accepts => magicless should accept
104 if (standardRet == 0) FUZZ_ASSERT(magiclessRet == 0);
105
106 // Magicless accepts => standard should accept
107 // NOTE: this is nice-to-have, please disable this check if it is difficult to satisfy.
108 if (magiclessRet == 0) FUZZ_ASSERT(standardRet == 0);
109
110 // If both accept, decompressed size and data should match
111 if (standardRet == 0 && magiclessRet == 0) {
112 FUZZ_ASSERT(standardOut.pos == magiclessOut.pos);
113 if (standardOut.pos > 0) {
114 FUZZ_ASSERT(
115 memcmp(standardOut.dst, magiclessOut.dst, standardOut.pos) == 0
116 );
117 }
118 }
119 }
120
121cleanup_and_return:
122#ifndef STATEFUL_FUZZING
123 ZSTD_freeDCtx(dctx); dctx = NULL;
124#endif
125 free(standardSrc);
126 free(standardDst);
127 free(magiclessDst);
128 FUZZ_dataProducer_free(producer);
129 return 0;
130}