fix: zero-length buffer panic and invalid empty-input compression - #2
Open
AskAlexSharov wants to merge 1 commit into
Open
fix: zero-length buffer panic and invalid empty-input compression#2AskAlexSharov wants to merge 1 commit into
AskAlexSharov wants to merge 1 commit into
Conversation
AskAlexSharov
force-pushed
the
fix/cgo-binding-bugs
branch
from
July 24, 2026 02:19
8d26829 to
20530c4
Compare
1. Zero-length dst buffer panicked instead of returning an error. The methods guarded only empty src, then unconditionally took &dst[0]. Calling any compress/decompress method with a zero-length dst therefore panicked with "index out of range" instead of the documented "output buffer too small" error. This was reachable through the public API — e.g. GzipDecompress(compressed, 0) builds a zero-length buffer via make([]byte, 0) and crashed the caller. Each method now returns an error for an empty dst. 2. Compressing empty input produced an invalid (empty) stream. The compress methods short-circuited empty src to (0, nil), so GzipCompress(nil) returned a zero-byte slice. Zero bytes is not a valid gzip/zlib/DEFLATE stream — a standard decoder (including compress/gzip) rejects it as truncated input. The methods now pass the empty input to libdeflate, which emits a valid empty stream (~20 bytes for gzip). A nil data pointer is used for empty src, since &src[0] would panic and libdeflate accepts NULL when the length is 0. Adds tests (edgecases_test.go) that decode our empty-input output with the standard library (gzip/zlib/flate) to prove the streams are conformant, and tests that the zero-length dst paths return errors rather than panicking.
AskAlexSharov
force-pushed
the
fix/cgo-binding-bugs
branch
from
July 24, 2026 02:32
20530c4 to
08486e9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two correctness bugs in the CGo bindings, each with a regression test.
Bug 1 — zero-length
dstpanics instead of returning an errorEvery compress/decompress method guarded only empty
src, then took&dst[0]unconditionally:So any call with a zero-length output buffer panicked with
index out of rangeinstead of the documented "output buffer too small" error. This is reachable through the public API —GzipDecompress(compressed, 0)allocatesmake([]byte, 0)and crashed the caller:Each method now returns an error for an empty
dst.Bug 2 — compressing empty input produced an invalid stream
The compress methods short-circuited empty input to
(0, nil), soGzipCompress(nil)returned a zero-byte slice. Zero bytes is not a valid gzip/zlib/DEFLATE stream — a standard decoder rejects it as truncated:The methods now pass empty input through to libdeflate, which emits a valid empty stream (~20 bytes for gzip). libdeflate handles this safely —
deflate_compress_nonespecial-casesin_nbytes == 0, andcrc32(0, NULL, 0)reads nothing — so a nil data pointer is passed for emptysrc(taking&src[0]would itself panic).Tests
TestEmpty{Gzip,Zlib,Deflate}IsValidStandardStream— compress empty input and decode it with the standard library (compress/gzip,compress/zlib,compress/flate) to prove the output is a conformant stream, not just round-trippable by this package.TestZeroLengthDstReturnsErrorNotPanic— the six methods andGzipDecompress(_, 0)return errors instead of panicking.All tests pass under
go test -race;gofmt,go vet, andgolangci-lintare clean.Scope
Based on
main. Theruntime.SetFinalizerwork onalex/compressor-finalizeris not included, so the finalizer-vs-KeepAlivepremature-free issue is intentionally out of scope here.