WEAVEParse/WEAVEStep trust wire indices — OOB read+writedog/WEAVE.c's codec is a zero-copy, entirely UNVALIDATED view over a 'W'
blob the header itself flags as "may be attacker-influenced", and the merge/next
decoders then dereference the parsed inserter/remover indices as raw array
subscripts. WEAVEStep reads a token's inserter straight from the 'I' column
(WEAVE.c:165) and remover ids from 'M' (:174-176) with NO bound against the
commit-table length; those indices flow into ordp[_ins]++ (ADV_IDH,
WEAVE.c:410) — a controllable OOB WRITE — and into commits[0][li] / rmap[li]
(wmerge_decode, :552,561,564) — OOB reads. Separately WEAVEParse aliases
byte-aligned TLV values as tok32c*/u64c* (:55-58) with no length-multiple or
alignment check, so a 'K'/'C' value of non-multiple length is read 1-3 bytes
past its end and mis-aligned loads are UB. The sibling HUNKu8sDrain already
does the right thing (validate tok32Offset, length, aligned copy) — this is the
precedent to mirror. Method: Issues.
WEAVE.c:410 #define ADV_IDH(INS) ... ordp[_ins]++ with
_ins = cur.inserter, ordp sized u64bDataLen(out_cmts)+1 (:402).wmerge_decode WEAVE.c:552 commits[0][li], :561/564
rmap[li]/rmap[*r] (both sized nc); li = tk.inserter, unchecked.WEAVEStep :165 u8sDrain32(c->ins,&out->inserter) and
:174-176 remover u32cs — never compared to $len(commits).WEAVEParse :55-58 casts v[0]→tok32c*/u64c*; loop
guard toks[0]>=toks[1] is a pointer compare, so a 3-byte 'K' still enters
WEAVEStep and reads a full 4-byte tok32. HUNK rejects via HUNKTOKLEN.weave_scope_alive :976, weave_emit_membership :1283) is safe
ONLY because it routes indices through bounds-checked u1At; decode bypasses it.WEAVEAlive (:117-132) slices text with UNCHECKED offsets: hi=tok32Offset(t)
(24-bit, ≤16 MiB) then a_part(u8c,seg,text,lo,hi-lo) with no hi<=$len(text)
and no monotonicity check (a_part's bound is an assert, gone in release).
WEAVEStep has these guards (:152,155); WEAVEAlive does not → OOB read of
hi) or a hi-lo underflow (hi<lo).< $len(commits),
'K' length a multiple of sizeof(tok32), 'C'/'A' a multiple of 8, and
$len(anc) == $len(toks); return WEAVEFAIL (never OK) on violation.hunk_drain_toks does; no raw dereference of a u8c*-derived tok32c*.'W' blob can NEVER produce an OOB access downstream.dog/ libdog, ABC style; error codes RON60, WEAVE-prefixed, 10 chars max.wmerge_decode :526-581, weave_emit_decode :936-966, the inline pass-1
loop in wnext_diff :350-364) into a single validated decoder so the index
check lives once, not thrice.fuzz/WEAVE.c (and property) case feeding malformed
'I'/'M'/'K'/'C' records straight into WEAVEParse→WEAVEMerge/Next;
existing fuzz only round-trips well-formed blobs.WEAVEStep/WEAVEParse (inserter/remover < ncommits);
add the same hi<=$len(text) + monotonic-offset guards to WEAVEAlive.anc==toks count; fix alignment.u64map :610-631 for
HASHx and fix its u64map_cap u32 overflow).WEAVEScope (:95-109) must reject an undersized into bitmap up front
instead of silently no-oping via u1sSet, and its ok64 return made real.79612854 — WEAVEStep unchecked inserter/removers WEAVE.c:163-176, ADV_IDH ordp[_ins]++ :410, WEAVEParse raw tok32c*/u64c* casts :56-58, WEAVEAlive unchecked hi :116-131. NOTHING landed (no DOG-008 in the log); a WIP fix sits UNLANDED in worktree ~/src/DOG-008 (WEAVE.c + test/WEAVE01,04 modified).