wit-bindgen-cpp generates invalid resource handles for variant/list<option> params, causing an 'unknown handle index' trap in wasmtime
Reproduction of a wit-bindgen-cpp handle-management defect where C++ components pass invalid resource handles across the component boundary, aborting execution in wasmtime with 'unknown handle index'.
Environment
| component |
version |
| OS |
macOS 15.7 (Darwin 24.6.0), x86_64 |
| wasmtime |
wasmtime 41.0.0 (3dda91692 2026-01-20) |
| jco |
1.16.1 (source checkout, tag jco-v1.16.1) |
| Node.js |
v22.22.2 |
| wac |
wac-cli 0.8.1 |
| wasi-sdk |
27.0 (wasm32-wasip2-clang/clang++) |
Steps to reproduce
The full chain is: compile the guest sources into a provider component and a consumer component, compose them with wac, then run the composed component. Prebuilt copies of every artifact are included (components/provider.wasm, components/consumer.wasm, composed.wasm), so you can also skip straight to step 5.
Github repo:https://github.com/xiaozzzZZzzz240/G004-wit-bindgen-cpp-emits-invalid-resource-handle-trapping-unknown-handle
-
Clone this repository:
git clone <THIS_REPO_URL>
cd <THIS_REPO_DIR>
-
Compile the provider component from the JavaScript sources in src/provider-JavaScript/ (toolchain versions in the table above; the WIT package is in wit/):
jco componentize src/provider-JavaScript/world2-sbtyzmep_generated.js --wit wit --world-name world2-sbtyzmep --disable http fetch-event --out components/provider.wasm
-
Compile the consumer component from the C++ sources in src/consumer-Cpp/:
wasm32-wasip2-clang++ -std=c++23 -fno-exceptions -o components/consumer.wasm -mexec-model=reactor src/consumer-Cpp/world2b-dthcw81x_generated.cpp src/consumer-Cpp/world2b_dthcw81x.cpp src/consumer-Cpp/world2b_dthcw81x_component_type.o
-
Compose the two components into one runnable component with wac 0.8.1:
wac plug components/consumer.wasm --plug components/provider.wasm -o composed.wasm
-
Run the composed component with wasmtime 41.0.0:
wasmtime run composed.wasm
Expected result
This test case intentionally performs an invalid resource-handle operation at the very end, so the expected behavior is: print the prefix below, then trap cleanly with invalid handle. A reference interpreter for the generated program behaves exactly this way:
"resinst0"
"resinst0"
"bar"
"c2"
true
true
ok(some(c2(some(resource("temres63")))))
((resource("temres64"), "p"), "beta")
"c2"
true
true
"bar"
c0(1)
[some(c1([resource("temres13")]))]
"c1"
true
"temres99"
trap(invalid handle)
(jco on the same file also fails (rc=1), but its output diverges from this reference as well; see Notes below — it is raw differential data, not confirming evidence for this expected output.)
Actual result
Under wasmtime the same composed.wasm exits with rc=1. stdout:
"resinst0"
"resinst0"
"bar"
"c2"
true
true
ok(some(c2(some(resource("temres63")))))
((resource("temres64"), "p"), "beta")
"c2"
true
true
"bar"
stderr:
Error: failed to run main module `/Users/zhangyixuan/WASM/myProject/Wasm_component_testing/mycode/execute/reportrepo/G004-wit-bindgen-cpp-emits-invalid-resource-handle-unknown-handle-index/composed.wasm`
Caused by:
0: failed to invoke `run` function
1: error while executing at wasm backtrace:
0: 0x858 - <unknown>!<wasm function 20>
1: 0xd1c000 - wit-component:shim!indirect-mydefined:package3hl16smu1p/itf-sn3qxkhktg-f-cph90o7
2: 0xcc4053 - consumer.wasm!mydefined::package3hl16smu1p::itf_sn3qxkhktg::FCph90o7(mydefined::package3hl16smu1p::itf_sn3qxkhktg::Varnl7r84, std::__2::span<std::__2::optional<mydefined::package3hl16smu1p::itf_sn3qxkhktg::Varnl7r84>, 4294967295ul>)
3: 0xcbdf75 - consumer.wasm!exports::wasi::cli::run::Run()
4: 0xcc428a - consumer.wasm!__wasm_export_wasiX3AcliX2FrunX400X2E2X2E0X23run
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
2: unknown handle index 3852
Notes
- Differential evidence — jco on the exact same file: rc=1
"resinst0"
"temres2"
"bar"
"c2"
true
true
ok(some(c2(some(resource("temres63")))))
((resource("temres64"), "p"), "beta")
"c2"
true
true
"bar"
--- stderr ---
can't access property "rep", repTable.get(...) is undefined
Stack:
export_itfSn3qxkhktg$fCph90o7@/var/folders/ng/263gml_52h33wsbthhfjjr980000gn/T/ca0ba5338ca2/sources/initializer.js:12460:33
Redirecting call to abort() to mozalloc_abort
RuntimeError: unreachable
at wasm://wasm/03286172:wasm-function[12489]:0x885e22
at wasm://wasm/03286172:wasm-function[4582]:0x1abd23
at mydefined:package3hl16smu1p/itf-sn3qxkhktg#f-cph90o7 (wasm://wasm/03286172:wasm-function[12711]:0x89d478)
at wasm://wasm/11dbd7b2:wasm-function[23]:0x8a1
at wit-component:shim.indirect-mydefined:package3hl16smu1p/itf-sn3qxkhktg-f-cph90o7 (wasm://wasm/wit-component:shim-786761ae:wasm-function[3]:0x124)
at consumer.wasm.mydefined::package3hl16smu1p::itf_sn3qxkhktg::FCph90o7(mydefined::package3hl16smu1p::itf_sn3qxkhktg::Varnl7r84, std::__2::span<std::__2::optional<mydefined::package3hl16smu1p::itf_sn3qxkhktg::Varnl7r84>, 4294967295ul>) (wasm://wasm/consumer.wasm-0016dc16:wasm-function[251]:0x6f64)
at consumer.wasm.exports::wasi::cli::run::Run() (wasm://wasm/consumer.wasm-0016dc16:wasm-function[19]:0xe86)
at consumer.wasm.__wasm_export_wasiX3AcliX2FrunX400X2E2X2E0X23run (wasm://wasm/consumer.wasm-0016dc16:wasm-function[258]:0x719b)
at Object.run (file:///private/var/folders/ng/263gml_52h33wsbthhfjjr980000gn/T/ARsKAl/composed.js:30578:13)
at file:///private/var/folders/ng/263gml_52h33wsbthhfjjr980000gn/T/ARsKAl/_run.js:14:15
wit-bindgen-cpp generates invalid resource handles for variant/list<option> params, causing an 'unknown handle index' trap in wasmtime
Reproduction of a wit-bindgen-cpp handle-management defect where C++ components pass invalid resource handles across the component boundary, aborting execution in wasmtime with 'unknown handle index'.
Environment
Steps to reproduce
The full chain is: compile the guest sources into a provider component and a consumer component, compose them with
wac, then run the composed component. Prebuilt copies of every artifact are included (components/provider.wasm,components/consumer.wasm,composed.wasm), so you can also skip straight to step 5.Github repo:https://github.com/xiaozzzZZzzz240/G004-wit-bindgen-cpp-emits-invalid-resource-handle-trapping-unknown-handle
Clone this repository:
Compile the provider component from the JavaScript sources in
src/provider-JavaScript/(toolchain versions in the table above; the WIT package is inwit/):jco componentize src/provider-JavaScript/world2-sbtyzmep_generated.js --wit wit --world-name world2-sbtyzmep --disable http fetch-event --out components/provider.wasmCompile the consumer component from the C++ sources in
src/consumer-Cpp/:wasm32-wasip2-clang++ -std=c++23 -fno-exceptions -o components/consumer.wasm -mexec-model=reactor src/consumer-Cpp/world2b-dthcw81x_generated.cpp src/consumer-Cpp/world2b_dthcw81x.cpp src/consumer-Cpp/world2b_dthcw81x_component_type.oCompose the two components into one runnable component with wac 0.8.1:
wac plug components/consumer.wasm --plug components/provider.wasm -o composed.wasmRun the composed component with wasmtime 41.0.0:
wasmtime run composed.wasmExpected result
This test case intentionally performs an invalid resource-handle operation at the very end, so the expected behavior is: print the prefix below, then trap cleanly with
invalid handle. A reference interpreter for the generated program behaves exactly this way:(
jcoon the same file also fails (rc=1), but its output diverges from this reference as well; see Notes below — it is raw differential data, not confirming evidence for this expected output.)Actual result
Under wasmtime the same
composed.wasmexits with rc=1. stdout:stderr:
Notes