From 17b198b0e7fe05391679447b9275a06a2fd0c450 Mon Sep 17 00:00:00 2001 From: b84330808 Date: Wed, 4 Nov 2026 16:01:13 +0000 Subject: [PATCH] decompress: return 0 from ZSTD_getDictID_fromFrame() for skippable frames Since a2ff6ea78 ("improve ZSTD_getFrameHeader on skippable frames"), ZSTD_getFrameHeader() stores the magic variant [0-15] of a skippable frame in its dictID field, as documented in zstd.h. ZSTD_getDictID_fromFrame() returns that field without looking at the frame type, so for a skippable frame written with a non-zero magic variant it now reports that a dictionary with ID 1-15 is required. It returned 0 before v1.5.7, and its documentation says it provides the dictID required to decompress the frame. A skippable frame requires no dictionary. Return 0 for skippable frames, and add a unit test that checks every magic variant. --- lib/decompress/zstd_decompress.c | 2 ++ tests/fuzzer.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 325f0b54dfc..59318f38d7f 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1645,6 +1645,8 @@ unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) ZSTD_FrameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 }; size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); if (ZSTD_isError(hError)) return 0; + /* for skippable frames, dictID holds the magic variant : no dictionary is required */ + if (zfp.frameType == ZSTD_skippableFrame) return 0; return zfp.dictID; } diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 32360b9a58d..e00621a74b9 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -2814,6 +2814,18 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + DISPLAYLEVEL(3, "test%3i : skippable frames don't require a dictionary : ", testNb++); + { unsigned magicVariant; + for (magicVariant = 0; magicVariant < 16; magicVariant++) { + size_t const skippableSize = ZSTD_writeSkippableFrame( + compressedBuffer, compressedBufferSize, + CNBuffer, 10, magicVariant); + CHECK_Z(skippableSize); + CHECK_EQ(0, ZSTD_getDictID_fromFrame(compressedBuffer, skippableSize)); + } + } + DISPLAYLEVEL(3, "OK \n"); + /* Dictionary and CCtx Duplication tests */ { ZSTD_CCtx* const ctxOrig = ZSTD_createCCtx(); ZSTD_CCtx* const ctxDuplicated = ZSTD_createCCtx();