Coverage Report

Created: 2025-08-26 06:15

/src/zstd/tests/fuzz/sequence_compression_api.c
Line
Count
Source (jump to first uncovered line)
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
/**
12
 * This fuzz target performs a zstd round-trip test by generating an arbitrary
13
 * array of sequences, generating the associated source buffer, calling
14
 * ZSTD_compressSequences(), and then decompresses and compares the result with
15
 * the original generated source buffer.
16
 */
17
18
#define ZSTD_STATIC_LINKING_ONLY
19
#include "zstd_errors.h"
20
21
#include <stddef.h>
22
#include <stdlib.h>
23
#include <stdio.h>
24
#include <string.h>
25
#include <time.h>
26
#include "fuzz_helpers.h"
27
#include "zstd_helpers.h"
28
#include "fuzz_data_producer.h"
29
#include "fuzz_third_party_seq_prod.h"
30
31
static ZSTD_CCtx* cctx = NULL;
32
static ZSTD_DCtx* dctx = NULL;
33
static void* literalsBuffer = NULL;
34
static void* generatedSrc = NULL;
35
static ZSTD_Sequence* generatedSequences = NULL;
36
37
static void* dictBuffer = NULL;
38
static ZSTD_CDict* cdict = NULL;
39
static ZSTD_DDict* ddict = NULL;
40
41
18.8M
#define ZSTD_FUZZ_GENERATED_SRC_MAXSIZE (1 << 20) /* Allow up to 1MB generated data */
42
26.1k
#define ZSTD_FUZZ_GENERATED_LITERALS_SIZE (1 << 20) /* Fixed size 1MB literals buffer */
43
6.53k
#define ZSTD_FUZZ_MATCHLENGTH_MAXSIZE (1 << 18) /* Allow up to 256KB matches */
44
2.67k
#define ZSTD_FUZZ_GENERATED_DICT_MAXSIZE (1 << ZSTD_WINDOWLOG_MAX_32) /* Allow up to 1 << ZSTD_WINDOWLOG_MAX_32 dictionary */
45
4.72M
#define ZSTD_FUZZ_MAX_NBSEQ (1 << 17) /* Maximum of 128K sequences */
46
47
/* Deterministic random number generator */
48
6.84G
#define FUZZ_RDG_rotl32(x,r) ((x << r) | (x >> (32 - r)))
49
static uint32_t FUZZ_RDG_rand(uint32_t* src)
50
6.84G
{
51
6.84G
    static const uint32_t prime1 = 2654435761U;
52
6.84G
    static const uint32_t prime2 = 2246822519U;
53
6.84G
    uint32_t rand32 = *src;
54
6.84G
    rand32 *= prime1;
55
6.84G
    rand32 ^= prime2;
56
6.84G
    rand32  = FUZZ_RDG_rotl32(rand32, 13);
57
6.84G
    *src = rand32;
58
6.84G
    return rand32 >> 5;
59
6.84G
}
60
61
/* Make a pseudorandom string - this simple function exists to avoid
62
 * taking a dependency on datagen.h to have RDG_genBuffer().
63
 */
64
6.53k
static char* generatePseudoRandomString(char* str, size_t size, FUZZ_dataProducer_t* producer) {
65
6.53k
    const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK1234567890!@#$^&*()_";
66
6.53k
    uint32_t seed = FUZZ_dataProducer_uint32(producer);
67
6.53k
    if (size) {
68
6.84G
        for (size_t n = 0; n < size; n++) {
69
6.84G
            int key = FUZZ_RDG_rand(&seed) % (int) (sizeof charset - 1);
70
6.84G
            str[n] = charset[key];
71
6.84G
        }
72
6.53k
    }
73
6.53k
    return str;
74
6.53k
}
75
76
/* Returns size of source buffer */
77
static size_t decodeSequences(void* dst, size_t nbSequences,
78
                              size_t literalsSize,
79
                              const void* dict, size_t dictSize,
80
                              ZSTD_SequenceFormat_e mode)
81
6.53k
{
82
6.53k
    const uint8_t* litPtr = literalsBuffer;
83
6.53k
    const uint8_t* const litBegin = literalsBuffer;
84
6.53k
    const uint8_t* const litEnd = litBegin + literalsSize;
85
6.53k
    const uint8_t* dictPtr = dict;
86
6.53k
    uint8_t* op = dst;
87
6.53k
    const uint8_t* const oend = (uint8_t*)dst + ZSTD_FUZZ_GENERATED_SRC_MAXSIZE;
88
6.53k
    size_t generatedSrcBufferSize = 0;
89
6.53k
    size_t bytesWritten = 0;
90
91
6.38M
    for (size_t i = 0; i < nbSequences; ++i) {
92
        /* block boundary */
93
6.37M
        if (generatedSequences[i].offset == 0)
94
6.37M
            FUZZ_ASSERT(generatedSequences[i].matchLength == 0);
95
96
6.37M
        if (litPtr + generatedSequences[i].litLength > litEnd) {
97
0
            litPtr = litBegin;
98
0
        }
99
6.37M
        memcpy(op, litPtr, generatedSequences[i].litLength);
100
6.37M
        bytesWritten += generatedSequences[i].litLength;
101
6.37M
        op += generatedSequences[i].litLength;
102
6.37M
        litPtr += generatedSequences[i].litLength;
103
104
        /* Copy over the match */
105
6.37M
        {   size_t matchLength = generatedSequences[i].matchLength;
106
6.37M
            size_t j = 0;
107
6.37M
            size_t k = 0;
108
6.37M
            if (dictSize != 0) {
109
3.63M
                if (generatedSequences[i].offset > bytesWritten) { /* Offset goes into the dictionary */
110
22.5k
                    size_t dictOffset = generatedSequences[i].offset - bytesWritten;
111
22.5k
                    size_t matchInDict = MIN(matchLength, dictOffset);
112
90.4M
                    for (; k < matchInDict; ++k) {
113
90.4M
                        op[k] = dictPtr[dictSize - dictOffset + k];
114
90.4M
                    }
115
22.5k
                    matchLength -= matchInDict;
116
22.5k
                    op += matchInDict;
117
22.5k
                }
118
3.63M
            }
119
308M
            for (; j < matchLength; ++j) {
120
302M
                op[j] = op[(ptrdiff_t)(j - generatedSequences[i].offset)];
121
302M
            }
122
6.37M
            op += j;
123
6.37M
            FUZZ_ASSERT(generatedSequences[i].matchLength == j + k);
124
6.37M
            bytesWritten += generatedSequences[i].matchLength;
125
6.37M
        }
126
6.37M
    }
127
6.53k
    generatedSrcBufferSize = bytesWritten;
128
6.53k
    FUZZ_ASSERT(litPtr <= litEnd);
129
6.53k
    if (mode == ZSTD_sf_noBlockDelimiters) {
130
2.84k
        const uint32_t lastLLSize = (uint32_t)(litEnd - litPtr);
131
2.84k
        if (lastLLSize <= (uint32_t)(oend - op)) {
132
417
            memcpy(op, litPtr, lastLLSize);
133
417
            generatedSrcBufferSize += lastLLSize;
134
417
    }   }
135
6.53k
    return generatedSrcBufferSize;
136
6.53k
}
137
138
/* Returns nb sequences generated
139
 * Note : random sequences are always valid in ZSTD_sf_noBlockDelimiters mode.
140
 * However, it can fail with ZSTD_sf_explicitBlockDelimiters,
141
 * due to potential lack of space in
142
 */
143
static size_t generateRandomSequences(FUZZ_dataProducer_t* producer,
144
                                      size_t literalsSizeLimit, size_t dictSize,
145
                                      size_t windowLog, ZSTD_SequenceFormat_e mode)
146
6.53k
{
147
6.53k
    const uint32_t repCode = 0;  /* not used by sequence ingestion api */
148
6.53k
    size_t windowSize = 1ULL << windowLog;
149
6.53k
    size_t blockSizeMax = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
150
6.53k
    uint32_t matchLengthMax = ZSTD_FUZZ_MATCHLENGTH_MAXSIZE;
151
6.53k
    uint32_t bytesGenerated = 0;
152
6.53k
    uint32_t nbSeqGenerated = 0;
153
6.53k
    uint32_t isFirstSequence = 1;
154
6.53k
    uint32_t blockSize = 0;
155
156
6.53k
    if (mode == ZSTD_sf_explicitBlockDelimiters) {
157
        /* ensure that no sequence can be larger than one block */
158
3.68k
        literalsSizeLimit = MIN(literalsSizeLimit, blockSizeMax/2);
159
3.68k
        matchLengthMax = MIN(matchLengthMax, (uint32_t)blockSizeMax/2);
160
3.68k
    }
161
162
4.72M
    while ( nbSeqGenerated < ZSTD_FUZZ_MAX_NBSEQ - 3 /* extra room for explicit delimiters */
163
4.72M
         && bytesGenerated < ZSTD_FUZZ_GENERATED_SRC_MAXSIZE
164
4.72M
         && !FUZZ_dataProducer_empty(producer)) {
165
4.71M
        uint32_t matchLength;
166
4.71M
        uint32_t matchBound = matchLengthMax;
167
4.71M
        uint32_t offset;
168
4.71M
        uint32_t offsetBound;
169
4.71M
        const uint32_t minLitLength = (isFirstSequence && (dictSize == 0));
170
4.71M
        const uint32_t litLength = FUZZ_dataProducer_uint32Range(producer, minLitLength, (uint32_t)literalsSizeLimit);
171
4.71M
        bytesGenerated += litLength;
172
4.71M
        if (bytesGenerated > ZSTD_FUZZ_GENERATED_SRC_MAXSIZE) {
173
51
            break;
174
51
        }
175
4.71M
        offsetBound = (bytesGenerated > windowSize) ? (uint32_t)windowSize : bytesGenerated + (uint32_t)dictSize;
176
4.71M
        offset = FUZZ_dataProducer_uint32Range(producer, 1, offsetBound);
177
4.71M
        if (dictSize > 0 && bytesGenerated <= windowSize) {
178
            /* Prevent match length from being such that it would be associated with an offset too large
179
             * from the decoder's perspective. If not possible (match would be too small),
180
             * then reduce the offset if necessary.
181
             */
182
187k
            const size_t bytesToReachWindowSize = windowSize - bytesGenerated;
183
187k
            if (bytesToReachWindowSize < ZSTD_MINMATCH_MIN) {
184
23
                const uint32_t newOffsetBound = offsetBound > windowSize ? (uint32_t)windowSize : offsetBound;
185
23
                offset = FUZZ_dataProducer_uint32Range(producer, 1, newOffsetBound);
186
187k
            } else {
187
187k
                matchBound = MIN(matchLengthMax, (uint32_t)bytesToReachWindowSize);
188
187k
            }
189
187k
        }
190
4.71M
        matchLength = FUZZ_dataProducer_uint32Range(producer, ZSTD_MINMATCH_MIN, matchBound);
191
4.71M
        bytesGenerated += matchLength;
192
4.71M
        if (bytesGenerated > ZSTD_FUZZ_GENERATED_SRC_MAXSIZE) {
193
33
            break;
194
33
        }
195
4.71M
        {   ZSTD_Sequence seq = {offset, litLength, matchLength, repCode};
196
4.71M
            const uint32_t lastLits = FUZZ_dataProducer_uint32Range(producer, 0, litLength);
197
4.71M
            #define SPLITPROB 6000
198
4.71M
            #define SPLITMARK 5234
199
4.71M
            const int split = (FUZZ_dataProducer_uint32Range(producer, 0, SPLITPROB) == SPLITMARK);
200
4.71M
            if (mode == ZSTD_sf_explicitBlockDelimiters) {
201
4.17M
                const size_t seqSize = seq.litLength + seq.matchLength;
202
4.17M
                if (blockSize + seqSize > blockSizeMax) {  /* reaching limit : must end block now */
203
44.9k
                    const ZSTD_Sequence endBlock = {0, 0, 0, 0};
204
44.9k
                    generatedSequences[nbSeqGenerated++] = endBlock;
205
44.9k
                    blockSize = (uint32_t)seqSize;
206
44.9k
                }
207
4.17M
                if (split) {
208
1.61M
                    const ZSTD_Sequence endBlock = {0, lastLits, 0, 0};
209
1.61M
                    generatedSequences[nbSeqGenerated++] = endBlock;
210
1.61M
                    assert(lastLits <= seq.litLength);
211
1.61M
                    seq.litLength -= lastLits;
212
1.61M
                    blockSize = (uint32_t)(seqSize - lastLits);
213
2.55M
                } else {
214
2.55M
                    blockSize += seqSize;
215
2.55M
                }
216
4.17M
            }
217
4.71M
            generatedSequences[nbSeqGenerated++] = seq;
218
4.71M
            isFirstSequence = 0;
219
4.71M
        }
220
4.71M
    }
221
222
6.53k
    if (mode == ZSTD_sf_explicitBlockDelimiters) {
223
        /* always end sequences with a block delimiter */
224
3.68k
        const ZSTD_Sequence endBlock = {0, 0, 0, 0};
225
3.68k
        assert(nbSeqGenerated < ZSTD_FUZZ_MAX_NBSEQ);
226
3.68k
        generatedSequences[nbSeqGenerated++] = endBlock;
227
3.68k
    }
228
6.53k
    return nbSeqGenerated;
229
6.53k
}
230
231
static size_t
232
transferLiterals(void* dst, size_t dstCapacity, const ZSTD_Sequence* seqs, size_t nbSeqs, const void* src, size_t srcSize)
233
0
{
234
0
    size_t n;
235
0
    char* op = dst;
236
0
    char* const oend = op + dstCapacity;
237
0
    const char* ip = src;
238
0
    const char* const iend = ip + srcSize;
239
0
    for (n=0; n<nbSeqs; n++) {
240
0
        size_t litLen = seqs[n].litLength;
241
0
        size_t mlen = seqs[n].matchLength;
242
0
        assert(op + litLen < oend); (void)oend;
243
0
        assert(ip + litLen + mlen <= iend); (void)iend;
244
0
        memcpy(op, ip, litLen);
245
0
        op += litLen;
246
0
        ip += litLen + mlen;
247
0
    }
248
0
    assert(oend - op >= 8);
249
0
    return (size_t)(op - (char*)dst);
250
0
}
251
252
static size_t roundTripTest_compressSequencesAndLiterals(
253
                    void* result, size_t resultCapacity,
254
                    void* compressed, size_t compressedCapacity,
255
                    const void* src, size_t srcSize,
256
                    const ZSTD_Sequence* seqs, size_t nbSeqs)
257
0
{
258
0
    size_t const litCapacity = srcSize + 8;
259
0
    void* literals = malloc(litCapacity);
260
0
    size_t cSize, litSize;
261
262
0
    assert(literals);
263
0
    litSize = transferLiterals(literals, litCapacity, seqs, nbSeqs, src, srcSize);
264
265
0
    cSize = ZSTD_compressSequencesAndLiterals(cctx,
266
0
                                compressed, compressedCapacity,
267
0
                                   seqs, nbSeqs,
268
0
                                   literals, litSize, litCapacity, srcSize);
269
0
    free(literals);
270
0
    if (ZSTD_getErrorCode(cSize) == ZSTD_error_cannotProduce_uncompressedBlock) {
271
        /* Valid scenario : ZSTD_compressSequencesAndLiterals cannot generate uncompressed blocks */
272
0
        return 0;
273
0
    }
274
0
    if (ZSTD_getErrorCode(cSize) == ZSTD_error_dstSize_tooSmall) {
275
        /* Valid scenario : in explicit delimiter mode,
276
         * it might be possible for the compressed size to outgrow dstCapacity.
277
         * In which case, it's still a valid fuzzer scenario,
278
         * but no roundtrip shall be possible */
279
0
        return 0;
280
0
    }
281
282
    /* round-trip */
283
0
    FUZZ_ZASSERT(cSize);
284
0
    {   size_t const dSize = ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize);
285
0
        FUZZ_ZASSERT(dSize);
286
0
        FUZZ_ASSERT_MSG(dSize == srcSize, "Incorrect regenerated size");
287
0
        FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, result, srcSize), "Corruption!");
288
0
        return dSize;
289
0
    }
290
0
}
291
292
static size_t roundTripTest(void* result, size_t resultCapacity,
293
                            void* compressed, size_t compressedCapacity,
294
                            const void* src, size_t srcSize,
295
                            const ZSTD_Sequence* seqs, size_t nbSeqs,
296
                            unsigned hasDict,
297
                            ZSTD_SequenceFormat_e mode)
298
6.53k
{
299
6.53k
    size_t cSize;
300
6.53k
    size_t dSize;
301
302
6.53k
    if (hasDict) {
303
2.66k
        FUZZ_ZASSERT(ZSTD_CCtx_refCDict(cctx, cdict));
304
2.66k
        FUZZ_ZASSERT(ZSTD_DCtx_refDDict(dctx, ddict));
305
2.66k
    }
306
307
6.53k
    {   int blockMode, validation;
308
        /* compressSequencesAndLiterals() only supports explicitBlockDelimiters and no validation */
309
6.53k
        FUZZ_ZASSERT(ZSTD_CCtx_getParameter(cctx, ZSTD_c_blockDelimiters, &blockMode));
310
6.53k
        FUZZ_ZASSERT(ZSTD_CCtx_getParameter(cctx, ZSTD_c_validateSequences, &validation));
311
6.53k
        if ((blockMode == ZSTD_sf_explicitBlockDelimiters) && (!validation)) {
312
0
            FUZZ_ZASSERT(roundTripTest_compressSequencesAndLiterals(result, resultCapacity, compressed, compressedCapacity, src, srcSize, seqs, nbSeqs));
313
0
        }
314
6.53k
    }
315
316
6.53k
    cSize = ZSTD_compressSequences(cctx, compressed, compressedCapacity,
317
6.53k
                                   seqs, nbSeqs,
318
6.53k
                                   src, srcSize);
319
6.53k
    if ( (ZSTD_getErrorCode(cSize) == ZSTD_error_dstSize_tooSmall)
320
6.53k
      && (mode == ZSTD_sf_explicitBlockDelimiters) ) {
321
        /* Valid scenario : in explicit delimiter mode,
322
         * it might be possible for the compressed size to outgrow dstCapacity.
323
         * In which case, it's still a valid fuzzer scenario,
324
         * but no roundtrip shall be possible */
325
161
        return 0;
326
161
    }
327
    /* round-trip */
328
6.37k
    FUZZ_ZASSERT(cSize);
329
6.37k
    dSize = ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize);
330
6.37k
    FUZZ_ZASSERT(dSize);
331
6.37k
    FUZZ_ASSERT_MSG(dSize == srcSize, "Incorrect regenerated size");
332
6.37k
    FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, result, srcSize), "Corruption!");
333
6.37k
    return dSize;
334
6.37k
}
335
336
int LLVMFuzzerTestOneInput(const uint8_t* src, size_t size)
337
6.53k
{
338
6.53k
    FUZZ_SEQ_PROD_SETUP();
339
340
6.53k
    void* rBuf;
341
6.53k
    size_t rBufSize;
342
6.53k
    void* cBuf;
343
6.53k
    size_t cBufSize;
344
6.53k
    size_t generatedSrcSize;
345
6.53k
    size_t nbSequences;
346
6.53k
    size_t dictSize = 0;
347
6.53k
    unsigned hasDict;
348
6.53k
    unsigned wLog;
349
6.53k
    int cLevel;
350
6.53k
    ZSTD_SequenceFormat_e mode;
351
352
6.53k
    FUZZ_dataProducer_t* const producer = FUZZ_dataProducer_create(src, size);
353
6.53k
    FUZZ_ASSERT(producer);
354
355
6.53k
    if (!cctx) {
356
6.53k
        cctx = ZSTD_createCCtx();
357
6.53k
        FUZZ_ASSERT(cctx);
358
6.53k
    }
359
6.53k
    if (!dctx) {
360
6.53k
        dctx = ZSTD_createDCtx();
361
6.53k
        FUZZ_ASSERT(dctx);
362
6.53k
    }
363
364
    /* Generate window log first so we don't generate offsets too large */
365
6.53k
    wLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
366
6.53k
    cLevel = FUZZ_dataProducer_int32Range(producer, -3, 22);
367
6.53k
    mode = (ZSTD_SequenceFormat_e)FUZZ_dataProducer_int32Range(producer, 0, 1);
368
369
6.53k
    ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
370
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 0);
371
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel);
372
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, (int)wLog);
373
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, ZSTD_MINMATCH_MIN);
374
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1);
375
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, (int)mode);
376
6.53k
    ZSTD_CCtx_setParameter(cctx, ZSTD_c_forceAttachDict, ZSTD_dictForceAttach);
377
378
6.53k
    if (!literalsBuffer) {
379
6.53k
        literalsBuffer = FUZZ_malloc(ZSTD_FUZZ_GENERATED_LITERALS_SIZE);
380
6.53k
        FUZZ_ASSERT(literalsBuffer);
381
6.53k
        literalsBuffer = generatePseudoRandomString(literalsBuffer, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, producer);
382
6.53k
    }
383
384
6.53k
    if (!dictBuffer) { /* Generate global dictionary buffer */
385
1
        ZSTD_compressionParameters cParams;
386
387
        /* Generate a large dictionary buffer */
388
1
        dictBuffer = calloc(ZSTD_FUZZ_GENERATED_DICT_MAXSIZE, 1);
389
1
        FUZZ_ASSERT(dictBuffer);
390
391
        /* Create global cdict and ddict */
392
1
        cParams = ZSTD_getCParams(1, ZSTD_FUZZ_GENERATED_SRC_MAXSIZE, ZSTD_FUZZ_GENERATED_DICT_MAXSIZE);
393
1
        cParams.minMatch = ZSTD_MINMATCH_MIN;
394
1
        cParams.hashLog = ZSTD_HASHLOG_MIN;
395
1
        cParams.chainLog = ZSTD_CHAINLOG_MIN;
396
397
1
        cdict = ZSTD_createCDict_advanced(dictBuffer, ZSTD_FUZZ_GENERATED_DICT_MAXSIZE, ZSTD_dlm_byRef, ZSTD_dct_rawContent, cParams, ZSTD_defaultCMem);
398
1
        ddict = ZSTD_createDDict_advanced(dictBuffer, ZSTD_FUZZ_GENERATED_DICT_MAXSIZE, ZSTD_dlm_byRef, ZSTD_dct_rawContent, ZSTD_defaultCMem);
399
1
        FUZZ_ASSERT(cdict);
400
1
        FUZZ_ASSERT(ddict);
401
1
    }
402
403
6.53k
    FUZZ_ASSERT(cdict);
404
6.53k
    FUZZ_ASSERT(ddict);
405
406
6.53k
    hasDict = FUZZ_dataProducer_uint32Range(producer, 0, 1);
407
6.53k
    if (hasDict) {
408
2.66k
        dictSize = ZSTD_FUZZ_GENERATED_DICT_MAXSIZE;
409
2.66k
    }
410
411
6.53k
    if (!generatedSequences) {
412
6.53k
        generatedSequences = FUZZ_malloc(sizeof(ZSTD_Sequence)*ZSTD_FUZZ_MAX_NBSEQ);
413
6.53k
    }
414
6.53k
    if (!generatedSrc) {
415
6.53k
        generatedSrc = FUZZ_malloc(ZSTD_FUZZ_GENERATED_SRC_MAXSIZE);
416
6.53k
    }
417
418
6.53k
    nbSequences = generateRandomSequences(producer, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictSize, wLog, mode);
419
6.53k
    generatedSrcSize = decodeSequences(generatedSrc, nbSequences, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictBuffer, dictSize, mode);
420
421
    /* Note : in explicit block delimiters mode,
422
     * the fuzzer might generate a lot of small blocks.
423
     * In which case, the final compressed size might be > ZSTD_compressBound().
424
     * This is still a valid scenario fuzzer though, which makes it possible to check under-sized dstCapacity.
425
     * The test just doesn't roundtrip. */
426
6.53k
    cBufSize = ZSTD_compressBound(generatedSrcSize);
427
6.53k
    cBuf = FUZZ_malloc(cBufSize);
428
429
6.53k
    rBufSize = generatedSrcSize;
430
6.53k
    rBuf = FUZZ_malloc(rBufSize);
431
432
6.53k
    {   const size_t result = roundTripTest(rBuf, rBufSize,
433
6.53k
                                        cBuf, cBufSize,
434
6.53k
                                        generatedSrc, generatedSrcSize,
435
6.53k
                                        generatedSequences, nbSequences,
436
6.53k
                                        hasDict, mode);
437
6.53k
        FUZZ_ASSERT(result <= generatedSrcSize);  /* can be 0 when no round-trip */
438
6.53k
    }
439
440
0
    free(rBuf);
441
6.53k
    free(cBuf);
442
6.53k
    FUZZ_dataProducer_free(producer);
443
6.53k
#ifndef STATEFUL_FUZZING
444
6.53k
    ZSTD_freeCCtx(cctx); cctx = NULL;
445
6.53k
    ZSTD_freeDCtx(dctx); dctx = NULL;
446
6.53k
    free(generatedSequences); generatedSequences = NULL;
447
6.53k
    free(generatedSrc); generatedSrc = NULL;
448
6.53k
    free(literalsBuffer); literalsBuffer = NULL;
449
6.53k
#endif
450
6.53k
    FUZZ_SEQ_PROD_TEARDOWN();
451
6.53k
    return 0;
452
6.53k
}