xref: /netbsd-src/external/bsd/zstd/dist/tests/fuzz/stream_decompress.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos 
11*3117ece4Schristos /**
12*3117ece4Schristos  * This fuzz target attempts to decompress the fuzzed data with the simple
13*3117ece4Schristos  * decompression function to ensure the decompressor never crashes.
14*3117ece4Schristos  */
15*3117ece4Schristos 
16*3117ece4Schristos #define ZSTD_STATIC_LINKING_ONLY
17*3117ece4Schristos 
18*3117ece4Schristos #include <stddef.h>
19*3117ece4Schristos #include <stdlib.h>
20*3117ece4Schristos #include <stdio.h>
21*3117ece4Schristos #include "fuzz_helpers.h"
22*3117ece4Schristos #include "zstd.h"
23*3117ece4Schristos #include "fuzz_data_producer.h"
24*3117ece4Schristos 
25*3117ece4Schristos static ZSTD_DStream *dstream = NULL;
26*3117ece4Schristos uint32_t seed;
27*3117ece4Schristos 
28*3117ece4Schristos static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer, void* buf, size_t bufSize)
29*3117ece4Schristos {
30*3117ece4Schristos   ZSTD_outBuffer buffer = { buf, 0, 0 };
31*3117ece4Schristos 
32*3117ece4Schristos   if (FUZZ_dataProducer_empty(producer)) {
33*3117ece4Schristos     buffer.size = bufSize;
34*3117ece4Schristos   } else {
35*3117ece4Schristos     buffer.size = (FUZZ_dataProducer_uint32Range(producer, 0, bufSize));
36*3117ece4Schristos   }
37*3117ece4Schristos   FUZZ_ASSERT(buffer.size <= bufSize);
38*3117ece4Schristos 
39*3117ece4Schristos   if (buffer.size == 0) {
40*3117ece4Schristos     buffer.dst = NULL;
41*3117ece4Schristos   }
42*3117ece4Schristos 
43*3117ece4Schristos   return buffer;
44*3117ece4Schristos }
45*3117ece4Schristos 
46*3117ece4Schristos static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
47*3117ece4Schristos                                   FUZZ_dataProducer_t *producer)
48*3117ece4Schristos {
49*3117ece4Schristos   ZSTD_inBuffer buffer = { *src, 0, 0 };
50*3117ece4Schristos 
51*3117ece4Schristos   FUZZ_ASSERT(*size > 0);
52*3117ece4Schristos   if (FUZZ_dataProducer_empty(producer)) {
53*3117ece4Schristos     buffer.size = *size;
54*3117ece4Schristos   } else {
55*3117ece4Schristos     buffer.size = (FUZZ_dataProducer_uint32Range(producer, 0, *size));
56*3117ece4Schristos   }
57*3117ece4Schristos   FUZZ_ASSERT(buffer.size <= *size);
58*3117ece4Schristos   *src += buffer.size;
59*3117ece4Schristos   *size -= buffer.size;
60*3117ece4Schristos 
61*3117ece4Schristos   if (buffer.size == 0) {
62*3117ece4Schristos     buffer.src = NULL;
63*3117ece4Schristos   }
64*3117ece4Schristos 
65*3117ece4Schristos   return buffer;
66*3117ece4Schristos }
67*3117ece4Schristos 
68*3117ece4Schristos int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
69*3117ece4Schristos {
70*3117ece4Schristos     /* Give a random portion of src data to the producer, to use for
71*3117ece4Schristos     parameter generation. The rest will be used for (de)compression */
72*3117ece4Schristos     FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
73*3117ece4Schristos     int stableOutBuffer;
74*3117ece4Schristos     ZSTD_outBuffer out;
75*3117ece4Schristos     void* buf;
76*3117ece4Schristos     size_t bufSize;
77*3117ece4Schristos     size = FUZZ_dataProducer_reserveDataPrefix(producer);
78*3117ece4Schristos     bufSize = MAX(10 * size, ZSTD_BLOCKSIZE_MAX);
79*3117ece4Schristos 
80*3117ece4Schristos     /* Allocate all buffers and contexts if not already allocated */
81*3117ece4Schristos     buf = FUZZ_malloc(bufSize);
82*3117ece4Schristos 
83*3117ece4Schristos     if (!dstream) {
84*3117ece4Schristos         dstream = ZSTD_createDStream();
85*3117ece4Schristos         FUZZ_ASSERT(dstream);
86*3117ece4Schristos     } else {
87*3117ece4Schristos         FUZZ_ZASSERT(ZSTD_DCtx_reset(dstream, ZSTD_reset_session_only));
88*3117ece4Schristos     }
89*3117ece4Schristos 
90*3117ece4Schristos     stableOutBuffer = FUZZ_dataProducer_uint32Range(producer, 0, 10) == 5;
91*3117ece4Schristos     if (stableOutBuffer) {
92*3117ece4Schristos       FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dstream, ZSTD_d_stableOutBuffer, 1));
93*3117ece4Schristos       out.dst = buf;
94*3117ece4Schristos       out.size = bufSize;
95*3117ece4Schristos       out.pos = 0;
96*3117ece4Schristos     } else {
97*3117ece4Schristos       out = makeOutBuffer(producer, buf, bufSize);
98*3117ece4Schristos     }
99*3117ece4Schristos 
100*3117ece4Schristos     while (size > 0) {
101*3117ece4Schristos         ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
102*3117ece4Schristos         do {
103*3117ece4Schristos             size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
104*3117ece4Schristos             if (ZSTD_isError(rc)) goto error;
105*3117ece4Schristos             if (out.pos == out.size) {
106*3117ece4Schristos                 if (stableOutBuffer) goto error;
107*3117ece4Schristos                 out = makeOutBuffer(producer, buf, bufSize);
108*3117ece4Schristos             }
109*3117ece4Schristos         } while (in.pos != in.size);
110*3117ece4Schristos     }
111*3117ece4Schristos 
112*3117ece4Schristos error:
113*3117ece4Schristos #ifndef STATEFUL_FUZZING
114*3117ece4Schristos     ZSTD_freeDStream(dstream); dstream = NULL;
115*3117ece4Schristos #endif
116*3117ece4Schristos     FUZZ_dataProducer_free(producer);
117*3117ece4Schristos     free(buf);
118*3117ece4Schristos     return 0;
119*3117ece4Schristos }
120