Skip to content

Path B partial: per-resource handle table routing complete; outer-boundary handle leak remains #107

@avrabe

Description

@avrabe

Tracked under #106 (Epic ADR-0).

Background

Three wit-bindgen runtime fixtures fail with wasm unreachable after meld fusion: resource_floats, resource_with_lists, resource-import-and-export. Root cause: rustc/LLVM assume(ptr.is_aligned()) debug-assert fires when leaf code dereferences the rep as a Box<T> pointer when the rep is actually a small handle integer.

Convergent diagnosis from prototype paths D + E:

  • meld-core/src/merger.rs:739 redirected ALL [resource-*] imports of any re-exporter through one shared ht_* regardless of which resource the import was for
  • meld-core/src/adapter/fact.rs:582 did the same per-component lookup for borrow handling

Path B (commits e027bb1 + c104b1b)

Rekeyed HandleTableInfo from HashMap<usize, _> to HashMap<(usize, String, String), _>. Per-resource discrimination throughout: redirect logic uses [export] prefix + resource_graph.resource_definer to determine the owner of each [resource-*] import; consumer-side imports (without [export] prefix) fall back to ANY component's handle table for the matching (iface, resource_name); \$N dedup suffix is stripped before lookup.

Status:

  • ✅ 73-test wit-bindgen suite: 0 regressions
  • ✅ Resource handle routing is now correctly per-resource
  • ✅ Original & 7 align trap eliminated (leaf no longer derefs handle as Box)
  • ❌ The trio still traps at runtime, but with a different error: unknown handle index 0x110004

Remaining bug

The trap value 0x110004 = table_base_addr + ENTRY_SIZE — the first entry in meld's per-resource handle table memory. wasmtime's canonical-ABI rejects it as an unknown handle.

Hypothesis: in the wit-bindgen-rust pattern, intermediate's exports.float resource is built around a Box<Float { inner_handle: leaf_imports_handle }>. Path B routes intermediate's [resource-new] to ht_new(box_ptr) which returns 0x110004. But when intermediate's Float.add() returns a NEW Float, the cabi-export shim chains through both layers — the outer ht_new and the inner canonical resource.new for leaf — and somewhere a memory-address handle ends up where wasmtime expects a canonical handle.

This is structurally similar to the opaque-rep drop bug from path I (https://github.com/pulseengine/wit-bindgen/tree/feat/opaque-rep-attribute): when wit-bindgen-rust uses Box::new(InnerHandle { ... }) as the rep, the outer handle and inner handle live at different layers, and the canonical-ABI machinery only knows about one.

Reproducer

```bash
git checkout feat/issue-92-shim-module
cargo run --release --bin meld -- fuse tests/wit_bindgen/fixtures/resource_floats.wasm -o /tmp/floats.wasm --component
wasm-tools validate /tmp/floats.wasm # passes
wasmtime --invoke='run()' /tmp/floats.wasm

Error: unknown handle index 1114116 (= 0x110004)

```

Two paths forward

  1. Wrap the boundary — insert a memory-address ↔ canonical-handle translation shim in `component_wrap.rs` so the fused module's per-resource handle table values get unwrapped to canonical handles at every cross-boundary point. Estimated: 100-200 LOC, deeper investigation needed to find every leak.
  2. Pivot to opaque-rep upstream — extend pulseengine/wit-bindgen feat/opaque-rep-attribute to support methods (constructor-only works today). Once upstream, re-exporter components opt out of the boxed-rep pattern and meld's per-resource routing covers the rest. Estimated: ~50-100 LOC in wit-bindgen `bindgen.rs` + new fixture.

Related

  • Commits: e027bb1, c104b1b
  • Branch: feat/issue-92-shim-module
  • wit-bindgen fork: pulseengine/wit-bindgen feat/opaque-rep-attribute (commit 236ef4bb)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions