PACKResolveOfs delta-apply bound uses half, not the target buffer's endThe OFS chain applier (dog/git/PACK.c:263-287) ping-pongs results between
the base scratch and the upper half of the delta scratch, but sizes the
apply gauge as {dst, dst, dst + half} (half = deltalen/2) for BOTH
targets. When dst == base[0] the true capacity is baselen. Latent
today: every caller sizes the two scratches equal, so half < baselen.
Found in the 2026-07-24 dog/git review. Method: work.
dog/git/PACK.c:278 — u8g apply_out = {dst, dst, dst + half}; inside
the bottom-up apply loop; dst alternates between delta[0]+half and
base[0] (PACK.c:283-285).keeper/KEEP.c:723-724, buf1/buf2 both KEEP_BUFSZ 1GB) and the fuzz
harness (dog/fuzz/PACKRESOLVE.c:24-27, 4MiB each) — the fuzzer can
never reach the overflow, so green fuzz proves nothing here.deltalen > 2*baselen gets a scratch
overflow — DELTApply's room check (DELT.c:32) tests the inflated
bound, so the guard itself is what's wrong.deltalen/2 even
though base holds baselen — with 1GB keeper buffers, an object
resolving via a delta fails NOROOM past 512MB while a raw record of
the same size resolves fine.dst
points into (base[0]+baselen vs delta[0]+deltalen).deltalen > 2*baselen and a chain whose
result exceeds baselen-vs-half (today: OOB write caught by ASAN or
a wrong NOROOM); plus a case proving (b)'s cap is lifted.dog/git libdog, ABC style; no allocation added (CLAUDE.md §5), the
scratch-split contract in PACK.h:145-152 stays caller-visible.dog/test/PACKRESOLVE.c + dog/fuzz/PACKRESOLVE.c stay green;
keeper keep_get_packed_rec byte-identical results.u8bAllocate), not BASS, so the
over-bound apply lands in an ASAN redzone instead of the next carve.dog/test/PACKRESOLVE.c (asymmetric scratch sizes).dobj.size > half
inflate guard (PACK.c:272) still refers to the delta lower half.__sanitizer symbol miss);
sanitizer + fuzz builds used clang, plain gcc build unaffected.//GIT-023 on base 06a2a21d
(orchestrator-verified, not landed). git/PACK.c apply gauge term
is the real end of the target scratch (dend = dst==base[0] ?
base+baselen : delta+deltalen); test/PACKRESOLVE.c +2 cases:
narrow_base (defect a — ASAN heap-overflow before, NOROOM after)
and half_cap (defect b — spurious NOROOM before, resolves after).
ctest 76/76 green in plain gcc AND clang ASAN builds; fuzzer 66M
runs / 61s clean.GIT-023: apply gauge bounds by the target buffer