Skip to content

fix(fuse): gate the unsound shared+rebase auto path (#326)#329

Merged
avrabe merged 2 commits into
mainfrom
fix/326-gate-unsound-shared-rebase
Jul 10, 2026
Merged

fix(fuse): gate the unsound shared+rebase auto path (#326)#329
avrabe merged 2 commits into
mainfrom
fix/326-gate-unsound-shared-rebase

Conversation

@avrabe

@avrabe avrabe commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

Stops --memory auto from silently selecting shared-memory + address rebasing — the default path that silently corrupts memory across fused components (#326). auto now resolves to multi-memory (sound); explicit --memory shared --address-rebase remains an opt-in but warns loudly.

This is the "gate now" half of the agreed plan; correct runtime dynamic-address rebasing in rewriter.rs (Tier-5) is the follow-up "fix properly" step.

Root cause (confirmed in-code + reproduced)

convert_memarg (rewriter.rs) rebases only the static memarg offset (and bulk-memory ops); needs_rebase_locals fires only for Memory{Copy,Fill,Init}. So the dynamic address operand of ordinary i32.load/i32.store is never rebased. Real components address heap/shadow-stack via computed pointers ⇒ shared fusion silently overlaps their private memory — wrong result, no trap, no error. (--memory multi fuses the same input correctly.)

Change

  • resolve_auto_memory_strategy: the grow-free/≥2-memory branch now selects MultiMemory (was SharedMemory+rebase), with a log::warn! explaining the gate. LS-D-1: emit correct output or none, never plausible-but-wrong.
  • Explicit --memory shared --address-rebase: proceeds but emits a loud unsoundness warning.
  • Corrected docstrings/comments that claimed the shared path was "statically sound".

Tests

Scope / follow-ups

Refs #326.

🤖 Generated with Claude Code

`--memory auto` silently selected shared memory + address rebasing for
grow-free multi-memory inputs. That is UNSOUND (#326): `convert_memarg` only
rebases the static memarg offset (and bulk-memory ops); the dynamic address
operand of ordinary i32.load/i32.store is never rebased. Real components
address heap/shadow-stack via computed pointers, so shared fusion silently
overlaps their private memory — wrong results, no trap, no error. Confirmed in
`rewriter.rs` (convert_memarg; needs_rebase_locals gated to Memory{Copy,Fill,
Init}) and reproduced end-to-end.

Gate now (LS-D-1 — emit correct output or none, never plausible-but-wrong):
- `resolve_auto_memory_strategy` no longer selects shared+rebase; Auto always
  resolves to multi-memory (sound). A `log::warn!` explains the gate.
- Explicit `--memory shared --address-rebase` remains an opt-in but now warns
  loudly that it is unsound for computed-pointer access.
- Corrected the docstrings that claimed the shared path was "statically sound".

Tests:
- `auto_selects_shared_for_growfree_inputs` → `auto_gates_shared_for_growfree_
  inputs_326` (asserts multi + 2 separate memories = the correctness #326
  protects); `ls_m_7_auto_reprobes_after_add_component` re-probes via memory
  count (2 → 3) since both resolutions are now multi.
- `test_304_identity_direct_adapter_is_inlined` now requests `SharedMemory`
  explicitly — the #304 inlining feature runs on the shared path, which Auto no
  longer selects; adapter inlining is orthogonal to the memory-access
  unsoundness #326 gates.

Interim safety gate; correct runtime dynamic-address rebasing in rewriter.rs
(Tier-5) is the follow-up "fix properly" step. Safety docs (ADR-4,
loss-scenarios, safety-requirements) still describe the old auto→shared default
and should be reconciled in a traceability follow-up.

Refs #326.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

LS-N verification gate

58/58 approved LS entries verified

count
Passed (≥1 test, all green) 58
Failed (≥1 test failure) 0
Missing (no ls_*_NN_* test found) 0

Approved loss-scenarios.yaml entries are expected to have a
regression test named ls_<letter>_<num>_* (e.g. LS-A-11
ls_a_11_*). The gate runs each prefix via cargo test --lib --no-fail-fast and aggregates pass/fail/missing.

Failed LS entries

(none)

Missing regression tests

(none)

Updated automatically by tools/post_verification_comment.py.
Source of truth: safety/stpa/loss-scenarios.yaml.

@avrabe avrabe merged commit e325398 into main Jul 10, 2026
14 checks passed
@avrabe avrabe deleted the fix/326-gate-unsound-shared-rebase branch July 10, 2026 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant