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