From ad954f0a64e47e2439a3352fc35b8c3d1553a1ab Mon Sep 17 00:00:00 2001 From: b84330808 Date: Wed, 4 Nov 2026 15:51:29 +0000 Subject: [PATCH] fileio: don't call FIO_highbit64(0) for an empty --patch-from source FIO_adjustParamsForPatchFromMode() computes the window log of the source with FIO_highbit64(maxSrcFileSize), which asserts v != 0. When the file to compress is empty, maxSrcFileSize is 0, so zstd --patch-from=ref empty aborts on the assertion. The CLI is built with assert() enabled by default, so this crashes the regular `zstd` binary. An empty source only needs the smallest window, so use ZSTD_WINDOWLOG_MIN in that case. This is the window log the clamp below already selected for any small source. Add a cli-test that compresses and decompresses an empty file with --patch-from. --- programs/fileio.c | 3 ++- tests/cli-tests/compression/patch-from.sh | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100755 tests/cli-tests/compression/patch-from.sh diff --git a/programs/fileio.c b/programs/fileio.c index 78a906d533b..1c965c7b367 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1363,7 +1363,8 @@ static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs, unsigned long long const maxSrcFileSize, int cLevel) { - unsigned const fileWindowLog = FIO_highbit64(maxSrcFileSize) + 1; + /* FIO_highbit64() requires v > 0 : an empty source only needs the smallest window */ + unsigned const fileWindowLog = maxSrcFileSize ? FIO_highbit64(maxSrcFileSize) + 1 : ZSTD_WINDOWLOG_MIN; ZSTD_compressionParameters const cParams = ZSTD_getCParams(cLevel, (size_t)maxSrcFileSize, (size_t)dictSize); FIO_adjustMemLimitForPatchFromMode(prefs, dictSize, maxSrcFileSize); if (fileWindowLog > ZSTD_WINDOWLOG_MAX) diff --git a/tests/cli-tests/compression/patch-from.sh b/tests/cli-tests/compression/patch-from.sh new file mode 100755 index 00000000000..074273dc749 --- /dev/null +++ b/tests/cli-tests/compression/patch-from.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +# Test --patch-from with an empty file to patch +datagen -g1000 -P50 > ref +touch empty +zstd --patch-from=ref empty -o empty.zst +zstd -d --patch-from=ref empty.zst -o empty.out +cmp empty empty.out