From b5cddda073ccdfadbee022d452b34d3eaf7d30ed Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Fri, 21 Aug 2020 15:59:03 -0400 Subject: [PATCH 01/12] Add new definition of ZSTD_d_forceSkipChecksum in experimental section --- lib/zstd.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/zstd.h b/lib/zstd.h index 2cb82d7a1..76afd183e 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -528,11 +528,13 @@ typedef enum { * At the time of this writing, they include : * ZSTD_d_format * ZSTD_d_stableOutBuffer + * ZSTD_d_forceSkipChecksum * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly */ ZSTD_d_experimentalParam1=1000, - ZSTD_d_experimentalParam2=1001 + ZSTD_d_experimentalParam2=1001, + ZSTD_d_experimentalParam3=1002 } ZSTD_dParameter; @@ -1690,6 +1692,16 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS */ #define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 +/* ZSTD_d_forceSkipChecksum + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * Tells the decompressor to skip checksum validation during decompression, regardless. + * of whether or not checksumming was specified during decompression. This offers some + * slight performance benefits, and may be useful for debugging. + */ +#define ZSTD_d_forceSkipChecksum ZSTD_d_experimentalParam3 + /*! ZSTD_DCtx_setFormat() : * Instruct the decoder context about what kind of data to decode next. * This instruction is mandatory to decode data without a fully-formed header, From 2f391243425132001d30615d64bfb953cabb9631 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Fri, 21 Aug 2020 16:23:39 -0400 Subject: [PATCH 02/12] Rename to ZSTD_d_forceIgnoreChecksum, add to DCtx, add function to set the advanced param --- lib/decompress/zstd_decompress.c | 15 +++++++++++++-- lib/decompress/zstd_decompress_internal.h | 6 ++++++ lib/zstd.h | 6 +++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index be5c7cfc3..82c24f328 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1397,6 +1397,11 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } +size_t ZSTD_DCtx_setForceSkipChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format) +{ + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceSkipChecksum, format); +} + ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) { ZSTD_bounds bounds = { 0, 0, 0 }; @@ -1414,6 +1419,9 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) bounds.lowerBound = (int)ZSTD_obm_buffered; bounds.upperBound = (int)ZSTD_obm_stable; return bounds; + case ZSTD_d_forceIgnoreChecksum: + bounds.lowerBound = (int)ZSTD_d_validateChecksum; + bounds.upperBound = (int)ZSTD_d_ignoreChecksum; default:; } bounds.error = ERROR(parameter_unsupported); @@ -1453,6 +1461,9 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); dctx->outBufferMode = (ZSTD_outBufferMode_e)value; return 0; + case ZSTD_d_forceIgnoreChecksum: + CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); + dctx->forceIgnoreChecksum = (ZSTD_ignoreChecksumMode_e)value; default:; } RETURN_ERROR(parameter_unsupported, ""); @@ -1524,7 +1535,7 @@ static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const ne { if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) zds->oversizedDuration++; - else + else zds->oversizedDuration = 0; } @@ -1731,7 +1742,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); - + if (tooSmall || tooLarge) { size_t const bufferSize = neededInBuffSize + neededOutBuffSize; DEBUGLOG(4, "inBuff : from %u to %u", diff --git a/lib/decompress/zstd_decompress_internal.h b/lib/decompress/zstd_decompress_internal.h index 9ad96c554..0481ce645 100644 --- a/lib/decompress/zstd_decompress_internal.h +++ b/lib/decompress/zstd_decompress_internal.h @@ -100,6 +100,11 @@ typedef enum { ZSTD_obm_stable = 1 /* ZSTD_outBuffer is stable */ } ZSTD_outBufferMode_e; +typedef enum { + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_ignoreChecksumMode_e; + struct ZSTD_DCtx_s { const ZSTD_seqSymbol* LLTptr; @@ -122,6 +127,7 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; + ZSTD_ignoreChecksumMode_e forceIgnoreChecksum; /* if enabled, will ignore checksums in compressed frame */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; diff --git a/lib/zstd.h b/lib/zstd.h index 76afd183e..d37c59965 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -528,7 +528,7 @@ typedef enum { * At the time of this writing, they include : * ZSTD_d_format * ZSTD_d_stableOutBuffer - * ZSTD_d_forceSkipChecksum + * ZSTD_d_forceIgnoreChecksum * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly */ @@ -1692,7 +1692,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS */ #define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 -/* ZSTD_d_forceSkipChecksum +/* ZSTD_d_forceIgnoreChecksum * Experimental parameter. * Default is 0 == disabled. Set to 1 to enable * @@ -1700,7 +1700,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS * of whether or not checksumming was specified during decompression. This offers some * slight performance benefits, and may be useful for debugging. */ -#define ZSTD_d_forceSkipChecksum ZSTD_d_experimentalParam3 +#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 /*! ZSTD_DCtx_setFormat() : * Instruct the decoder context about what kind of data to decode next. From 6a8dbdcd1f0e68782d244e95b0e14ba6fe307fb4 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Fri, 21 Aug 2020 16:46:46 -0400 Subject: [PATCH 03/12] Modify decompression loop to gnore checksums if flag is enabled --- lib/decompress/zstd_decompress.c | 9 +++++---- lib/decompress/zstd_decompress_internal.h | 4 ++-- tests/fuzzer.c | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 82c24f328..73ed7e1a8 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -114,6 +114,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->oversizedDuration = 0; dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); dctx->outBufferMode = ZSTD_obm_buffered; + dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION dctx->dictContentEndForFuzzing = NULL; #endif @@ -661,7 +662,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, } if (ZSTD_isError(decodedSize)) return decodedSize; - if (dctx->fParams.checksumFlag) + if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) XXH64_update(&dctx->xxhState, op, decodedSize); if (decodedSize != 0) op += decodedSize; @@ -675,7 +676,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, corruption_detected, ""); } - if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) { /* Frame content checksum verification */ U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); U32 checkRead; RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); @@ -1399,7 +1400,7 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) size_t ZSTD_DCtx_setForceSkipChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceSkipChecksum, format); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, format); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) @@ -1463,7 +1464,7 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value return 0; case ZSTD_d_forceIgnoreChecksum: CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); - dctx->forceIgnoreChecksum = (ZSTD_ignoreChecksumMode_e)value; + dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; default:; } RETURN_ERROR(parameter_unsupported, ""); diff --git a/lib/decompress/zstd_decompress_internal.h b/lib/decompress/zstd_decompress_internal.h index 0481ce645..6f1dda202 100644 --- a/lib/decompress/zstd_decompress_internal.h +++ b/lib/decompress/zstd_decompress_internal.h @@ -103,7 +103,7 @@ typedef enum { typedef enum { ZSTD_d_validateChecksum = 0, ZSTD_d_ignoreChecksum = 1 -} ZSTD_ignoreChecksumMode_e; +} ZSTD_forceIgnoreChecksum_e; struct ZSTD_DCtx_s { @@ -127,7 +127,7 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; - ZSTD_ignoreChecksumMode_e forceIgnoreChecksum; /* if enabled, will ignore checksums in compressed frame */ + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* if == 1, will ignore checksums in compressed frame */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 8ac2864f3..cb68ca5d0 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -2354,6 +2354,9 @@ static int basicUnitTests(U32 const seed, double compressibility) { size_t const sr = ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (ZSTD_format_e)888); if (!ZSTD_isError(sr)) goto _output_error; } + { size_t const sr = ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, (ZSTD_forceIgnoreChecksum_e)888); + if (!ZSTD_isError(sr)) goto _output_error; + } DISPLAYLEVEL(3, "OK \n"); ZSTD_freeDCtx(dctx); From 08d3567ba8666873b29a4b8adfea24cfd68cac1e Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Fri, 21 Aug 2020 16:51:43 -0400 Subject: [PATCH 04/12] Add function prototype --- lib/decompress/zstd_decompress.c | 2 +- lib/zstd.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 73ed7e1a8..de2314dbc 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1398,7 +1398,7 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } -size_t ZSTD_DCtx_setForceSkipChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format) +size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format) { return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, format); } diff --git a/lib/zstd.h b/lib/zstd.h index d37c59965..c3a34387a 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1709,6 +1709,11 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); +/*! ZSTD_DCtx_setForceIgnoreChecksum() : + * Instruct the decoder context to ignore checksums in compressed frame. + * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format); + /*! ZSTD_decompressStream_simpleArgs() : * Same as ZSTD_decompressStream(), * but using only integral types as arguments. From 1b34b15e6bd1a2148a2338535c7ad764ebb39d7c Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Fri, 21 Aug 2020 17:49:30 -0400 Subject: [PATCH 05/12] Adding CLI capability to invoke decompression with no checksum --- programs/fileio.c | 4 ++++ tests/fuzzer.c | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index d5b8a7d14..491740c91 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1754,6 +1754,10 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi if (ress.dctx==NULL) EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); + if (!prefs->checksumFlag) { + DISPLAY("Ignoring checksums..."); + CHECK( ZSTD_DCtx_setForceIgnoreChecksum(ress.dctx, 1 /* ZSTD_d_ignoreChecksum */)); + } ress.srcBufferSize = ZSTD_DStreamInSize(); ress.srcBuffer = malloc(ress.srcBufferSize); ress.dstBufferSize = ZSTD_DStreamOutSize(); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index cb68ca5d0..8ac2864f3 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -2354,9 +2354,6 @@ static int basicUnitTests(U32 const seed, double compressibility) { size_t const sr = ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (ZSTD_format_e)888); if (!ZSTD_isError(sr)) goto _output_error; } - { size_t const sr = ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, (ZSTD_forceIgnoreChecksum_e)888); - if (!ZSTD_isError(sr)) goto _output_error; - } DISPLAYLEVEL(3, "OK \n"); ZSTD_freeDCtx(dctx); From 47685ac8560b0700a144a3ba7a7bc7a52d6859f9 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Fri, 21 Aug 2020 18:18:53 -0400 Subject: [PATCH 06/12] Move enum into zstd.h, and fix pesky switch() logic --- lib/decompress/zstd_decompress.c | 6 ++++-- lib/decompress/zstd_decompress_internal.h | 5 ----- lib/zstd.h | 7 ++++++- programs/fileio.c | 4 +--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index de2314dbc..0177f1d4f 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1398,9 +1398,9 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } -size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format) +size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e shouldIgnore) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, format); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, shouldIgnore); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) @@ -1423,6 +1423,7 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) case ZSTD_d_forceIgnoreChecksum: bounds.lowerBound = (int)ZSTD_d_validateChecksum; bounds.upperBound = (int)ZSTD_d_ignoreChecksum; + return bounds; default:; } bounds.error = ERROR(parameter_unsupported); @@ -1465,6 +1466,7 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value case ZSTD_d_forceIgnoreChecksum: CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; + return 0; default:; } RETURN_ERROR(parameter_unsupported, ""); diff --git a/lib/decompress/zstd_decompress_internal.h b/lib/decompress/zstd_decompress_internal.h index 6f1dda202..178023806 100644 --- a/lib/decompress/zstd_decompress_internal.h +++ b/lib/decompress/zstd_decompress_internal.h @@ -100,11 +100,6 @@ typedef enum { ZSTD_obm_stable = 1 /* ZSTD_outBuffer is stable */ } ZSTD_outBufferMode_e; -typedef enum { - ZSTD_d_validateChecksum = 0, - ZSTD_d_ignoreChecksum = 1 -} ZSTD_forceIgnoreChecksum_e; - struct ZSTD_DCtx_s { const ZSTD_seqSymbol* LLTptr; diff --git a/lib/zstd.h b/lib/zstd.h index c3a34387a..c5dd2e94a 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1162,6 +1162,11 @@ typedef enum { * Decoder cannot recognise automatically this format, requiring this instruction. */ } ZSTD_format_e; +typedef enum { + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_forceIgnoreChecksum_e; + typedef enum { /* Note: this enum and the behavior it controls are effectively internal * implementation details of the compressor. They are expected to continue @@ -1712,7 +1717,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); /*! ZSTD_DCtx_setForceIgnoreChecksum() : * Instruct the decoder context to ignore checksums in compressed frame. * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_format_e format); +ZSTDLIB_API size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e format); /*! ZSTD_decompressStream_simpleArgs() : * Same as ZSTD_decompressStream(), diff --git a/programs/fileio.c b/programs/fileio.c index 491740c91..5349bc6b1 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1754,10 +1754,8 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi if (ress.dctx==NULL) EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); - if (!prefs->checksumFlag) { - DISPLAY("Ignoring checksums..."); + if (!prefs->checksumFlag) CHECK( ZSTD_DCtx_setForceIgnoreChecksum(ress.dctx, 1 /* ZSTD_d_ignoreChecksum */)); - } ress.srcBufferSize = ZSTD_DStreamInSize(); ress.srcBuffer = malloc(ress.srcBufferSize); ress.dstBufferSize = ZSTD_DStreamOutSize(); From 20eb0958822af10440cfd689925e689fd041caeb Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Sat, 22 Aug 2020 13:26:33 -0400 Subject: [PATCH 07/12] Added unit test to fuzzer.c, changed definition param name --- lib/decompress/zstd_decompress.c | 20 ++++++++++--------- lib/zstd.h | 2 +- tests/fuzzer.c | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 0177f1d4f..21e724d7e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -676,12 +676,14 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, corruption_detected, ""); } - if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) { /* Frame content checksum verification */ - U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); - U32 checkRead; - RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); - checkRead = MEM_readLE32(ip); - RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + if (!dctx->forceIgnoreChecksum) { + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + } ip += 4; remainingSrcSize -= 4; } @@ -978,7 +980,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); dctx->decodedSize += rSize; - if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); + if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) XXH64_update(&dctx->xxhState, dst, rSize); dctx->previousDstEnd = (char*)dst + rSize; /* Stay on the same stage until we are finished streaming the block. */ @@ -1398,9 +1400,9 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } -size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e shouldIgnore) +size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e value) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, shouldIgnore); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, value); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) diff --git a/lib/zstd.h b/lib/zstd.h index c5dd2e94a..9f9f991f3 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1717,7 +1717,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); /*! ZSTD_DCtx_setForceIgnoreChecksum() : * Instruct the decoder context to ignore checksums in compressed frame. * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e format); +ZSTDLIB_API size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e value); /*! ZSTD_decompressStream_simpleArgs() : * Same as ZSTD_decompressStream(), diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 8ac2864f3..4f0676ab7 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -544,6 +544,40 @@ static int basicUnitTests(U32 const seed, double compressibility) if (ZSTD_getErrorCode(r) != ZSTD_error_dstSize_tooSmall) goto _output_error; } DISPLAYLEVEL(3, "OK \n"); + DISPLAYLEVEL(3, "test%3i : decompress with corrupted checksum : ", testNb++); + { /* create compressed buffer with checksumming enabled */ + ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1) ); + CHECK_VAR(cSize, ZSTD_compress2(cctx, + compressedBuffer, compressedBufferSize, + CNBuffer, CNBuffSize) ); + ZSTD_freeCCtx(cctx); + } + { /* copy the compressed buffer and corrupt the checksum */ + char* corruptedChecksumCompressedBuffer = (char*)malloc(cSize); + if (!corruptedChecksumCompressedBuffer) { + DISPLAY("Not enough memory, aborting\n"); + testResult = 1; + goto _end; + } + + memcpy(corruptedChecksumCompressedBuffer, compressedBuffer, cSize); + corruptedChecksumCompressedBuffer[cSize-1] += 1; + size_t r = ZSTD_decompress(decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); + if (!ZSTD_isError(r)) goto _output_error; + if (ZSTD_getErrorCode(r) != ZSTD_error_checksum_wrong) goto _output_error; + + ZSTD_DCtx* dctx = ZSTD_createDCtx(); assert(dctx != NULL); + CHECK_Z(ZSTD_DCtx_setForceIgnoreChecksum(dctx, ZSTD_d_ignoreChecksum)); + r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); + if (ZSTD_isError(r)) goto _output_error; + + ZSTD_freeDCtx(dctx); + free(corruptedChecksumCompressedBuffer); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3i : ZSTD_decompressBound test with content size missing : ", testNb++); { /* create compressed buffer with content size missing */ ZSTD_CCtx* const cctx = ZSTD_createCCtx(); From e3f5f9658a46efd6619e50cae857fa3903c32059 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Sat, 22 Aug 2020 16:05:40 -0400 Subject: [PATCH 08/12] Added CLI tests for --no-check, fixed ignore checksum logic --- lib/decompress/zstd_decompress.c | 13 ++++++++----- programs/fileio.c | 2 +- tests/playTests.sh | 5 +++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 21e724d7e..6999966a3 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -447,7 +447,7 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), dictionary_wrong, ""); #endif - if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0); + if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) XXH64_reset(&dctx->xxhState, 0); return 0; } @@ -1010,10 +1010,13 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_checkChecksum: assert(srcSize == 4); /* guaranteed by dctx->expected */ - { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); - U32 const check32 = MEM_readLE32(src); - DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); - RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + { + if (!dctx->forceIgnoreChecksum) { + U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + } dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; diff --git a/programs/fileio.c b/programs/fileio.c index 5349bc6b1..38f59a737 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1755,7 +1755,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); if (!prefs->checksumFlag) - CHECK( ZSTD_DCtx_setForceIgnoreChecksum(ress.dctx, 1 /* ZSTD_d_ignoreChecksum */)); + CHECK( ZSTD_DCtx_setForceIgnoreChecksum(ress.dctx, ZSTD_d_ignoreChecksum)); ress.srcBufferSize = ZSTD_DStreamInSize(); ress.srcBuffer = malloc(ress.srcBufferSize); ress.dstBufferSize = ZSTD_DStreamOutSize(); diff --git a/tests/playTests.sh b/tests/playTests.sh index b7bfa76cd..3d099efb2 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -260,6 +260,11 @@ zstd tmp -c --compress-literals --fast=1 | zstd -t zstd tmp -c --compress-literals -19 | zstd -t zstd -b --fast=1 -i0e1 tmp --compress-literals zstd -b --fast=1 -i0e1 tmp --no-compress-literals +println "test: --no-check for decompression" +zstd -f tmp --check +zstd -f tmp -o tmp1.zst --no-check +zstd -d -f tmp.zst --no-check +zstd -d -f tmp1.zst --no-check println "\n===> zstdgrep tests" ln -sf "$ZSTD_BIN" zstdcat From ffaa0df76d509c5243103b99b049e57ad85d48c2 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Sat, 22 Aug 2020 16:58:41 -0400 Subject: [PATCH 09/12] Document change in CLI for --no-check during decompression in --help menu --- lib/decompress/zstd_decompress.c | 4 ++-- lib/zstd.h | 4 ++-- programs/zstdcli.c | 1 + tests/fuzzer.c | 9 +++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 6999966a3..d02638109 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1543,7 +1543,7 @@ static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const ne { if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) zds->oversizedDuration++; - else + else zds->oversizedDuration = 0; } @@ -1750,7 +1750,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); - + if (tooSmall || tooLarge) { size_t const bufferSize = neededInBuffSize + neededOutBuffSize; DEBUGLOG(4, "inBuff : from %u to %u", diff --git a/lib/zstd.h b/lib/zstd.h index 9f9f991f3..572f5063b 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1701,8 +1701,8 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS * Experimental parameter. * Default is 0 == disabled. Set to 1 to enable * - * Tells the decompressor to skip checksum validation during decompression, regardless. - * of whether or not checksumming was specified during decompression. This offers some + * Tells the decompressor to skip checksum validation during decompression, regardless + * of whether checksumming was specified during compression. This offers some * slight performance benefits, and may be useful for debugging. */ #define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 1aea63dca..b7e7d1fda 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -196,6 +196,7 @@ static void usage_advanced(const char* programName) DISPLAYOUT( " -l : print information about zstd compressed files \n"); DISPLAYOUT( "--test : test compressed file integrity \n"); DISPLAYOUT( " -M# : Set a memory usage limit for decompression \n"); + DISPLAYOUT( "--no-check : disable validation of checksums in compressed frame \n"); # if ZSTD_SPARSE_DEFAULT DISPLAYOUT( "--[no-]sparse : sparse mode (default: enabled on file, disabled on stdout) \n"); # else diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 4f0676ab7..7f8d9f654 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -554,8 +554,10 @@ static int basicUnitTests(U32 const seed, double compressibility) ZSTD_freeCCtx(cctx); } { /* copy the compressed buffer and corrupt the checksum */ - char* corruptedChecksumCompressedBuffer = (char*)malloc(cSize); - if (!corruptedChecksumCompressedBuffer) { + size_t r; + char* const corruptedChecksumCompressedBuffer = (char*)malloc(cSize); + ZSTD_DCtx* const dctx = ZSTD_createDCtx(); + if (!corruptedChecksumCompressedBuffer || !dctx) { DISPLAY("Not enough memory, aborting\n"); testResult = 1; goto _end; @@ -563,11 +565,10 @@ static int basicUnitTests(U32 const seed, double compressibility) memcpy(corruptedChecksumCompressedBuffer, compressedBuffer, cSize); corruptedChecksumCompressedBuffer[cSize-1] += 1; - size_t r = ZSTD_decompress(decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); + r = ZSTD_decompress(decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); if (!ZSTD_isError(r)) goto _output_error; if (ZSTD_getErrorCode(r) != ZSTD_error_checksum_wrong) goto _output_error; - ZSTD_DCtx* dctx = ZSTD_createDCtx(); assert(dctx != NULL); CHECK_Z(ZSTD_DCtx_setForceIgnoreChecksum(dctx, ZSTD_d_ignoreChecksum)); r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); if (ZSTD_isError(r)) goto _output_error; From 44c54a3e319df11df1078c46e194ebd948825bd0 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Mon, 24 Aug 2020 16:14:19 -0400 Subject: [PATCH 10/12] Addressing comments: more comments, cleanup, remove extra function, checksum logic --- lib/decompress/zstd_decompress.c | 7 +------ lib/zstd.h | 7 ++----- programs/fileio.c | 8 ++++++-- programs/zstdcli.c | 16 ++++++++++++++-- tests/fuzzer.c | 18 +++++++++++------- tests/playTests.sh | 3 ++- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index d02638109..f26e5ff61 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -677,10 +677,10 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, corruption_detected, ""); } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); if (!dctx->forceIgnoreChecksum) { U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); U32 checkRead; - RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); checkRead = MEM_readLE32(ip); RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); } @@ -1403,11 +1403,6 @@ size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } -size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e value) -{ - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, value); -} - ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) { ZSTD_bounds bounds = { 0, 0, 0 }; diff --git a/lib/zstd.h b/lib/zstd.h index 572f5063b..742fab442 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1163,6 +1163,7 @@ typedef enum { } ZSTD_format_e; typedef enum { + /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ ZSTD_d_validateChecksum = 0, ZSTD_d_ignoreChecksum = 1 } ZSTD_forceIgnoreChecksum_e; @@ -1704,6 +1705,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS * Tells the decompressor to skip checksum validation during decompression, regardless * of whether checksumming was specified during compression. This offers some * slight performance benefits, and may be useful for debugging. + * Param has values of type ZSTD_forceIgnoreChecksum_e */ #define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 @@ -1714,11 +1716,6 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); -/*! ZSTD_DCtx_setForceIgnoreChecksum() : - * Instruct the decoder context to ignore checksums in compressed frame. - * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setForceIgnoreChecksum(ZSTD_DCtx* dctx, ZSTD_forceIgnoreChecksum_e value); - /*! ZSTD_decompressStream_simpleArgs() : * Same as ZSTD_decompressStream(), * but using only integral types as arguments. diff --git a/programs/fileio.c b/programs/fileio.c index 38f59a737..f2b8447af 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1754,8 +1754,12 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi if (ress.dctx==NULL) EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); - if (!prefs->checksumFlag) - CHECK( ZSTD_DCtx_setForceIgnoreChecksum(ress.dctx, ZSTD_d_ignoreChecksum)); + if (!prefs->checksumFlag) { + CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, ZSTD_d_ignoreChecksum)); + } else { + CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, ZSTD_d_validateChecksum)); + } + ress.srcBufferSize = ZSTD_DStreamInSize(); ress.srcBuffer = malloc(ress.srcBufferSize); ress.dstBufferSize = ZSTD_DStreamOutSize(); diff --git a/programs/zstdcli.c b/programs/zstdcli.c index b7e7d1fda..fce88d8c2 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -154,6 +154,20 @@ static void usage_advanced(const char* programName) DISPLAYOUT( "--output-dir-mirror DIR : processed files are stored into DIR respecting original directory structure \n"); #endif + +#ifndef ZSTD_NOCOMPRESS + DISPLAYOUT( "--[no-]check : during compression, add XXH64 integrity checksum to frame (default: enabled)"); +#ifndef ZSTD_NODECOMPRESS + DISPLAYOUT( ". If specified with -d, decompressor will ignore/validate checksums in compressed frame (default: validate)."); +#endif +#endif /* ZSTD_NOCOMPRESS */ +#ifndef ZSTD_NODECOMPRESS +#ifdef ZSTD_NOCOMPRESS + DISPLAYOUT( "--[no-]check : during decompression, ignore/validate checksums in compressed frame (default: validate)."); +#endif +#endif /* ZSTD_NODECOMPRESS */ + DISPLAYOUT( "\n"); + DISPLAYOUT( "-- : All arguments after \"--\" are treated as files \n"); #ifndef ZSTD_NOCOMPRESS @@ -174,7 +188,6 @@ static void usage_advanced(const char* programName) DISPLAYOUT( "--size-hint=# optimize compression parameters for streaming input of approximately this size \n"); DISPLAYOUT( "--target-compressed-block-size=# : generate compressed block of approximately targeted size \n"); DISPLAYOUT( "--no-dictID : don't write dictID into header (dictionary compression only) \n"); - DISPLAYOUT( "--[no-]check : add XXH64 integrity checksum to frame (default: enabled) \n"); DISPLAYOUT( "--[no-]compress-literals : force (un)compressed literals \n"); DISPLAYOUT( "--format=zstd : compress files to the .zst format (default) \n"); @@ -196,7 +209,6 @@ static void usage_advanced(const char* programName) DISPLAYOUT( " -l : print information about zstd compressed files \n"); DISPLAYOUT( "--test : test compressed file integrity \n"); DISPLAYOUT( " -M# : Set a memory usage limit for decompression \n"); - DISPLAYOUT( "--no-check : disable validation of checksums in compressed frame \n"); # if ZSTD_SPARSE_DEFAULT DISPLAYOUT( "--[no-]sparse : sparse mode (default: enabled on file, disabled on stdout) \n"); # else diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 7f8d9f654..d85ccef5d 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -547,6 +547,11 @@ static int basicUnitTests(U32 const seed, double compressibility) DISPLAYLEVEL(3, "test%3i : decompress with corrupted checksum : ", testNb++); { /* create compressed buffer with checksumming enabled */ ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + if (!cctx) { + DISPLAY("Not enough memory, aborting\n"); + testResult = 1; + goto _end; + } CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1) ); CHECK_VAR(cSize, ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, @@ -555,26 +560,25 @@ static int basicUnitTests(U32 const seed, double compressibility) } { /* copy the compressed buffer and corrupt the checksum */ size_t r; - char* const corruptedChecksumCompressedBuffer = (char*)malloc(cSize); ZSTD_DCtx* const dctx = ZSTD_createDCtx(); - if (!corruptedChecksumCompressedBuffer || !dctx) { + if (!dctx) { DISPLAY("Not enough memory, aborting\n"); testResult = 1; goto _end; } - memcpy(corruptedChecksumCompressedBuffer, compressedBuffer, cSize); - corruptedChecksumCompressedBuffer[cSize-1] += 1; - r = ZSTD_decompress(decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); + ((char*)compressedBuffer)[cSize-1] += 1; + r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize); if (!ZSTD_isError(r)) goto _output_error; if (ZSTD_getErrorCode(r) != ZSTD_error_checksum_wrong) goto _output_error; CHECK_Z(ZSTD_DCtx_setForceIgnoreChecksum(dctx, ZSTD_d_ignoreChecksum)); - r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, corruptedChecksumCompressedBuffer, cSize); + r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize-1); + if (!ZSTD_isError(r)) goto _output_error; /* wrong checksum size should still throw error */ + r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize); if (ZSTD_isError(r)) goto _output_error; ZSTD_freeDCtx(dctx); - free(corruptedChecksumCompressedBuffer); } DISPLAYLEVEL(3, "OK \n"); diff --git a/tests/playTests.sh b/tests/playTests.sh index 3d099efb2..affd64eb0 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -261,8 +261,9 @@ zstd tmp -c --compress-literals -19 | zstd -t zstd -b --fast=1 -i0e1 tmp --compress-literals zstd -b --fast=1 -i0e1 tmp --no-compress-literals println "test: --no-check for decompression" -zstd -f tmp --check +zstd -f tmp -o tmp.zst --check zstd -f tmp -o tmp1.zst --no-check +printf '\xDE\xAD\xBE\xEF' | dd of=tmp.zst bs=1 seek=$(($(wc -c <"tmp.zst") - 4)) count=4 conv=notrunc # corrupt checksum in tmp zstd -d -f tmp.zst --no-check zstd -d -f tmp1.zst --no-check From a030560d6274ee2b4d9a262f40e27e920bee9aa9 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Mon, 24 Aug 2020 17:28:00 -0400 Subject: [PATCH 11/12] Add new DCtx param: validateChecksum and update unit tests --- lib/decompress/zstd_decompress.c | 10 ++++++---- lib/decompress/zstd_decompress_internal.h | 3 ++- programs/fileio.c | 6 +----- tests/fuzzer.c | 4 ++-- tests/playTests.sh | 9 +++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index f26e5ff61..c8cfa716e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -115,6 +115,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); dctx->outBufferMode = ZSTD_obm_buffered; dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; + dctx->validateChecksum = 1; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION dctx->dictContentEndForFuzzing = NULL; #endif @@ -447,7 +448,8 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), dictionary_wrong, ""); #endif - if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) XXH64_reset(&dctx->xxhState, 0); + dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; + if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); return 0; } @@ -662,7 +664,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, } if (ZSTD_isError(decodedSize)) return decodedSize; - if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, op, decodedSize); if (decodedSize != 0) op += decodedSize; @@ -980,7 +982,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); dctx->decodedSize += rSize; - if (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) XXH64_update(&dctx->xxhState, dst, rSize); + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); dctx->previousDstEnd = (char*)dst + rSize; /* Stay on the same stage until we are finished streaming the block. */ @@ -1011,7 +1013,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_checkChecksum: assert(srcSize == 4); /* guaranteed by dctx->expected */ { - if (!dctx->forceIgnoreChecksum) { + if (dctx->validateChecksum) { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); U32 const check32 = MEM_readLE32(src); DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); diff --git a/lib/decompress/zstd_decompress_internal.h b/lib/decompress/zstd_decompress_internal.h index 178023806..891d1bedb 100644 --- a/lib/decompress/zstd_decompress_internal.h +++ b/lib/decompress/zstd_decompress_internal.h @@ -122,7 +122,8 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; - ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* if == 1, will ignore checksums in compressed frame */ + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ + U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; diff --git a/programs/fileio.c b/programs/fileio.c index f2b8447af..1970f6cb2 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1754,11 +1754,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi if (ress.dctx==NULL) EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); - if (!prefs->checksumFlag) { - CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, ZSTD_d_ignoreChecksum)); - } else { - CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, ZSTD_d_validateChecksum)); - } + CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, !prefs->checksumFlag)); ress.srcBufferSize = ZSTD_DStreamInSize(); ress.srcBuffer = malloc(ress.srcBufferSize); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index d85ccef5d..e5c3e6e3b 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -571,8 +571,8 @@ static int basicUnitTests(U32 const seed, double compressibility) r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize); if (!ZSTD_isError(r)) goto _output_error; if (ZSTD_getErrorCode(r) != ZSTD_error_checksum_wrong) goto _output_error; - - CHECK_Z(ZSTD_DCtx_setForceIgnoreChecksum(dctx, ZSTD_d_ignoreChecksum)); + + CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_forceIgnoreChecksum, ZSTD_d_ignoreChecksum)); r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize-1); if (!ZSTD_isError(r)) goto _output_error; /* wrong checksum size should still throw error */ r = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize); diff --git a/tests/playTests.sh b/tests/playTests.sh index affd64eb0..18f6f3fb9 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -261,11 +261,12 @@ zstd tmp -c --compress-literals -19 | zstd -t zstd -b --fast=1 -i0e1 tmp --compress-literals zstd -b --fast=1 -i0e1 tmp --no-compress-literals println "test: --no-check for decompression" -zstd -f tmp -o tmp.zst --check -zstd -f tmp -o tmp1.zst --no-check -printf '\xDE\xAD\xBE\xEF' | dd of=tmp.zst bs=1 seek=$(($(wc -c <"tmp.zst") - 4)) count=4 conv=notrunc # corrupt checksum in tmp +zstd -f tmp -o tmp_corrupt.zst --check +zstd -f tmp -o tmp.zst --no-check +printf '\xDE\xAD\xBE\xEF' | dd of=tmp_corrupt.zst bs=1 seek=$(($(wc -c < "tmp_corrupt.zst") - 4)) count=4 conv=notrunc # corrupt checksum in tmp +zstd -d -f tmp_corrupt.zst --no-check +zstd -d -f tmp_corrupt.zst --check --no-check # final flag overrides zstd -d -f tmp.zst --no-check -zstd -d -f tmp1.zst --no-check println "\n===> zstdgrep tests" ln -sf "$ZSTD_BIN" zstdcat From e1e41addb3b5d318c1490f20b66a9e49d85a2ab6 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Mon, 24 Aug 2020 17:36:36 -0400 Subject: [PATCH 12/12] Adjust #ifndef logic --- programs/zstdcli.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index fce88d8c2..4dda2a5cd 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -160,12 +160,11 @@ static void usage_advanced(const char* programName) #ifndef ZSTD_NODECOMPRESS DISPLAYOUT( ". If specified with -d, decompressor will ignore/validate checksums in compressed frame (default: validate)."); #endif -#endif /* ZSTD_NOCOMPRESS */ -#ifndef ZSTD_NODECOMPRESS +#else #ifdef ZSTD_NOCOMPRESS DISPLAYOUT( "--[no-]check : during decompression, ignore/validate checksums in compressed frame (default: validate)."); #endif -#endif /* ZSTD_NODECOMPRESS */ +#endif /* ZSTD_NOCOMPRESS */ DISPLAYOUT( "\n"); DISPLAYOUT( "-- : All arguments after \"--\" are treated as files \n");