Skip to content

Commit ccf6672

Browse files
avrabeclaude
andauthored
chore(release): v0.40.0 — sound --memory shared via reloc-driven rebasing (#342)
Cut v0.40.0 (0.39.0 → 0.40.0). Scope: #326 reloc-consumer (merged #340) — the address-rebasing keystone that makes single-address-space MCU fusion sound. SR-48 proposed → verified: runtime oracle test_326_reloc_const_rebasing_end_to_end (address rebased to base+addr via wasmtime), path-F control test_326_shared_rebase_without_relocs_hard_errors, reloc.rs parser/Finding-B tests; 457 lib + 4 integration green; Mythos discover pass done. Known limitation #339 (Mythos Finding A, no-reloc value-as-pointer) documented. `rivet release status v0.40.0` → Cuttable (SR-48 verified). `rivet validate` PASS. CHANGELOG [0.40.0] with falsification + known-limitations. Refs #326, #339, ADR-6, SR-48, LS-M-11. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8e7558a commit ccf6672

4 files changed

Lines changed: 73 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,57 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
## [0.40.0] - 2026-07-11
8+
9+
MCU-lowering release: `fuse --memory shared` is now **sound** for relocatable
10+
inputs. This is the address-rebasing keystone that the v0.38.0 soundness gate
11+
was holding the line for — single-address-space fusion no longer silently
12+
corrupts memory (#326).
13+
14+
**What changed:** when meld places a component's linear memory at a non-zero
15+
base in a shared address space, it now consumes that module's relocation
16+
metadata (`linking` + `reloc.CODE`/`reloc.DATA`, as produced by `-C
17+
link-arg=--emit-relocs`) and rebases every `R_WASM_MEMORY_ADDR_*` site — code
18+
address literals and inline data pointers — by the module's base. A `--memory
19+
shared` input that lacks the metadata and performs direct memory access now
20+
hard-errors instead of emitting a colliding module. The input contract is
21+
**relocatable**, not PIC: a Component-Model core may import only functions, so
22+
`wasm-tools component new` rejects a PIC/dylink core (ADR-6).
23+
24+
**Falsification:** if the rebasing regressed, `test_326_reloc_const_rebasing_end_to_end`
25+
(fuses two components and asserts, via wasmtime, that an absolute address
26+
literal resolves to `base + addr` at runtime) would fail. If the hard-error gate
27+
regressed, `test_326_shared_rebase_without_relocs_hard_errors` would fail. If the
28+
legacy bulk-only dynamic rebasing regressed, `test_address_rebasing_end_to_end`
29+
would fail.
30+
31+
### Added
32+
33+
- **Sound `fuse --memory shared` via relocation-metadata consumption (#326).**
34+
New `reloc` module hand-parses `linking` v2 + `reloc.CODE`/`reloc.DATA` (the
35+
wasmparser readers were dropped upstream). The rewriter rebases flagged
36+
`i32.const`/`i64.const` address literals and inline data pointers through the
37+
per-function offset map; consumed reloc sections are stripped from the output.
38+
memarg-offset rebasing moved from blanket to reloc-driven, which also fixes a
39+
latent over-rebasing of genuine struct-field offsets.
40+
41+
### Fixed
42+
43+
- **`fuse --memory shared` no longer silently corrupts memory (#326).** Absolute
44+
addresses in a relocated component (heap/shadow-stack pointers, `static mut`
45+
data, canonical-ABI buffer copies) are rebased into the shared window; the
46+
runtime datapoints that motivated this (a `list<u8>` buffer reading wrong
47+
bytes, a `static mut` store not persisting) are corrected for `--emit-relocs`
48+
inputs.
49+
50+
### Known limitations
51+
52+
- A **no-reloc** module that references an absolute address purely as a *value*
53+
(no load/store) still slips the hard-error gate (#339, Mythos Finding A — a
54+
sound fix needs data-flow analysis). This does not affect the supported
55+
`--emit-relocs` path. `memory64` shared inputs with 8-byte inline data
56+
pointers are rejected rather than mis-rebased.
57+
758
## [0.39.0] - 2026-07-11
859

960
Debug-info fidelity release: two independent correctness fixes to what the

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ exclude = [
1010
]
1111

1212
[workspace.package]
13-
version = "0.39.0"
13+
version = "0.40.0"
1414
authors = ["PulseEngine <https://github.com/pulseengine>"]
1515
edition = "2024"
1616
license = "Apache-2.0"

safety/requirements/safety-requirements.yaml

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ artifacts:
16691669
the pending "inject addr + memory_base at every load/store" idea in SR-37's
16701670
history — that is unsound (it cannot distinguish pointers from integers,
16711671
nor same-module from cross-module pointers).
1672-
status: proposed
1672+
status: verified
16731673
tags: [memory-strategy, shared-memory, relocation, mcu, v0.40.0]
16741674
links:
16751675
- type: derives-from
@@ -1683,18 +1683,27 @@ artifacts:
16831683
release: v0.40.0
16841684
fields:
16851685
implementation:
1686+
- meld-core/src/reloc.rs
16861687
- meld-core/src/rewriter.rs
16871688
- meld-core/src/segments.rs
16881689
- meld-core/src/merger.rs
16891690
verification-method: test
16901691
verification-description: >
1691-
PLANNED (prototype on feat/326-reloc-consumer). Oracle fixtures from the
1692-
/tmp/spike326 spike reproduce both gale datapoints under a fused shared
1693-
memory: `reloc_326_static_addr_rebased_shared` (a `static mut` store at
1694-
an absolute `i32.const` persists across calls after rebasing — datapoint
1695-
B) and `reloc_326_data_pointer_rebased_shared` (a computed-pointer copy
1696-
preserves content — datapoint A). Negative control: a `--memory shared`
1697-
input WITHOUT `reloc.*` metadata hard-errors rather than emitting a
1698-
colliding module. Done when both oracles pass, the control errors, and
1699-
the fused output carries no stale `reloc.*` sections.
1692+
VERIFIED (#340, merged 2026-07-11). Runtime oracle
1693+
`test_326_reloc_const_rebasing_end_to_end`
1694+
(meld-core/tests/rebasing_end_to_end.rs): fuses two components into a
1695+
shared memory and, via wasmtime, asserts an absolute `i32.const` address
1696+
literal is rebased to `base + addr` (the datapoint-B `static mut` class).
1697+
Path-F negative control `test_326_shared_rebase_without_relocs_hard_errors`:
1698+
a `--memory shared` input with direct memory access and no `reloc.*`
1699+
hard-errors (`Error::MissingRelocMetadata`) instead of emitting a
1700+
colliding module. `reloc.rs` unit tests parse `linking`+`reloc.CODE`,
1701+
confirm the metadata survives `wasm-tools component new`, and
1702+
`unhandled_data_addr_relocs_flags_non_i32_pointers` gates out memory64
1703+
8-byte data pointers (Mythos Finding B). Existing
1704+
`test_address_rebasing_end_to_end` (bulk-only dynamic rebasing) stays
1705+
green. 457 lib + 4 integration tests pass; Mythos discover pass done.
1706+
KNOWN LIMITATION (#339, Mythos Finding A): a no-reloc module that leaks an
1707+
absolute address purely as a value (no load/store) still slips the
1708+
hard-error gate; does not affect the supported `--emit-relocs` path.
17001709

0 commit comments

Comments
 (0)