Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,57 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

## [0.40.0] - 2026-07-11

MCU-lowering release: `fuse --memory shared` is now **sound** for relocatable
inputs. This is the address-rebasing keystone that the v0.38.0 soundness gate
was holding the line for — single-address-space fusion no longer silently
corrupts memory (#326).

**What changed:** when meld places a component's linear memory at a non-zero
base in a shared address space, it now consumes that module's relocation
metadata (`linking` + `reloc.CODE`/`reloc.DATA`, as produced by `-C
link-arg=--emit-relocs`) and rebases every `R_WASM_MEMORY_ADDR_*` site — code
address literals and inline data pointers — by the module's base. A `--memory
shared` input that lacks the metadata and performs direct memory access now
hard-errors instead of emitting a colliding module. The input contract is
**relocatable**, not PIC: a Component-Model core may import only functions, so
`wasm-tools component new` rejects a PIC/dylink core (ADR-6).

**Falsification:** if the rebasing regressed, `test_326_reloc_const_rebasing_end_to_end`
(fuses two components and asserts, via wasmtime, that an absolute address
literal resolves to `base + addr` at runtime) would fail. If the hard-error gate
regressed, `test_326_shared_rebase_without_relocs_hard_errors` would fail. If the
legacy bulk-only dynamic rebasing regressed, `test_address_rebasing_end_to_end`
would fail.

### Added

- **Sound `fuse --memory shared` via relocation-metadata consumption (#326).**
New `reloc` module hand-parses `linking` v2 + `reloc.CODE`/`reloc.DATA` (the
wasmparser readers were dropped upstream). The rewriter rebases flagged
`i32.const`/`i64.const` address literals and inline data pointers through the
per-function offset map; consumed reloc sections are stripped from the output.
memarg-offset rebasing moved from blanket to reloc-driven, which also fixes a
latent over-rebasing of genuine struct-field offsets.

### Fixed

- **`fuse --memory shared` no longer silently corrupts memory (#326).** Absolute
addresses in a relocated component (heap/shadow-stack pointers, `static mut`
data, canonical-ABI buffer copies) are rebased into the shared window; the
runtime datapoints that motivated this (a `list<u8>` buffer reading wrong
bytes, a `static mut` store not persisting) are corrected for `--emit-relocs`
inputs.

### Known limitations

- A **no-reloc** module that references an absolute address purely as a *value*
(no load/store) still slips the hard-error gate (#339, Mythos Finding A — a
sound fix needs data-flow analysis). This does not affect the supported
`--emit-relocs` path. `memory64` shared inputs with 8-byte inline data
pointers are rejected rather than mis-rebased.

## [0.39.0] - 2026-07-11

Debug-info fidelity release: two independent correctness fixes to what the
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ exclude = [
]

[workspace.package]
version = "0.39.0"
version = "0.40.0"
authors = ["PulseEngine <https://github.com/pulseengine>"]
edition = "2024"
license = "Apache-2.0"
Expand Down
29 changes: 19 additions & 10 deletions safety/requirements/safety-requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,7 @@ artifacts:
the pending "inject addr + memory_base at every load/store" idea in SR-37's
history — that is unsound (it cannot distinguish pointers from integers,
nor same-module from cross-module pointers).
status: proposed
status: verified
tags: [memory-strategy, shared-memory, relocation, mcu, v0.40.0]
links:
- type: derives-from
Expand All @@ -1683,18 +1683,27 @@ artifacts:
release: v0.40.0
fields:
implementation:
- meld-core/src/reloc.rs
- meld-core/src/rewriter.rs
- meld-core/src/segments.rs
- meld-core/src/merger.rs
verification-method: test
verification-description: >
PLANNED (prototype on feat/326-reloc-consumer). Oracle fixtures from the
/tmp/spike326 spike reproduce both gale datapoints under a fused shared
memory: `reloc_326_static_addr_rebased_shared` (a `static mut` store at
an absolute `i32.const` persists across calls after rebasing — datapoint
B) and `reloc_326_data_pointer_rebased_shared` (a computed-pointer copy
preserves content — datapoint A). Negative control: a `--memory shared`
input WITHOUT `reloc.*` metadata hard-errors rather than emitting a
colliding module. Done when both oracles pass, the control errors, and
the fused output carries no stale `reloc.*` sections.
VERIFIED (#340, merged 2026-07-11). Runtime oracle
`test_326_reloc_const_rebasing_end_to_end`
(meld-core/tests/rebasing_end_to_end.rs): fuses two components into a
shared memory and, via wasmtime, asserts an absolute `i32.const` address
literal is rebased to `base + addr` (the datapoint-B `static mut` class).
Path-F negative control `test_326_shared_rebase_without_relocs_hard_errors`:
a `--memory shared` input with direct memory access and no `reloc.*`
hard-errors (`Error::MissingRelocMetadata`) instead of emitting a
colliding module. `reloc.rs` unit tests parse `linking`+`reloc.CODE`,
confirm the metadata survives `wasm-tools component new`, and
`unhandled_data_addr_relocs_flags_non_i32_pointers` gates out memory64
8-byte data pointers (Mythos Finding B). Existing
`test_address_rebasing_end_to_end` (bulk-only dynamic rebasing) stays
green. 457 lib + 4 integration tests pass; Mythos discover pass done.
KNOWN LIMITATION (#339, Mythos Finding A): a no-reloc module that leaks an
absolute address purely as a value (no load/store) still slips the
hard-error gate; does not affect the supported `--emit-relocs` path.

Loading