Skip to content

G006-wit-bindgen-cpp-resource-drop-invalid-handle-trap-in-generated #1682

Description

@xiaozzzZZzzz240

wit-bindgen-cpp: generated C++ resource destructor calls resource.drop on an already-freed handle, trapping with "invalid handle" in wasmtime

Reproduction of a wit-bindgen-cpp bug where the generated C++ resource-export destructor chain (ResourceExportBase::Deregister → ResourceDrop) performs an invalid/duplicate resource.drop, aborting the component with an invalid-handle trap under wasmtime.

The wit-bindgen C++ backend is at fault—its glue layer performs an extra drop in the lift/destructor chain, translating a semantically valid program into a component that contains illegal operations.

Environment

component version
OS macOS 15.7 (Darwin 24.6.0), x86_64
wasmtime wasmtime 41.0.0 (3dda91692 2026-01-20)
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/G006-wit-bindgen-cpp-resource-drop-invalid-handle-trap-in-generated

  1. Clone this repository:

    git clone <THIS_REPO_URL>
    cd <THIS_REPO_DIR>
  2. Compile the provider component from the C++ sources in src/provider-Cpp/ (toolchain versions in the table above; the WIT package is in wit/):

    wasm32-wasip2-clang++ -std=c++23 -fno-exceptions -o components/provider.wasm -mexec-model=reactor src/provider-Cpp/world9-wi7n9u47_generated.cpp src/provider-Cpp/world9_wi7n9u47.cpp src/provider-Cpp/world9_wi7n9u47_component_type.o
  3. Compile the consumer component from the C sources in src/consumer-C/:

    wasm32-wasip2-clang -o components/consumer.wasm -mexec-model=reactor src/consumer-C/world9b-mul38v8w_generated.c src/consumer-C/world9b_mul38v8w.c src/consumer-C/world9b_mul38v8w_component_type.o
  4. 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
  5. 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.

"resinst0"
"resinst1"
"resinst2"
"resinst0"
resource("temres32")
"c1"
true
"c0"
resource("temres35")
(resource("temres36"), "foo")
"c1"
true
true
resource("temres225")
"bar"
"c2"
true
true
"temres35"
"temres40"
"beta"
"c0"
true
true
5
true
trap(invalid handle)

Actual result

Under wasmtime the same composed.wasm exits with rc=1. stdout:

"resinst0"
"resinst1"
"resinst2"
"resinst0"
resource("temres32")
"c1"
true
"c0"
resource("temres35")
(resource("temres36"), "foo")
"c1"
true
true
resource("temres225")
"bar"
"c2"
true
true

stderr:

Error: failed to run main module `/Users/myuser/WASM/myProject/Wasm_component_testing/mycode/execute/reportrepo/G006-wit-bindgen-cpp-resource-drop-invalid-handle-trap-in-generated/composed.wasm`

Caused by:
    0: failed to invoke `run` function
    1: error while executing at wasm backtrace:
           0:  0x1b078 - provider.wasm!exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2::ResourceDrop(int)
           1:  0x12e58 - provider.wasm!wit::ResourceExportBase<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2>::Deregister::operator()(exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2*) const
           2:   0x69f9 - provider.wasm!std::__2::unique_ptr<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2, wit::ResourceExportBase<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2>::Deregister>::reset[abi:nn200100](exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2*)
           3:   0x5b98 - provider.wasm!std::__2::unique_ptr<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2, wit::ResourceExportBase<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2>::Deregister>::~unique_ptr[abi:nn200100]()
           4:  0x1e008 - provider.wasm!std::__2::__tuple_leaf<0ul, std::__2::unique_ptr<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2, wit::ResourceExportBase<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2>::Deregister>, false>::~__tuple_leaf()
           5:  0x1af60 - provider.wasm!std::__2::__tuple_impl<std::__2::__tuple_indices<0ul, 1ul>, std::__2::unique_ptr<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2, wit::ResourceExportBase<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2>::Deregister>, wit::string>::~__tuple_impl()
           6:  0x1ad37 - provider.wasm!std::__2::tuple<std::__2::unique_ptr<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2, wit::ResourceExportBase<exports::mydefined::package3hl16smu1p::itf_ou0j0n064d::Res2>::Deregister>, wit::string>::~tuple()
           7:  0x1b45b - provider.wasm!__wasm_export_mydefinedX3Apackage3hl16smu1pX2Fitf_ou0j0n064dX23f_m2yyf8i
           8:    0xab2 - <unknown>!<wasm function 29>
           9:  0xe5f60 - wit-component:shim!indirect-mydefined:package3hl16smu1p/itf-ou0j0n064d-f-m2yyf8i
          10:  0xa9057 - consumer.wasm!mydefined_package3hl16smu1p_itf_ou0j0n064d_f_m2yyf8i
          11:  0xa7845 - consumer.wasm!exports_wasi_cli_run_run
          12:  0xa9209 - consumer.wasm!__wasm_export_exports_wasi_cli_run_run
       note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
    2: handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource

Metadata

Metadata

Assignees

No one assigned

    Labels

    gen-cppRelated to the C++ code generator

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions