Skip to content

test(dissolve): lock cabi-arena-realloc → __cabi_arena_realloc linkability (#418) - #420

Merged
avrabe merged 1 commit into
mainfrom
test/cabi-arena-realloc-linkability-418
Jun 22, 2026
Merged

test(dissolve): lock cabi-arena-realloc → __cabi_arena_realloc linkability (#418)#420
avrabe merged 1 commit into
mainfrom
test/cabi-arena-realloc-linkability-418

Conversation

@avrabe

@avrabe avrabe commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What

Verifies — and regression-locks — the synth-layer mechanism for #418 (the BYO-OS lean-MCU dissolve, gale#89). An env::__cabi_arena_realloc import lowers, on the --relocatable host-link path (#197), to a R_ARM_THM_CALL relocation against an UNDEFINED __cabi_arena_realloc symbol — which the native link binds to the TCB's arena allocator.

Layering: synth references the symbol; the TCB provides it; the linker binds it. synth never implements the allocator or the canonical-ABI realloc contract.

This was a read-only triage claim before; now confirmed empirically (the .o carries *UND* __cabi_arena_realloc + the call-site relocation) and locked by a test. synth sees the verbatim core field name — the kebab cabi-arena-realloc is component-surface and never reaches synth, so no naming transform on our side.

Frozen-safe

New test (synth-cli, object .o parse) + a minimal wat fixture; zero codegen; control_step verified unchanged (113 instrs); rivet non-xref 0.

The full end-to-end check on gale's real dissolved component lands when that fixture arrives (requested on #418).

Refs: #418, gale#89, meld#301, synth#197.

🤖 Generated with Claude Code

…ility (#418)

Verifies the synth-layer mechanism for the BYO-OS lean-MCU dissolve (gale#89):
an `env::__cabi_arena_realloc` import (the grow-free `cabi_realloc` extern) lowers,
on the `--relocatable` host-link path (#197), to a `R_ARM_THM_CALL` relocation
against an UNDEFINED `__cabi_arena_realloc` symbol — which the native link binds
to the TCB's arena allocator. synth references the symbol; the TCB provides it;
the linker binds it (synth never implements the allocator or the realloc contract).

Empirically confirmed (was a read-only triage claim before): the .o carries
`*UND* __cabi_arena_realloc` + the relocation at the call site. synth sees the
verbatim core field name — the kebab `cabi-arena-realloc` is component-surface,
never reaching synth — so no naming transform on our side.

Frozen-safe: new test (synth-cli, object .o parse) + a minimal wat fixture, zero
codegen; control_step verified unchanged (113 instrs); rivet non-xref 0. The full
end-to-end check on gale's real dissolved component lands when that fixture
arrives (requested on #418).

Trace: skip

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@avrabe
avrabe merged commit be3de44 into main Jun 22, 2026
14 checks passed
@avrabe
avrabe deleted the test/cabi-arena-realloc-linkability-418 branch June 22, 2026 10:14
avrabe added a commit that referenced this pull request Jul 17, 2026
…arena-realloc importers, decline matrix + CI oracle

CLI: on the self-contained Cortex-M --all-exports path (ARM backend, not
--relocatable, not --native-pointer-abi), a sole env::__cabi_arena_realloc
import is bound via the synth-core arena-bind rewrite — the compile yields a
fully self-contained ET_EXEC image (previously: ET_REL 'link me with the Kiln
bridge', the embedder seam). Pinned opt-out: --no-bind-cabi-arena.

Untouched seams (asserted): --relocatable keeps the #420 TCB layering
(undefined symbol, host-link-bound); modules with OTHER imports keep the
host seam entirely (never a half-bound hybrid); modules without the import
pass through byte-identically.

Gates:
- scripts/repro/cabi_arena_bind_418_differential.py now GREEN (was red-first):
  unicorn runs the image's own startup then each export; wasmtime satisfies
  the import with a host arena at a DIFFERENT base — all six
  pointer-independent cases match, exhaustion traps on both sides. CI job
  arena-bind-418-oracle.
- cabi_arena_bind_418.rs: ET_EXEC + no undefined arena symbol + binding log;
  opt-out/relocatable restore the external seam; wrong signature declines
  loudly; mixed imports keep ET_REL.
- Harness anti-vacuity: startup must reach the first compiled function AND
  leave R11 = __linear_memory_base (a min()-over-symbols bug initially ran
  nothing and greened 4/6 cases on a zeroed machine — caught and locked).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
avrabe added a commit that referenced this pull request Jul 17, 2026
…ssolve — synthesized in-module arena allocator (#799)

* test(#418): red-first execution differential — self-contained arena-import dissolve vs wasmtime host arena

The fixture is the wit-bindgen cabi-realloc-extern / meld-dissolve shape
(exported cabi_realloc routing to env::__cabi_arena_realloc, Rust/wasm-ld
layout globals). The gate asserts the default self-contained compile yields
ET_EXEC and every export matches wasmtime ground truth where the import is
satisfied by a host arena implementing the #418 contract (0/0 -> align, bump,
copy-on-grow, bounded + trap on exhaustion). Host arena uses a DIFFERENT base
than synth will, so only pointer-independent semantics can green.

RED today: the arena import degrades the compile to an ET_REL link-me object
(the embedder seam) — script exits at the ET_EXEC assert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L

* feat(#418): arena-bind rewrite — replace the sole env::__cabi_arena_realloc import with a synthesized in-module allocator

A wasm->wasm transform in synth-core: when env::__cabi_arena_realloc is the
module's ONLY import, remove it and prepend a DEFINED allocator function
implementing the #418 contract ((i32x4)->i32; old_len==0&&new_len==0 -> align;
bump allocation from an appended cursor global; copy-on-realloc of
min(old,new) bytes; bounded [arena_base, linmem_end) — traps on exhaustion,
never memory.grow). Imports-first index space + sole-import removal +
prepend = every call/export/elem index PRESERVED, no remapping; untouched
sections are byte-copied verbatim (count-patch only on function/global/code).

arena_base mirrors the shipped used-extent rule: max(data_end, i32-const
global inits <= linmem) — covering __stack_pointer / __heap_base /
__data_end — floor 16, 16-aligned. Loud declines: wrong signature, no/64-bit
memory, non-const data offsets, no defined functions, no arena room. Other
imports present -> NotApplicable pass-through (the module keeps the
host-linked seam). Result is Validator-checked before use.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L

* feat(#418): wire the arena binding — self-contained dissolve of cabi-arena-realloc importers, decline matrix + CI oracle

CLI: on the self-contained Cortex-M --all-exports path (ARM backend, not
--relocatable, not --native-pointer-abi), a sole env::__cabi_arena_realloc
import is bound via the synth-core arena-bind rewrite — the compile yields a
fully self-contained ET_EXEC image (previously: ET_REL 'link me with the Kiln
bridge', the embedder seam). Pinned opt-out: --no-bind-cabi-arena.

Untouched seams (asserted): --relocatable keeps the #420 TCB layering
(undefined symbol, host-link-bound); modules with OTHER imports keep the
host seam entirely (never a half-bound hybrid); modules without the import
pass through byte-identically.

Gates:
- scripts/repro/cabi_arena_bind_418_differential.py now GREEN (was red-first):
  unicorn runs the image's own startup then each export; wasmtime satisfies
  the import with a host arena at a DIFFERENT base — all six
  pointer-independent cases match, exhaustion traps on both sides. CI job
  arena-bind-418-oracle.
- cabi_arena_bind_418.rs: ET_EXEC + no undefined arena symbol + binding log;
  opt-out/relocatable restore the external seam; wrong signature declines
  loudly; mixed imports keep ET_REL.
- Harness anti-vacuity: startup must reach the first compiled function AND
  leave R11 = __linear_memory_base (a min()-over-symbols bug initially ran
  nothing and greened 4/6 cases on a zeroed machine — caught and locked).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L

* chore: drop stray __pycache__ artifact + ignore it

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>
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