Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/storage-git-gix/parked-gix/.nornir/upstream-gix-base-size.md

Upstream report, ready to file: gix accepts a delta with a wrong base size

FILED 2026-08-03: https://github.com/GitoxideLabs/gitoxide/issues/2868 (as Ignalina).

Originally blocked because both GitHub tokens on oden were expired on 2026-08-03 (gh auth status: Ignalina invalid, rickard-lundin invalid). File under the Ignalina account.

Reproduction already in-tree: crates/gunnar-delta/tests/gix_base_size_blind.rs. That test asserts gitoxide is wrong, so it goes red the day gitoxide is right — delete it then rather than loosening it, and withdraw this report instead if it turns out to be git's verdict that changed.


Title

decode_entry does not validate a delta's stated base size, accepting packs git index-pack --strict rejects

Body

A delta instruction stream is prefixed by two varints: the size of the base it applies to, and the size of the result. gix reads the base-size varint and never compares it against the base it was actually handed, so a pack whose base size disagrees with its base decodes without complaint.

Rewriting only that varint — same width, so not a byte of the instruction stream moves — gives a pack where:

Perfect reconstruction is the point, and it is why this is worth fixing rather than shrugging at. The check does not exist to catch a bad delta applied correctly. It exists to catch a good delta applied to the wrong object — a mis-resolved REF_DELTA, a wrong OFS_DELTA back-offset. The stated base size is the cheapest cross-check that the base you resolved is the base the encoder meant, and it is one comparison against a value already parsed.

With the check absent, a resolution error survives the whole decode path. The first thing that notices is the object id, and only if something recomputes it.

Found while building a delta encoder against gix's decoder: a deliberately corrupted base-size varint was expected to fail the round trip and did not. Only a git index-pack subprocess caught it, which meant the cheap in-process check was blind and the expensive out-of-process one was load-bearing.

Suggested fix

In decode_entry, after parsing the base-size varint, compare it against the length of the resolved base and error if they differ. One comparison, no new parsing.

Environment