Skip to content

G007-componentize-py-invalid-resource-handle-none-unwrap-panics-instead-of #233

Description

@xiaozzzZZzzz240

componentize-py: dropped/invalid resource handle yields None instead of an integer, causing a Result::unwrap() panic on TypeError and process abort in jco instead of an invalid-handle trap

Reproduction of a componentize-py runtime crash where an invalid or dangling resource handle is passed to Python as None, making runtime/src/lib.rs unwrap a TypeError PyErr and abort under jco rather than trapping with an invalid-handle error.

When a Python consumer calls a method on an already-dropped resource handle, componentize-py's bindings pass the handle as None instead of an integer. Its Rust runtime then unwrap()s the resulting TypeError and aborts the whole component, instead of surfacing the clean invalid handle trap required by the Component Model. Reproduces identically under both wasmtime and jco.

We deliberately passed a bad handle; in the correct world, the host would look it up in the table and then trap with "invalid handle". In reality, componentize-py's binding layer trips over None and panics before the handle even leaves the guest.

Environment

component version
OS macOS 15.7 (Darwin 24.6.0), x86_64
jco 1.16.1 (source checkout, tag jco-v1.16.1)
Node.js v22.22.2
wac wac-cli 0.8.1
componentize-py componentize-py 0.17.2

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/G007-componentize-py-invalid-resource-handle-none-unwrap-panics-instead-of

  1. Clone this repository:

    git clone <THIS_REPO_URL>
    cd <THIS_REPO_DIR>
  2. 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/world0-afno6b9m_generated.js --wit wit --world-name world0-afno6b9m --disable http fetch-event --out components/provider.wasm
  3. Compile the consumer component from the Python sources in src/consumer-Python/:

    (cd src/consumer-Python && componentize-py --wit-path ../../wit --world world0b-w80o2rak componentize world0b-w80o2rak_generated -o ../../components/consumer.wasm)
  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 jco:

    npm install -g @bytecodealliance/jco@1.16.1
    jco 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("temres9")
true
true
ok(resource("temres13"))
true
true
"alpha"
"beta"
true
"temres335"
trap(invalid handle)

Actual result

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

"resinst0"
"resinst0"
"resinst0"
"resinst1"
resource("temres9")
true
true
ok(resource("temres13"))
true
true
"alpha"
"beta"
true
"temres4"

stderr:

thread '<unnamed>' panicked at runtime/src/lib.rs:1217:14:
called `Result::unwrap()` on an `Err` value: PyErr { type: <class 'TypeError'>, value: TypeError("'NoneType' object cannot be interpreted as an integer"), traceback: None }
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/02945cba: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]:0xb44e1)
    at libcomponentize_py_runtime.so.std::sys::backtrace::__rust_end_short_backtrace::h31a9416a2c4ea1cb (wasm://wasm/libcomponentize_py_runtime.so-0052fcc2:wasm-function[1572]:0xb4442)

wasmtime on the exact same file: rc=134

"resinst0"
"resinst1"
"resinst2"
"resinst0"
resource("temres9")
true
true
ok(resource("temres13"))
true
true
"alpha"
"beta"
true
"temres335"

--- stderr ---

thread '<unnamed>' panicked at runtime/src/lib.rs:1217:14:
called `Result::unwrap()` on an `Err` value: PyErr { type: <class 'TypeError'>, value: TypeError("'NoneType' object cannot be interpreted as an integer"), traceback: None }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Error: failed to run main module `/Users/myuser/WASM/myProject/Wasm_component_testing/mycode/execute/reportrepo/G007-componentize-py-invalid-resource-handle-none-unwrap-panics-instead-of/composed.wasm`

Caused by:
    0: failed to invoke `run` function
    1: error while executing at wasm backtrace:
           0: 0x2e53270 - libc.so!abort
           1: 0xce0d13 - <unknown>!<wasm function 306>
           2: 0x1801e66 - libcomponentize_py_runtime.so!std::sys::pal::wasi::helpers::abort_internal::h118dde344a79086c
           3: 0x17ebaea - libcomponentize_py_runtime.so!std::process::abort::h2738589d00d7233e
           4: 0x17fa624 - libcomponentize_py_runtime.so!__rustc::__rust_abort
           5: 0x1802f40 - libcomponentize_py_runtime.so!__rustc::__rust_start_panic
           6: 0x17fbd12 - libcomponentize_py_runtime.so!__rustc::rust_panic
           7: 0x17fbc90 - libcomponentize_py_runtime.so!std::panicking::rust_panic_with_hook::h02d894de16d94192
           8: 0x17e77d5 - libcomponentize_py_runtime.so!std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::he125d401eefa4f33
           9: 0x17e7736 - libcomponentize_py_runtime.so!std::sys::backtrace::__rust_end_short_backtrace::h31a9416a2c4ea1cb
          10: 0x17fb588 - libcomponentize_py_runtime.so!__rustc::rust_begin_unwind
          11: 0x181cbb1 - libcomponentize_py_runtime.so!core::panicking::panic_fmt::h52dbee1629029330
          12: 0x183c177 - libcomponentize_py_runtime.so!core::result::unwrap_failed::h68b1db2abd074508
          13: 0x177816a - libcomponentize_py_runtime.so!componentize-py#ToCanonHandle
          14: 0x2ebfd2e - libcomponentize_py_bindings.so!mydefined:package3hl16smu1p/itf-arpoig8f1c#[method]res0.get-name-import
          15: 0x2ec8b79 - libcomponentize_py_bindings.so!componentize-py#CallIndirect
          16: 0xce0d4b - <unknown>!<wasm function 310>
          17: 0x1778707 - libcomponentize_py_runtime.so!componentize_py_runtime::_$LT$impl$u20$componentize_py_runtime..call_import..MakeDef$GT$::_PYO3_DEF::trampoline::h88da0896868f0eed
          18: 0x1ac78d8 - libpython3.12.so!_PyEval_EvalFrameDefault
          19: 0x1acba17 - libpython3.12.so!_PyEval_Vector
          20: 0x19a9390 - libpython3.12.so!_PyFunction_Vectorcall
          21: 0x19ab8fd - libpython3.12.so!method_vectorcall
          22: 0x19a8d4f - libpython3.12.so!_PyVectorcall_Call
          23: 0x19a9132 - libpython3.12.so!_PyObject_Call
          24: 0x19a91cc - libpython3.12.so!PyObject_Call
          25: 0xce0921 - <unknown>!<wasm

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