ZINFInflate wraps output on fill, never signals NOROOM
ZINFInflate (dog/git/ZINF.c) mishandles a too-small into slice: when avail_out hits 0 it WRAPS next_out back to into[0] and keeps inflating (corrupting already-produced bytes), then the trailing u8sFed(into, total_out) — all-or-nothing — no-ops because total_out exceeds capacity, so the head never advances and the call returns OK with produced 0. A genuine empty result also yields 0, so overflow is undetectable by the caller. Surfaced by JS-035 (zip.inflate grow-and-retry), which had to add an XOR head-sentinel hack to guess at overflow. Method: Issues.
avail_out == 0 reset block, dog/git/ZINF.c:31-34, inside the inflate loop (lines 27-35); resets next_out/avail_out instead of erroring.into to the object's known uncompressed length (keeper/UNPK.c:336,618, dog/git/PACK.c:177), so the wrap is LATENT there; it only bites a caller that doesn't know the size up front.js/zip.cpp works around it with a head sentinel (into[0][0] ^= 0xa5, re-checked after the call) — that hack is deletable once this lands.PACKInflate (dog/git/PACK.c:171-182) never cross-checks total_out == size, and UNPK.c:618 CONSUMES the inflated delta bytes. Related: GIT-025 (PACKRecordEnd's measure-by-inflate needs the fix).into holds, return a NOROOM-style error (new ZINFROOM) so the caller can grow and retry — never wrap or corrupt.OK, total_out equals the bytes actually present in into; the success path stays byte-identical for the pre-sized native callers.dog/git libdog, ABC style; new code RON60-encoded, ZINF-prefixed (abc/ok64), declared in ZINF.h beside ZINFFAIL/ZINFINIT/ZINFTOOBIG.OK).inflate returns Z_OK with avail_out == 0 (stream not ended, no room left) → inflateEnd(&zs); return ZINFROOM;.u8csUsed/u8sFed only on the Z_STREAM_END success path.keeper/test/ZINF.c case inflating a known stream into an undersized into expects ZINFROOM (today: OK + produced 0 + corruption).ZINFROOM to ZINF.h; fix the loop in ZINF.c; ctest green across ZINF/PACK/UNPK (the pre-sized callers must stay green).PACKInflate: a lying size header (stream inflates past size) must surface as PACKBADOBJ (total_out == size check), not silent corruption.zip.cpp:46-55): drop the XOR hack, grow directly on a ZINFROOM throw.ZINF.c avail_out==0 reset) and ZINF.h declares no ZINFROOM.