componentize-py: generated resource __exit__ drop binding unpacks None, causing TypeError and a libcomponentize_py_runtime abort instead of an invalid-handle trap under jco
Reproduction of a componentize-py bug where generated Python import bindings mismanage resource handles, so dropping a resource unpacks a None handle pair and aborts the guest runtime under jco.
Both G007:#233 and G008 are componentize-py 0.17.2 bugs from the illegal suite: an intentional invalid resource-handle operation should trap cleanly with invalid handle, but instead the Python side sees a None handle and aborts. They differ in code path: G007 crashes while lowering a handle into an imported method call — the Rust runtime's ToCanonHandle unwraps a TypeError and panics at lib.rs:1217. G008 crashes while dropping a resource — the generated exit binding unpacks a None handle pair, and the runtime panics at lib.rs:515. G007 is filed upstream (issue #233); G008 isn't yet.
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/G008-componentize-py-resource-drop-binding-unpacks-none-aborting-runtime
-
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/world7-t8b6pjs1_generated.js --wit wit --world-name world7-t8b6pjs1 --disable http fetch-event --out components/provider.wasm
-
Compile the consumer component from the Python sources in src/consumer-Python/:
(cd src/consumer-Python && componentize-py --wit-path ../../wit --world world7b-awp0lf7x componentize world7b-awp0lf7x_generated -o ../../components/consumer.wasm)
-
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 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"
"resinst0"
resource("temres7")
resource("temres9")
true
"alpha"
resource("temres111")
true
true
"alpha"
"bar"
true
true
"temres150"
trap(invalid handle)
Actual result
Under jco the same composed.wasm exits with rc=1. stdout:
"resinst0"
"temres2"
resource("resinst0")
resource("temres9")
true
"alpha"
resource("temres111")
true
true
"alpha"
"bar"
true
true
"temres7"
stderr:
Traceback (most recent call last):
File "/0/world7b-awp0lf7x_generated.py", line 264, in run
File "/0/world7b-awp0lf7x_generated.py", line 22, in _skel_drop
File "/world/wit_world/imports/itf_hthdp03eh5.py", line 56, in __exit__
TypeError: cannot unpack non-iterable NoneType object
thread '<unnamed>' panicked at runtime/src/lib.rs:515:25:
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/02947686: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)
wasmtime on the exact same file: rc=134
"resinst0"
"resinst0"
resource("temres7")
resource("temres9")
true
"alpha"
resource("temres111")
true
true
"alpha"
"bar"
true
true
"temres150"
--- stderr ---
Traceback (most recent call last):
File "/0/world7b-awp0lf7x_generated.py", line 264, in run
File "/0/world7b-awp0lf7x_generated.py", line 22, in _skel_drop
File "/world/wit_world/imports/itf_hthdp03eh5.py", line 56, in __exit__
TypeError: cannot unpack non-iterable NoneType object
thread '<unnamed>' panicked at runtime/src/lib.rs:515:25:
Python function threw an unexpected exception
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/G008-componentize-py-resource-drop-binding-unpacks-none-aborting-runtime/composed.wasm`
Caused by:
0: failed to invoke `run` function
1: error while executing at wasm backtrace:
0: 0x2e3e21e - libc.so!abort
1: 0xccb64e - <unknown>!<wasm function 306>
2: 0x17ece14 - libcomponentize_py_runtime.so!std::sys::pal::wasi::helpers::abort_internal::h118dde344a79086c
3: 0x17d6a98 - libcomponentize_py_runtime.so!std::process::abort::h2738589d00d7233e
4: 0x17e55d2 - libcomponentize_py_runtime.so!__rustc::__rust_abort
5: 0x17edeee - libcomponentize_py_runtime.so!__rustc::__rust_start_panic
6: 0x17e6cc0 - libcomponentize_py_runtime.so!__rustc::rust_panic
7: 0x17e6c3e - libcomponentize_py_runtime.so!std::panicking::rust_panic_with_hook::h02d894de16d94192
8: 0x17d27bc - libcomponentize_py_runtime.so!std::panicking::begin_panic_handler::_$u7b$$u7b$closure$u7d$$u7d$::he125d401eefa4f33
9: 0x17d26e4 - libcomponentize_py_runtime.so!std::sys::backtrace::__rust_end_short_backtrace::h31a9416a2c4ea1cb
10: 0x17e6536 - libcomponentize_py_runtime.so!__rustc::rust_begin_unwind
11: 0x1807b5f - libcomponentize_py_runtime.so!core::panicking::panic_fmt::h52dbee1629029330
12: 0x175ea2d - libcomponentize_py_runtime.so!componentize-py#Dispatch
13: 0x2eb330e - libcomponentize_py_bindings.so!wasi:cli/run@0.2.0#run-export
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
2: wasm trap: wasm `unreachable` instruction executed
componentize-py: generated resource
__exit__drop binding unpacksNone, causingTypeErrorand alibcomponentize_py_runtimeabort instead of an invalid-handle trap under jcoReproduction of a componentize-py bug where generated Python import bindings mismanage resource handles, so dropping a resource unpacks a
Nonehandle pair and aborts the guest runtime under jco.Both G007:#233 and G008 are componentize-py 0.17.2 bugs from the illegal suite: an intentional invalid resource-handle operation should trap cleanly with invalid handle, but instead the Python side sees a None handle and aborts. They differ in code path: G007 crashes while lowering a handle into an imported method call — the Rust runtime's ToCanonHandle unwraps a TypeError and panics at lib.rs:1217. G008 crashes while dropping a resource — the generated exit binding unpacks a None handle pair, and the runtime panics at lib.rs:515. G007 is filed upstream (issue #233); G008 isn't yet.
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/G008-componentize-py-resource-drop-binding-unpacks-none-aborting-runtime
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/world7-t8b6pjs1_generated.js --wit wit --world-name world7-t8b6pjs1 --disable http fetch-event --out components/provider.wasmCompile the consumer component from the Python sources in
src/consumer-Python/:(cd src/consumer-Python && componentize-py --wit-path ../../wit --world world7b-awp0lf7x componentize world7b-awp0lf7x_generated -o ../../components/consumer.wasm)Compose 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 jco:
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.Actual result
Under jco the same
composed.wasmexits with rc=1. stdout:stderr:
wasmtime on the exact same file: rc=134