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