Skip to content

Bug report: An error when deleting from the resource table causes the next access to obtain an incorrect handle. #1381

@xiaozzzZZzzz240

Description

@xiaozzzZZzzz240

generated_wit_00000.wit.zip
generated_wit_00000b.wit.zip
cplusplus.zip
python.zip
world0-pvwxtgtmlk_fromPython.wasm.zip
world1-consumer_fromC++_importworld0-pvwxtgtmlk_fromPython.wasm.zip
world1-consumer_fromC++.wasm.zip

Summary

Maybe this is the same type of issue as #1380.
In jco, the group resource object is incorrectly mapped to an exception object (which appears as an empty string / an erroneous proxy object) on the jco‑to‑Python side, so calling sizes results in '' has no attribute 'sizes'.

Environment

jco 1.16.1
wasmtime 41.0.0
OS: macOS Sequoia 15.7
CPU: Intel Core i7

Reproduce steps

The specific reproduction steps are as follows:

  1. Use the following command to generate Python binding files from generated_wit_00000.wit.
    componentize-py -d xxx/witfiles/package3hl16smu1p -w world0-pvwxtgtmlk bindings xxx/python/world0-pvwxtgtmlk

  2. Implement the Python program as shown in python.zip.

  3. Use the following command to generate Wasm component file from Python.
    cd xxx/python/world0-pvwxtgtmlk
    componentize-py --wit-path xxx/witfiles/package3hl16smu1p --world world0-pvwxtgtmlk componentize world0-pvwxtgtmlk_generated -o xxx/componentfiles/world0-pvwxtgtmlk_fromPython.wasm

  4. Use the following command to generate C++ binding files from generated_wit_00000b.wit.
    wit-bindgen cpp xxx/witfiles/package3hl16smu1p --world world1-consumer --out-dir xxx/cplusplus/world1-consumer

  5. Implement the C++ program as shown in cplusplus.zip.

  6. Use the following command to generate Wasm component file from C++.
    xxx/WASI/wasi-sdk-27.0/wasi-sdk-27.0-x86_64-macos/bin/wasm32-wasip2-clang++ -std=c++23 -o xxx/componentfiles/world1-consumer_fromC++.wasm -mexec-model=reactor xxx/cplusplus/world1-consumer/world1-consumer_generated.cpp xxx/cplusplus/world1-consumer/world1_consumer.cpp xxx/cplusplus/world1-consumer/world1_consumer_component_type.o

  7. Use wac to combine the two Wasm component files:
    wac plug xxx/componentfiles/world1-consumer_fromC++.wasm --plug xxx/componentfiles/world0-pvwxtgtmlk_fromPython.wasm -o xxx/componentfiles/world1-consumer_fromC++_importworld0-pvwxtgtmlk_fromPython.wasm

  8. Use wasmtime to run the final Wasm component file:
    wasmtime run world1-consumer_fromC++_importworld0-pvwxtgtmlk_fromPython.wasm
    Wasmtime prints:

[min-group] run begin
[dbg] py: open_temp path=mem://f-1 size=1
[dbg] py: file.__init__ path=mem://f-1
[dbg] py: open_temp path=mem://f-2 size=2
[dbg] py: file.__init__ path=mem://f-2
[dbg] py: make_group
[dbg] py: group.__init__
[min-group] before sizes
[dbg] py: file.size path=mem://f-1 -> 1
[dbg] py: file.size path=mem://f-2 -> 2
[dbg] py: group.sizes -> (1, 2)
[min-group] after sizes (1, 2)
[min-group] PASS
  1. Use jco to run the same final Wasm component file:
    jco run world1-consumer_fromC++_importworld0-pvwxtgtmlk_fromPython.wasm
    jco prints:
[min-group] run begin
[dbg] py: open_temp path=mem://f-1 size=1
[dbg] py: file.__init__ path=mem://f-1
[dbg] py: open_temp path=mem://f-2 size=2
[dbg] py: file.__init__ path=mem://f-2
[dbg] py: make_group
[dbg] py: group.__init__
[min-group] before sizes
AttributeError: '' object has no attribute 'sizes'

thread '<unnamed>' panicked at runtime/src/lib.rs:499:21:
Python function threw an unexpected exception
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
RuntimeError: unreachable
    at libc.so.abort (wasm://wasm/libc.so-001e65fe:wasm-function[458]:0x1041d)
    at wasm://wasm/02a72c46:wasm-function[306]:0xf8e8
    at libcomponentize_py_runtime.so.std::sys::pal::wasi::helpers::abort_internal::h118dde344a79086c (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2193]:0xceb72)
    at libcomponentize_py_runtime.so.std::process::abort::h2738589d00d7233e (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1645]:0xb87f6)
    at libcomponentize_py_runtime.so.__rustc::__rust_abort (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2002]:0xc7330)
    at libcomponentize_py_runtime.so.__rustc::__rust_start_panic (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2208]:0xcfc4c)
    at libcomponentize_py_runtime.so.__rustc::rust_panic (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2035]:0xc8a1e)
    at libcomponentize_py_runtime.so.std::panicking::rust_panic_with_hook::h02d894de16d94192 (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2034]:0xc899c)
    at libcomponentize_py_runtime.so.std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::he125d401eefa4f33 (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1573]:0xb451a)
    at libcomponentize_py_runtime.so.std::sys::backtrace::__rust_end_short_backtrace::h31a9416a2c4ea1cb (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1572]:0xb4442)

Simplified reproduction steps

  1. Use wasmtime to run the final Wasm component file:
    wasmtime run world1-consumer_fromC++_importworld0-pvwxtgtmlk_fromPython.wasm
    Wasmtime prints:
[min-group] run begin
[dbg] py: open_temp path=mem://f-1 size=1
[dbg] py: file.__init__ path=mem://f-1
[dbg] py: open_temp path=mem://f-2 size=2
[dbg] py: file.__init__ path=mem://f-2
[dbg] py: make_group
[dbg] py: group.__init__
[min-group] before sizes
[dbg] py: file.size path=mem://f-1 -> 1
[dbg] py: file.size path=mem://f-2 -> 2
[dbg] py: group.sizes -> (1, 2)
[min-group] after sizes (1, 2)
[min-group] PASS
  1. Use jco to run the same final Wasm component file:
    jco run world1-consumer_fromC++_importworld0-pvwxtgtmlk_fromPython.wasm
    jco prints:
[min-group] run begin
[dbg] py: open_temp path=mem://f-1 size=1
[dbg] py: file.__init__ path=mem://f-1
[dbg] py: open_temp path=mem://f-2 size=2
[dbg] py: file.__init__ path=mem://f-2
[dbg] py: make_group
[dbg] py: group.__init__
[min-group] before sizes
AttributeError: '' object has no attribute 'sizes'

thread '<unnamed>' panicked at runtime/src/lib.rs:499:21:
Python function threw an unexpected exception
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
RuntimeError: unreachable
    at libc.so.abort (wasm://wasm/libc.so-001e65fe:wasm-function[458]:0x1041d)
    at wasm://wasm/02a72c46:wasm-function[306]:0xf8e8
    at libcomponentize_py_runtime.so.std::sys::pal::wasi::helpers::abort_internal::h118dde344a79086c (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2193]:0xceb72)
    at libcomponentize_py_runtime.so.std::process::abort::h2738589d00d7233e (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1645]:0xb87f6)
    at libcomponentize_py_runtime.so.__rustc::__rust_abort (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2002]:0xc7330)
    at libcomponentize_py_runtime.so.__rustc::__rust_start_panic (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2208]:0xcfc4c)
    at libcomponentize_py_runtime.so.__rustc::rust_panic (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2035]:0xc8a1e)
    at libcomponentize_py_runtime.so.std::panicking::rust_panic_with_hook::h02d894de16d94192 (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[2034]:0xc899c)
    at libcomponentize_py_runtime.so.std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::he125d401eefa4f33 (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1573]:0xb451a)
    at libcomponentize_py_runtime.so.std::sys::backtrace::__rust_end_short_backtrace::h31a9416a2c4ea1cb (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1572]:0xb4442)

Result Analysis

Maybe this is the same type of issue as #1380.
This bug is probably due to:
In the resourceTransferBorrow generated by jco js-component-bindgen, the wrong parameter is used when removing a borrow handle.
It writes the second parameter of rscTableRemove(fromTable, ...) as fromHandle (slot value, rep|flag), whereas the correct parameter should be handle (slot index).
As a result:
The resource table is read/written using the wrong index (handle table corruption).
Subsequent resource method calls (e.g., group.sizes) get the wrong object.

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