Re: Fix detection of truncated zstd-compressed backups - Mailing list pgsql-hackers

From Chao Li
Subject Re: Fix detection of truncated zstd-compressed backups
Date
Msg-id 2E9971CA-062B-4EC0-8858-9979C73A3888@gmail.com
Whole thread
List pgsql-hackers

> On Aug 10, 2026, at 14:45, Chao Li <li.evan.chao@gmail.com> wrote:
>
>
> See attached 0002 for the fix of gzip streamer. I will check the lz4 streamer next.
>
> Best regards,
> --
> Chao Li (Evan)
> HighGo Software Co., Ltd.
> https://www.highgo.com/
>
>
>
>
>
<v2-0001-Fix-detection-of-truncated-zstd-compressed-backup.patch><v2-0002-Fix-detection-of-truncated-gzip-compressed-backup.patch>

Confirmed that lz4 also has the same problem. See the similar repro script:
```
workdir=$(mktemp -d /tmp/lz4-trunc.XXXXXX)
mkdir "$workdir/truncated"
dd if=/dev/zero of="$workdir/base.tar" bs=1024 count=2
lz4 -q -f "$workdir/base.tar" "$workdir/base.tar.lz4"
size=$(stat -f %z "$workdir/base.tar.lz4")
dd if="$workdir/base.tar.lz4" of="$workdir/truncated/base.tar.lz4" bs=1 count=$((size - 1))

manifest_prefix=$'{"PostgreSQL-Backup-Manifest-Version": 1,\n "Files": [],\n "WAL-Ranges": [],\n'
printf '%s' "$manifest_prefix" > "$workdir/manifest-prefix"
manifest_checksum=$(shasum -a 256 "$workdir/manifest-prefix" | awk '{print $1}')
printf '%s"Manifest-Checksum": "%s"}\n' "$manifest_prefix" "$manifest_checksum" > "$workdir/truncated/backup_manifest"

lz4 -t "$workdir/truncated/base.tar.lz4"
pg_verifybackup -F t -s "$workdir/truncated"
```

lz4 fails to decompress the truncated tar file, but pg_verifybackup succeeds.

The doc for LZ4F_decompress() [4] says that a return value >0 is a hint about how many source bytes are needed next, 0
meansthat the frame is complete, and an error return is identified with LZ4F_isError(). 

So, as in 0001, we can record the return value of LZ4F_decompress() in astreamer_lz4_frame and check it in
astreamer_lz4_decompressor_finalize().Unlike zstd, we don't need to call LZ4F_decompress() again because it has no
documentedcase where a positive return value with a full output buffer requires an empty-input call to flush internally
bufferedoutput. 

[4] https://github.com/lz4/lz4/blob/dev/lib/lz4frame.h#L470-L500

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/





Attachment

pgsql-hackers by date:

Previous
From: Fujii Masao
Date:
Subject: Re: Avoid calling SetMatViewPopulatedState if possible
Next
From: Daniel Gustafsson
Date:
Subject: Re: pg_control_checkpoint(): add "data_checksum_version" (Pg19)?