Merge pull request #2131 from terrelln/raw-dict-fuzzer
Fix rare scenario with lazy parser, dictionary, and repcodes
This commit is contained in:
@@ -3288,6 +3288,7 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
|
||||
{
|
||||
ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
|
||||
ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms);
|
||||
DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
|
||||
assert(params.fParams.contentSizeFlag == 1);
|
||||
return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
|
||||
}
|
||||
@@ -4063,6 +4064,7 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
|
||||
{ size_t oPos = 0;
|
||||
size_t iPos = 0;
|
||||
|
||||
@@ -970,6 +970,9 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||
return contiguous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest allowed match index. It may either be in the ext-dict or the prefix.
|
||||
*/
|
||||
MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
|
||||
{
|
||||
U32 const maxDistance = 1U << windowLog;
|
||||
@@ -980,6 +983,19 @@ MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current
|
||||
return matchLowest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest allowed match index in the prefix.
|
||||
*/
|
||||
MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
|
||||
{
|
||||
U32 const maxDistance = 1U << windowLog;
|
||||
U32 const lowestValid = ms->window.dictLimit;
|
||||
U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
|
||||
U32 const isDictionary = (ms->loadedDictEnd != 0);
|
||||
U32 const matchLowest = isDictionary ? lowestValid : withinWindow;
|
||||
return matchLowest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* debug functions */
|
||||
|
||||
@@ -63,10 +63,8 @@ size_t ZSTD_compressBlock_doubleFast_generic(
|
||||
const BYTE* ip = istart;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
||||
const U32 lowestValid = ms->window.dictLimit;
|
||||
const U32 maxDistance = 1U << cParams->windowLog;
|
||||
/* presumes that, if there is a dictionary, it must be using Attach mode */
|
||||
const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid;
|
||||
const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
|
||||
const BYTE* const prefixLowest = base + prefixLowestIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
@@ -104,13 +102,15 @@ size_t ZSTD_compressBlock_doubleFast_generic(
|
||||
|
||||
/* if a dictionary is attached, it must be within window range */
|
||||
if (dictMode == ZSTD_dictMatchState) {
|
||||
assert(lowestValid + maxDistance >= endIndex);
|
||||
assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex);
|
||||
}
|
||||
|
||||
/* init */
|
||||
ip += (dictAndPrefixLength == 0);
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
U32 const maxRep = (U32)(ip - prefixLowest);
|
||||
U32 const current = (U32)(ip - base);
|
||||
U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
|
||||
U32 const maxRep = current - windowLow;
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
@@ -61,9 +61,7 @@ ZSTD_compressBlock_fast_generic(
|
||||
const BYTE* ip1;
|
||||
const BYTE* anchor = istart;
|
||||
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
||||
const U32 maxDistance = 1U << cParams->windowLog;
|
||||
const U32 validStartIndex = ms->window.dictLimit;
|
||||
const U32 prefixStartIndex = (endIndex - validStartIndex > maxDistance) ? endIndex - maxDistance : validStartIndex;
|
||||
const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
|
||||
const BYTE* const prefixStart = base + prefixStartIndex;
|
||||
const BYTE* const iend = istart + srcSize;
|
||||
const BYTE* const ilimit = iend - HASH_READ_SIZE;
|
||||
@@ -74,7 +72,9 @@ ZSTD_compressBlock_fast_generic(
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_fast_generic");
|
||||
ip0 += (ip0 == prefixStart);
|
||||
ip1 = ip0 + 1;
|
||||
{ U32 const maxRep = (U32)(ip0 - prefixStart);
|
||||
{ U32 const current = (U32)(ip0 - base);
|
||||
U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
|
||||
U32 const maxRep = current - windowLow;
|
||||
if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
|
||||
}
|
||||
|
||||
@@ -662,10 +662,14 @@ ZSTD_compressBlock_lazy_generic(
|
||||
0;
|
||||
const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest));
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode);
|
||||
|
||||
/* init */
|
||||
ip += (dictAndPrefixLength == 0);
|
||||
if (dictMode == ZSTD_noDict) {
|
||||
U32 const maxRep = (U32)(ip - prefixLowest);
|
||||
U32 const current = (U32)(ip - base);
|
||||
U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, ms->cParams.windowLog);
|
||||
U32 const maxRep = current - windowLow;
|
||||
if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
|
||||
if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
|
||||
}
|
||||
@@ -929,11 +933,11 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
const BYTE* const ilimit = iend - 8;
|
||||
const BYTE* const base = ms->window.base;
|
||||
const U32 dictLimit = ms->window.dictLimit;
|
||||
const U32 lowestIndex = ms->window.lowLimit;
|
||||
const BYTE* const prefixStart = base + dictLimit;
|
||||
const BYTE* const dictBase = ms->window.dictBase;
|
||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||
const BYTE* const dictStart = dictBase + lowestIndex;
|
||||
const BYTE* const dictStart = dictBase + ms->window.lowLimit;
|
||||
const U32 windowLog = ms->cParams.windowLog;
|
||||
|
||||
typedef size_t (*searchMax_f)(
|
||||
ZSTD_matchState_t* ms,
|
||||
@@ -942,6 +946,8 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
|
||||
U32 offset_1 = rep[0], offset_2 = rep[1];
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic");
|
||||
|
||||
/* init */
|
||||
ip += (ip == prefixStart);
|
||||
|
||||
@@ -953,10 +959,11 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
U32 current = (U32)(ip-base);
|
||||
|
||||
/* check repCode */
|
||||
{ const U32 repIndex = (U32)(current+1 - offset_1);
|
||||
{ const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current+1, windowLog);
|
||||
const U32 repIndex = (U32)(current+1 - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
|
||||
if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
@@ -983,10 +990,11 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
current++;
|
||||
/* check repCode */
|
||||
if (offset) {
|
||||
const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
|
||||
const U32 repIndex = (U32)(current - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
@@ -1013,10 +1021,11 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||
current++;
|
||||
/* check repCode */
|
||||
if (offset) {
|
||||
const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
|
||||
const U32 repIndex = (U32)(current - offset_1);
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
@@ -1057,10 +1066,12 @@ _storeSequence:
|
||||
|
||||
/* check immediate repcode */
|
||||
while (ip <= ilimit) {
|
||||
const U32 repIndex = (U32)((ip-base) - offset_2);
|
||||
const U32 repCurrent = (U32)(ip-base);
|
||||
const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent, windowLog);
|
||||
const U32 repIndex = repCurrent - offset_2;
|
||||
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
|
||||
const BYTE* const repMatch = repBase + repIndex;
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
|
||||
if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
|
||||
if (MEM_read32(ip) == MEM_read32(repMatch)) {
|
||||
/* repcode detected we should take it */
|
||||
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
|
||||
|
||||
@@ -569,7 +569,10 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||
U32 repLen = 0;
|
||||
assert(current >= dictLimit);
|
||||
if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */
|
||||
if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) {
|
||||
/* We must validate the repcode offset because when we're using a dictionary the
|
||||
* valid offset range shrinks when the dictionary goes out of bounds.
|
||||
*/
|
||||
if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) {
|
||||
repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
|
||||
}
|
||||
} else { /* repIndex < dictLimit || repIndex >= current */
|
||||
|
||||
@@ -65,6 +65,10 @@ void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
|
||||
dctx->virtualStart = ddict->dictContent;
|
||||
dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
|
||||
dctx->previousDstEnd = dctx->dictEnd;
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
dctx->dictContentBeginForFuzzing = dctx->prefixStart;
|
||||
dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
|
||||
#endif
|
||||
if (ddict->entropyPresent) {
|
||||
dctx->litEntropy = 1;
|
||||
dctx->fseEntropy = 1;
|
||||
|
||||
@@ -114,6 +114,9 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
|
||||
dctx->oversizedDuration = 0;
|
||||
dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||
dctx->outBufferMode = ZSTD_obm_buffered;
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
dctx->dictContentEndForFuzzing = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
|
||||
@@ -1039,6 +1042,10 @@ static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dict
|
||||
dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
|
||||
dctx->prefixStart = dict;
|
||||
dctx->previousDstEnd = (const char*)dict + dictSize;
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
dctx->dictContentBeginForFuzzing = dctx->prefixStart;
|
||||
dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -947,13 +947,56 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c
|
||||
return seq;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
|
||||
{
|
||||
size_t const windowSize = dctx->fParams.windowSize;
|
||||
/* No dictionary used. */
|
||||
if (dctx->dictContentEndForFuzzing == NULL) return 0;
|
||||
/* Dictionary is our prefix. */
|
||||
if (prefixStart == dctx->dictContentBeginForFuzzing) return 1;
|
||||
/* Dictionary is not our ext-dict. */
|
||||
if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0;
|
||||
/* Dictionary is not within our window size. */
|
||||
if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0;
|
||||
/* Dictionary is active. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
MEM_STATIC void ZSTD_assertValidSequence(
|
||||
ZSTD_DCtx const* dctx,
|
||||
BYTE const* op, BYTE const* oend,
|
||||
seq_t const seq,
|
||||
BYTE const* prefixStart, BYTE const* virtualStart)
|
||||
{
|
||||
size_t const windowSize = dctx->fParams.windowSize;
|
||||
size_t const sequenceSize = seq.litLength + seq.matchLength;
|
||||
BYTE const* const oLitEnd = op + seq.litLength;
|
||||
DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u",
|
||||
(U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
|
||||
assert(op <= oend);
|
||||
assert((size_t)(oend - op) >= sequenceSize);
|
||||
assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX);
|
||||
if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) {
|
||||
size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing);
|
||||
/* Offset must be within the dictionary. */
|
||||
assert(seq.offset <= (size_t)(oLitEnd - virtualStart));
|
||||
assert(seq.offset <= windowSize + dictSize);
|
||||
} else {
|
||||
/* Offset must be within our window. */
|
||||
assert(seq.offset <= windowSize);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
DONT_VECTORIZE
|
||||
ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)seqStart;
|
||||
const BYTE* const iend = ip + seqSize;
|
||||
@@ -966,6 +1009,7 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
||||
const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
|
||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||
DEBUGLOG(5, "ZSTD_decompressSequences_body");
|
||||
(void)frame;
|
||||
|
||||
/* Regen sequences */
|
||||
if (nbSeq) {
|
||||
@@ -1030,6 +1074,10 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
||||
for ( ; ; ) {
|
||||
seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch);
|
||||
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
|
||||
assert(!ZSTD_isError(oneSeqSize));
|
||||
if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase);
|
||||
#endif
|
||||
DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
|
||||
BIT_reloadDStream(&(seqState.DStream));
|
||||
/* gcc and clang both don't like early returns in this loop.
|
||||
@@ -1068,9 +1116,10 @@ static size_t
|
||||
ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
|
||||
|
||||
@@ -1080,7 +1129,8 @@ ZSTD_decompressSequencesLong_body(
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)seqStart;
|
||||
const BYTE* const iend = ip + seqSize;
|
||||
@@ -1092,6 +1142,7 @@ ZSTD_decompressSequencesLong_body(
|
||||
const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
|
||||
const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
|
||||
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
|
||||
(void)frame;
|
||||
|
||||
/* Regen sequences */
|
||||
if (nbSeq) {
|
||||
@@ -1127,6 +1178,10 @@ ZSTD_decompressSequencesLong_body(
|
||||
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
|
||||
seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
|
||||
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
|
||||
assert(!ZSTD_isError(oneSeqSize));
|
||||
if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart);
|
||||
#endif
|
||||
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||
PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
|
||||
sequences[seqNb & STORED_SEQS_MASK] = sequence;
|
||||
@@ -1138,6 +1193,10 @@ ZSTD_decompressSequencesLong_body(
|
||||
seqNb -= seqAdvance;
|
||||
for ( ; seqNb<nbSeq ; seqNb++) {
|
||||
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
|
||||
assert(!ZSTD_isError(oneSeqSize));
|
||||
if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart);
|
||||
#endif
|
||||
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||
op += oneSeqSize;
|
||||
}
|
||||
@@ -1162,9 +1221,10 @@ static size_t
|
||||
ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
|
||||
|
||||
@@ -1178,9 +1238,10 @@ DONT_VECTORIZE
|
||||
ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
|
||||
|
||||
@@ -1189,9 +1250,10 @@ static TARGET_ATTRIBUTE("bmi2") size_t
|
||||
ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
|
||||
|
||||
@@ -1201,21 +1263,23 @@ typedef size_t (*ZSTD_decompressSequences_t)(
|
||||
ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset);
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame);
|
||||
|
||||
#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
|
||||
static size_t
|
||||
ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_decompressSequences");
|
||||
#if DYNAMIC_BMI2
|
||||
if (dctx->bmi2) {
|
||||
return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif
|
||||
return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
|
||||
|
||||
@@ -1230,15 +1294,16 @@ static size_t
|
||||
ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t maxDstSize,
|
||||
const void* seqStart, size_t seqSize, int nbSeq,
|
||||
const ZSTD_longOffset_e isLongOffset)
|
||||
const ZSTD_longOffset_e isLongOffset,
|
||||
const int frame)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_decompressSequencesLong");
|
||||
#if DYNAMIC_BMI2
|
||||
if (dctx->bmi2) {
|
||||
return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif
|
||||
return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
|
||||
}
|
||||
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
|
||||
|
||||
@@ -1333,12 +1398,12 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
if (usePrefetchDecoder)
|
||||
#endif
|
||||
#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
|
||||
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
|
||||
/* else */
|
||||
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
|
||||
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +160,11 @@ struct ZSTD_DCtx_s
|
||||
BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
|
||||
|
||||
size_t oversizedDuration;
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
void const* dictContentBeginForFuzzing;
|
||||
void const* dictContentEndForFuzzing;
|
||||
#endif
|
||||
}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
|
||||
|
||||
|
||||
|
||||
+90
-30
@@ -41,8 +41,10 @@ FUZZ_LDFLAGS := -pthread $(LDFLAGS)
|
||||
FUZZ_ARFLAGS := $(ARFLAGS)
|
||||
FUZZ_TARGET_FLAGS = $(FUZZ_CPPFLAGS) $(FUZZ_CXXFLAGS) $(FUZZ_LDFLAGS)
|
||||
|
||||
FUZZ_ROUND_TRIP_FLAGS := -DFUZZING_ASSERT_VALID_SEQUENCE
|
||||
|
||||
FUZZ_HEADERS := fuzz_helpers.h fuzz.h zstd_helpers.h fuzz_data_producer.h
|
||||
FUZZ_SRC := $(PRGDIR)/util.c fuzz_helpers.c zstd_helpers.c fuzz_data_producer.c
|
||||
FUZZ_SRC := $(PRGDIR)/util.c ./fuzz_helpers.c ./zstd_helpers.c ./fuzz_data_producer.c
|
||||
|
||||
ZSTDCOMMON_SRC := $(ZSTDDIR)/common/*.c
|
||||
ZSTDCOMP_SRC := $(ZSTDDIR)/compress/*.c
|
||||
@@ -56,9 +58,25 @@ FUZZ_SRC := \
|
||||
$(ZSTDCOMP_SRC) \
|
||||
$(ZSTDDICT_SRC) \
|
||||
$(ZSTDLEGACY_SRC)
|
||||
FUZZ_SRC := $(wildcard $(FUZZ_SRC))
|
||||
|
||||
FUZZ_OBJ := $(patsubst %.c,%.o, $(wildcard $(FUZZ_SRC)))
|
||||
FUZZ_D_OBJ1 := $(subst $(ZSTDDIR)/common/,d_lib_common_,$(FUZZ_SRC))
|
||||
FUZZ_D_OBJ2 := $(subst $(ZSTDDIR)/compress/,d_lib_compress_,$(FUZZ_D_OBJ1))
|
||||
FUZZ_D_OBJ3 := $(subst $(ZSTDDIR)/decompress/,d_lib_decompress_,$(FUZZ_D_OBJ2))
|
||||
FUZZ_D_OBJ4 := $(subst $(ZSTDDIR)/dictBuilder/,d_lib_dictBuilder_,$(FUZZ_D_OBJ3))
|
||||
FUZZ_D_OBJ5 := $(subst $(ZSTDDIR)/legacy/,d_lib_legacy_,$(FUZZ_D_OBJ4))
|
||||
FUZZ_D_OBJ6 := $(subst $(PRGDIR)/,d_prg_,$(FUZZ_D_OBJ5))
|
||||
FUZZ_D_OBJ7 := $(subst $\./,d_fuzz_,$(FUZZ_D_OBJ6))
|
||||
FUZZ_DECOMPRESS_OBJ := $(FUZZ_D_OBJ7:.c=.o)
|
||||
|
||||
FUZZ_RT_OBJ1 := $(subst $(ZSTDDIR)/common/,rt_lib_common_,$(FUZZ_SRC))
|
||||
FUZZ_RT_OBJ2 := $(subst $(ZSTDDIR)/compress/,rt_lib_compress_,$(FUZZ_RT_OBJ1))
|
||||
FUZZ_RT_OBJ3 := $(subst $(ZSTDDIR)/decompress/,rt_lib_decompress_,$(FUZZ_RT_OBJ2))
|
||||
FUZZ_RT_OBJ4 := $(subst $(ZSTDDIR)/dictBuilder/,rt_lib_dictBuilder_,$(FUZZ_RT_OBJ3))
|
||||
FUZZ_RT_OBJ5 := $(subst $(ZSTDDIR)/legacy/,rt_lib_legacy_,$(FUZZ_RT_OBJ4))
|
||||
FUZZ_RT_OBJ6 := $(subst $(PRGDIR)/,rt_prg_,$(FUZZ_RT_OBJ5))
|
||||
FUZZ_RT_OBJ7 := $(subst $\./,rt_fuzz_,$(FUZZ_RT_OBJ6))
|
||||
FUZZ_ROUND_TRIP_OBJ := $(FUZZ_RT_OBJ7:.c=.o)
|
||||
|
||||
.PHONY: default all clean cleanall
|
||||
|
||||
@@ -75,48 +93,91 @@ FUZZ_TARGETS := \
|
||||
dictionary_decompress \
|
||||
zstd_frame_info \
|
||||
simple_compress \
|
||||
dictionary_loader
|
||||
dictionary_loader \
|
||||
raw_dictionary_round_trip
|
||||
|
||||
all: $(FUZZ_TARGETS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $^ -c -o $@
|
||||
rt_lib_common_%.o: $(ZSTDDIR)/common/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
simple_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
rt_lib_compress_%.o: $(ZSTDDIR)/compress/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
stream_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) stream_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
rt_lib_decompress_%.o: $(ZSTDDIR)/decompress/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
block_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) block_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) block_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
rt_lib_dictBuilder_%.o: $(ZSTDDIR)/dictBuilder/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
simple_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
rt_lib_legacy_%.o: $(ZSTDDIR)/legacy/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
stream_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) stream_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
rt_prg_%.o: $(PRGDIR)/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
block_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) block_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) block_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
rt_fuzz_%.o: %.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $(FUZZ_ROUND_TRIP_FLAGS) $< -c -o $@
|
||||
|
||||
dictionary_round_trip: $(FUZZ_HEADERS) $(FUZZ_OBJ) dictionary_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) dictionary_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
d_lib_common_%.o: $(ZSTDDIR)/common/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
dictionary_decompress: $(FUZZ_HEADERS) $(FUZZ_OBJ) dictionary_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) dictionary_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
d_lib_compress_%.o: $(ZSTDDIR)/compress/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
simple_compress: $(FUZZ_HEADERS) $(FUZZ_OBJ) simple_compress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) simple_compress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
d_lib_decompress_%.o: $(ZSTDDIR)/decompress/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
zstd_frame_info: $(FUZZ_HEADERS) $(FUZZ_OBJ) zstd_frame_info.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) zstd_frame_info.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
d_lib_dictBuilder_%.o: $(ZSTDDIR)/dictBuilder/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
dictionary_loader: $(FUZZ_HEADERS) $(FUZZ_OBJ) dictionary_loader.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_OBJ) dictionary_loader.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
d_lib_legacy_%.o: $(ZSTDDIR)/legacy/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h $(PRGDIR)/util.c regression_driver.o
|
||||
$(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o
|
||||
d_prg_%.o: $(PRGDIR)/%.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
d_fuzz_%.o: %.c
|
||||
$(CC) $(FUZZ_CPPFLAGS) $(FUZZ_CFLAGS) $< -c -o $@
|
||||
|
||||
simple_round_trip: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_simple_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_simple_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
stream_round_trip: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_stream_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_stream_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
block_round_trip: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_block_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_block_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
simple_decompress: $(FUZZ_HEADERS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_simple_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_simple_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
stream_decompress: $(FUZZ_HEADERS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_stream_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_stream_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
block_decompress: $(FUZZ_HEADERS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_block_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_block_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
dictionary_round_trip: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_dictionary_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_dictionary_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
raw_dictionary_round_trip: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_raw_dictionary_round_trip.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_raw_dictionary_round_trip.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
dictionary_decompress: $(FUZZ_HEADERS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_dictionary_decompress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_dictionary_decompress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
simple_compress: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_simple_compress.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_simple_compress.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
zstd_frame_info: $(FUZZ_HEADERS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_zstd_frame_info.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_DECOMPRESS_OBJ) d_fuzz_zstd_frame_info.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
dictionary_loader: $(FUZZ_HEADERS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_dictionary_loader.o
|
||||
$(CXX) $(FUZZ_TARGET_FLAGS) $(FUZZ_ROUND_TRIP_OBJ) rt_fuzz_dictionary_loader.o $(LIB_FUZZING_ENGINE) -o $@
|
||||
|
||||
libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h $(PRGDIR)/util.c d_fuzz_regression_driver.o
|
||||
$(AR) $(FUZZ_ARFLAGS) $@ d_fuzz_regression_driver.o
|
||||
|
||||
corpora/%_seed_corpus.zip:
|
||||
@mkdir -p corpora
|
||||
@@ -136,7 +197,6 @@ regressiontest: corpora
|
||||
$(PYTHON) ./fuzz.py regression all
|
||||
|
||||
clean:
|
||||
@$(MAKE) -C $(ZSTDDIR) clean
|
||||
@$(RM) *.a *.o
|
||||
@$(RM) simple_round_trip stream_round_trip simple_decompress \
|
||||
stream_decompress block_decompress block_round_trip \
|
||||
|
||||
@@ -85,7 +85,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
|
||||
size_t const rBufSize = size;
|
||||
void* rBuf = FUZZ_malloc(rBufSize);
|
||||
size_t cBufSize = ZSTD_compressBound(size) * 2;
|
||||
size_t cBufSize = ZSTD_compressBound(size);
|
||||
void *cBuf;
|
||||
/* Half of the time fuzz with a 1 byte smaller output size.
|
||||
* This will still succeed because we force the checksum to be disabled,
|
||||
|
||||
@@ -57,6 +57,7 @@ TARGET_INFO = {
|
||||
'zstd_frame_info': TargetInfo(InputType.COMPRESSED_DATA),
|
||||
'simple_compress': TargetInfo(InputType.RAW_DATA),
|
||||
'dictionary_loader': TargetInfo(InputType.DICTIONARY_DATA),
|
||||
'raw_dictionary_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||
}
|
||||
TARGETS = list(TARGET_INFO.keys())
|
||||
ALL_TARGETS = TARGETS + ['all']
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This fuzz target performs a zstd round-trip test (compress & decompress) with
|
||||
* a raw content dictionary, compares the result with the original, and calls
|
||||
* abort() on corruption.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
|
||||
static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize,
|
||||
const void *dict, size_t dictSize,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_dictContentType_e const dictContentType = ZSTD_dct_rawContent;
|
||||
int const refPrefix = FUZZ_dataProducer_uint32Range(producer, 0, 1) != 0;
|
||||
size_t cSize;
|
||||
|
||||
FUZZ_setRandomParameters(cctx, srcSize, producer);
|
||||
/* Disable checksum so we can use sizes smaller than compress bound. */
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0));
|
||||
if (refPrefix)
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_refPrefix_advanced(
|
||||
cctx, dict, dictSize,
|
||||
ZSTD_dct_rawContent));
|
||||
else
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx, dict, dictSize,
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
|
||||
ZSTD_dct_rawContent));
|
||||
cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
|
||||
FUZZ_ZASSERT(cSize);
|
||||
|
||||
if (refPrefix)
|
||||
FUZZ_ZASSERT(ZSTD_DCtx_refPrefix_advanced(
|
||||
dctx, dict, dictSize,
|
||||
dictContentType));
|
||||
else
|
||||
FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
|
||||
dctx, dict, dictSize,
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
|
||||
dictContentType));
|
||||
{
|
||||
size_t const ret = ZSTD_decompressDCtx(
|
||||
dctx, result, resultCapacity, compressed, cSize);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
uint8_t const* const srcBuf = src;
|
||||
size_t const srcSize = FUZZ_dataProducer_uint32Range(producer, 0, size);
|
||||
uint8_t const* const dictBuf = srcBuf + srcSize;
|
||||
size_t const dictSize = size - srcSize;
|
||||
size_t const decompSize = srcSize;
|
||||
void* const decompBuf = FUZZ_malloc(decompSize);
|
||||
size_t compSize = ZSTD_compressBound(srcSize);
|
||||
void* compBuf;
|
||||
/* Half of the time fuzz with a 1 byte smaller output size.
|
||||
* This will still succeed because we force the checksum to be disabled,
|
||||
* giving us 4 bytes of overhead.
|
||||
*/
|
||||
compSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
compBuf = FUZZ_malloc(compSize);
|
||||
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
FUZZ_ASSERT(cctx);
|
||||
}
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
FUZZ_ASSERT(dctx);
|
||||
}
|
||||
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(decompBuf, decompSize, compBuf, compSize, srcBuf, srcSize, dictBuf, dictSize, producer);
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == srcSize, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, decompBuf, srcSize), "Corruption!");
|
||||
}
|
||||
free(decompBuf);
|
||||
free(compBuf);
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user