feat(#406): multi-memory phase 1 — N wasm memories to N distinct native base regions (VCR-MEM-002) - #749
Merged
Merged
Conversation
… here) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… phase 1 - compile_all_exports threads extra_memory_data_segments + multi_memory_decline from the decoder; module-level LOUD gates (decode decline reason, non-ARM backend, self-contained/!--relocatable, --native-pointer-abi, --shadow-stack-size) fire before any op is selected. - CompileConfig.memory_pages populated from the declared memories (indexed by memory index; memory-0 lowering never reads it). - build_relocatable_elf: one reservation section per non-default memory (.synth.wasm_mem_<k>, PROGBITS with placed init segments / NOBITS when pure zero-init) + a __synth_wasm_data_<k> base symbol, with segment-bounds and orphan-segment refusals. Single-memory modules pass empty lists — output byte-identical (frozen gate 10/10 green). VCR-MEM-002 phase 1, #406/#242. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…nct unicorn bases vs wasmtime 29 cases green on the branch (store-both aliasing discriminators, memory-1 init-data peeks, sub-word round-trips, per-memory size/grow); RED on origin/main (exit 1: the object lacks .synth.wasm_mem_1 — the pre-#406 silent-aliasing object has no per-memory region/symbol). Structural pins: __synth_wasm_data_1 DEFINED, .synth.wasm_mem_1 PROGBITS == 3 pages with the init segment placed, every ABS32 reloc in-range, and at least one memory-1 reloc (an object with none is the aliasing bug). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
GREEN: 2- and 3-memory ARM --relocatable objects (per-memory NOBITS/PROGBITS regions, defined __synth_wasm_data_<k>, init bytes placed, no _0 alias). REFUSED loudly: no --relocatable, self-contained --cortex-m, --native-pointer-abi, --shadow-stack-size, riscv, aarch64, cross-memory memory.copy, non-default memory.fill, i64 access on memory k, non-const segment offset, overflowing segment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
force-pushed
the
feat/43-multi-memory-ph1
branch
from
July 15, 2026 10:54
85bad1c to
dad0261
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
avrabe
added a commit
that referenced
this pull request
Jul 30, 2026
…CLOSED Cold review found the v0.53 assembly was about to ship the SAME defect class as v0.51 and v0.52, with a new twist: the ledger was defending it. F1 (BLOCK) — the FEATURE_MATRIX "Honest Summary" cited #881, #882 and #872 as open residuals. All three were CLOSED by lanes in THIS release. Root cause is a lane-ordering race: L6's doc-honesty commit landed 2026-07-29 15:28 and said "honest-summary residual examples now cite the actually-open issues (#881/#882/#872)" -- true when written; L1 closed #881 fourteen hours later. The doc-honesty lane ran FIRST and nobody re-swept after the fixes landed. The document had become self-contradictory: the summary said RV32 br_table still declines while the backend row three sections up said it lowers. Re-pointed at genuinely-open issues (#890, #851, #846), verified against `gh issue view`. F2 (BLOCK) — claims.yaml PINNED the stale "#881" verbatim, so `claim_check` reported 34/34 while green-confirming a false residual, and correcting the prose would have turned the gate RED. CLAUDE.md says never fix a red gate by loosening the ledger; this was the inverse -- a ledger entry that had gone false, so the gate protected the defect instead of catching it. The fix is structural, not a re-point: an ISSUE-NUMBER pin goes stale the moment the issue is fixed, because `verbatim` only asserts the phrase is PRESENT. This pin has now been wrong twice for exactly that reason (#782, then #881). It now pins the CAPABILITY GAP -- "single-precision FPUs", the i64-from-f32 decline that genuinely remains -- which becomes false precisely when the gap closes. Red-first verified: replacing the phrase reddens SYNTH-F32-F64-VFP (exit 1), restoring it returns green. F3 -- three of seven lanes had NO changelog entry, including L4/#872: a default-on soundness fix that MOVED SHIPPED BYTES (gust_poll 692->696, fact-spec 132->140). A user diffing v0.52->v0.53 output would have found no explanation. Added L1 (#885), L4 (#888) and L7 (#889) entries, and collapsed a duplicate `### Added` section that violated the Keep-a-Changelog structure the release process mandates. F4 -- README declared "No multi-memory" while the matrix (corrected this release) says P with a CI-wired differential. Multi-memory phase 1 shipped in v0.43 (#749); the README line was ~10 releases stale, so v0.53 would have shipped two documents disagreeing about a capability. F5 -- the #880 changelog entry claimed every pinned phrase is bound to its oracle AND that oracle's CI wiring. SYNTH-MATRIX-WCET-COMPOSITION has neither -- the sound-WCET-bound row, one of the most safety-load-bearing claims in the matrix, is the single exception. Named it rather than softening it away. F6 -- #872's real remaining hole (a mid-segment `Pop {…,PC}` the segment-local validator misses) and VCR-DEC-001's (a wrong-return-register rewrite accepted by `validate_cfg_rewrite` AND VCR-RA-003 both, caught only by execution) existed only in Rust doc-comments. Both now stated in the matrix and CHANGELOG: the release was simultaneously OVERSTATING what is open and OMITTING what is. claim_check 34/34, docs regenerated, render byte-fresh. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe
added a commit
that referenced
this pull request
Jul 30, 2026
* chore(release): v0.53.0 — "The last mile" (7 lanes) Version sweep: workspace + all 13 intra-workspace path-dep pins + MODULE.bazel + status.json, Cargo.lock refreshed to 0.53.0 (v0.52's cold review caught a stale lock; no CI job builds --locked, so this one is on the release process). Docs regenerated once at assembly per #805 -- lanes do not hand-edit generated artifacts. claim_check 34/34, check_version_pins OK. CHANGELOG headline added by the coordinator over the 8 lane-written entries. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L * fix(release): cold-review blockers — stop citing issues this release CLOSED Cold review found the v0.53 assembly was about to ship the SAME defect class as v0.51 and v0.52, with a new twist: the ledger was defending it. F1 (BLOCK) — the FEATURE_MATRIX "Honest Summary" cited #881, #882 and #872 as open residuals. All three were CLOSED by lanes in THIS release. Root cause is a lane-ordering race: L6's doc-honesty commit landed 2026-07-29 15:28 and said "honest-summary residual examples now cite the actually-open issues (#881/#882/#872)" -- true when written; L1 closed #881 fourteen hours later. The doc-honesty lane ran FIRST and nobody re-swept after the fixes landed. The document had become self-contradictory: the summary said RV32 br_table still declines while the backend row three sections up said it lowers. Re-pointed at genuinely-open issues (#890, #851, #846), verified against `gh issue view`. F2 (BLOCK) — claims.yaml PINNED the stale "#881" verbatim, so `claim_check` reported 34/34 while green-confirming a false residual, and correcting the prose would have turned the gate RED. CLAUDE.md says never fix a red gate by loosening the ledger; this was the inverse -- a ledger entry that had gone false, so the gate protected the defect instead of catching it. The fix is structural, not a re-point: an ISSUE-NUMBER pin goes stale the moment the issue is fixed, because `verbatim` only asserts the phrase is PRESENT. This pin has now been wrong twice for exactly that reason (#782, then #881). It now pins the CAPABILITY GAP -- "single-precision FPUs", the i64-from-f32 decline that genuinely remains -- which becomes false precisely when the gap closes. Red-first verified: replacing the phrase reddens SYNTH-F32-F64-VFP (exit 1), restoring it returns green. F3 -- three of seven lanes had NO changelog entry, including L4/#872: a default-on soundness fix that MOVED SHIPPED BYTES (gust_poll 692->696, fact-spec 132->140). A user diffing v0.52->v0.53 output would have found no explanation. Added L1 (#885), L4 (#888) and L7 (#889) entries, and collapsed a duplicate `### Added` section that violated the Keep-a-Changelog structure the release process mandates. F4 -- README declared "No multi-memory" while the matrix (corrected this release) says P with a CI-wired differential. Multi-memory phase 1 shipped in v0.43 (#749); the README line was ~10 releases stale, so v0.53 would have shipped two documents disagreeing about a capability. F5 -- the #880 changelog entry claimed every pinned phrase is bound to its oracle AND that oracle's CI wiring. SYNTH-MATRIX-WCET-COMPOSITION has neither -- the sound-WCET-bound row, one of the most safety-load-bearing claims in the matrix, is the single exception. Named it rather than softening it away. F6 -- #872's real remaining hole (a mid-segment `Pop {…,PC}` the segment-local validator misses) and VCR-DEC-001's (a wrong-return-register rewrite accepted by `validate_cfg_rewrite` AND VCR-RA-003 both, caught only by execution) existed only in Rust doc-comments. Both now stated in the matrix and CHANGELOG: the release was simultaneously OVERSTATING what is open and OMITTING what is. claim_check 34/34, docs regenerated, render byte-fresh. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L --------- Co-authored-by: Claude <noreply@anthropic.com>
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.
VCR-MEM-002 phase 1 (#406, epic #242): N wasm memories → N distinct native base regions
The meld#300 multi-memory structural-isolation model needs synth to stop dropping the memarg memory index. Pre-#406, every load/store lowered onto the ONE R11 base — a store to memory 1 silently clobbered memory 0, memory k's init data was silently dropped, and
memory.size/growon memory k read memory 0's state.What ships
WasmOp::MultiMemory { memory, op }(memory-0 ops stay the bare variants — every existing match arm and frozen byte untouched by construction), with a mirror-pinnedmemarg_memory_indexhelper covering exactlyconvert_operator's memarg arms.--relocatable): memory 0 keeps the runtime R11 base (and__synth_wasm_dataunder the native-pointer ABI — frozen-safe); memory k > 0 is addressed via its own__synth_wasm_data_<k>symbol (R_ARM_ABS32 literal pool, the dissolved --relocatable objects carry full wasm linmem (64KB .data) + absolute MOVW relocs — MCU-unshippable + link-fragile (gale mutex silicon fault) #345 link-survivable form) defined at the base of a per-memory.synth.wasm_mem_<k>reservation section — PROGBITS with init segments placed (previously silently dropped), NOBITS when pure zero-init.memory.size/grow: memory 0 unchanged (R10); memory k's size is the declared constant (grow is always -1 on this backend, so initial == size), grow(k) validates the context then emits the fixed-memory -1.i32.load/store+ 8/16 sign/zero variants) on memory k. Wider/float accesses,--safety-boundson memory k, and cross-/non-defaultmemory.copy/filldecline loudly, typed and precise — never a silent alias.Capability matrix (all pinned by
crates/synth-cli/tests/multi_memory_406.rs, 13/13)--relocatable--relocatable--relocatable/ self-contained--cortex-m--native-pointer-abi--shadow-stack-sizememory.copy/ non-defaultmemory.fillDefense in depth:
select_defaultand the optimized path (optimizer_bridge) declineMultiMemory+ non-zeromemory.size/growexplicitly, so no path can fall back into aliasing.Evidence
scripts/repro/multi_memory_406_differential.py+mem406_multi_memory.wat— compiles--relocatable, maps the two memories at DISTINCT unicorn bases (0x200000 R11 / 0x400000 symbol-patched, far apart so residual aliasing faults rather than accidentally passing), 29/29 vs wasmtime multi-memory: store-both aliasing discriminators, memory-1 init-data peeks, sub-word round-trips, per-memory size/grow. Structural pins:__synth_wasm_data_1DEFINED,.synth.wasm_mem_1== 3 pages with segment placed, ≥1 memory-1 reloc, all in-range.memory_pages/the new ELF params are empty for every single-memory module by construction.wide_static_746_differential.pyuntouched and green in the four-crate sweep context (25/25 lives in its CI job); the memidx threading wraps at decode, upstream of the fix(#739): static ABOVE sp_init — relocate (never bake) + de-vacuate the in-range oracle #744/#739 residual: i64/wide static-region load not relocated under --shadow-stack-size (sub-word fixed in #744, wide arm declines) #746 static-region arms.-D warningsclean, synth-core/-synthesis/-backend/-cli suites 90/90 green.Refs #406, #242 (VCR-MEM-002 phase 1). Phase 2+ (self-contained MPU/PMP regions, cross-memory bulk ops, wide accesses) stays on the roadmap artifact.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L