fix(protocol): derive the xattr digest length from the hasher - #7786
Merged
Conversation
Upstream defines the constant, not a number: xattrs.c:48 sets MAX_XATTR_DIGEST_LEN to MD5_DIGEST_LEN, which lib/md-defines.h:12 fixes at 16. oc carried the 16 as a bare literal, so it could not track the hasher that compute_xattr_checksum actually runs. Derive it from the md-5 output size instead, add a const assertion pinning the derived value to upstream's 16 (the digest is a wire field, so a length change is a protocol break), and cover the drift with tests driven from the live hasher output rather than a second literal.
oferchen
enabled auto-merge (squash)
September 9, 2026 12:04
oferchen
added a commit
that referenced
this pull request
Sep 9, 2026
The measurement-gate note's "Three that look mirrored and are not" section landed as #7779 and went stale within a day: all three entries have since been fixed, and one of them cited a file that is being deleted. Each closure verified in the tree, not taken from a changelog: - hash table floor/growth -> #7790. `TAG_TABLE_SIZE` now exists at exactly one site (`crates/matching/src/index/mod.rs:68`) and its own doc says the growth role "belongs to CompactLookup", which grows on upstream's `(count/8) * 10 + 11` rule. The entry's second cited site, `optimized_search.rs:12`, is dropped: that module is dead and its removal is in flight, and the live constant was never the growth-bearing one. - `MAX_XATTR_DIGEST_LEN` literal -> #7786. Now `<Md5 as OutputSizeUser>::OutputSize::USIZE` with `const _: () = assert!(MAX_XATTR_DIGEST_LEN == 16)` beneath it (`crates/protocol/src/xattr/mod.rs:76,81`), so a digest change cannot silently move a wire length. - `MAX_INPUT_SIZE` copies -> #7787. One definition at `crates/checksums/src/simd_batch/mod.rs:46`; every backend imports it. The entry said nine copies; the sweep found twelve sites, eleven constants plus one bare literal no grep for the name could reach. The count is corrected rather than left flattering. The section is kept rather than deleted: the lesson it teaches (value equality is not provenance) is the reason the gate exists, and each fix is evidence the reading was right. The upstream anchors are unchanged except `match.c:86-88` -> `match.c:84-88`, matching the range the code itself cites for the same rule. Also drops the deleted module from the zsync design note's file list and corrects that entry's crate directory (`crates/match/` -> `crates/matching/`).
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.
MAX_XATTR_DIGEST_LENwas a bare16. Upstream does not write a numberthere:
xattrs.c:48defines it asMD5_DIGEST_LEN, andlib/md-defines.h:12sets that to 16. The value was right; the construction was fragile — the buffer
bound and the hasher that fills it had no relationship a compiler could check.
It is now derived from the hasher itself:
compute_xattr_checksumrunsMd5, so the buffer and the digest cannotdisagree by construction.
The distinction the derivation has to preserve
Upstream pins this to MD5's length specifically, not to
MAX_DIGEST_LEN(
lib/md-defines.h:13-21, up to SHA-512's 64).compat.c:835-836fixesxattr_sum_nnito the implied MD5 choice, above a comment reserving the rightto make the algorithm negotiable later. Deriving from "the longest digest oc can
produce" would have been a wire-format change, not a cleanup — the abbreviated
xattr digest is a wire field.
A
constassertion pins the value at 16 so the derivation cannot drift into aprotocol break, and
digest_len_is_upstream_md5_digest_len_not_max_digest_lenpins the distinction itself.
Tests
digest_len_tracks_the_hasher_that_fills_the_buffer— drives the expectedlength from a live
Md5::digest(DATUM).len()rather than restating16, soit fails if the constant is ever re-pointed at a different hasher.
digest_len_is_upstream_md5_digest_len_not_max_digest_len— encodes why 16and not 64.
Footprint
One file, +48/-2. No behaviour change: the value is identical before and after.