Skip to content

Commit

Permalink
Bind wasmtime_trap_exit_status
Browse files Browse the repository at this point in the history
* Add an `ExitTrap` subclass of `Trap`
* Return an appropriate trap from `Trap.__from_ptr__`
* Attach the exit code via a `code` field

Closes bytecodealliance#30
  • Loading branch information
alexcrichton committed Jun 23, 2020
1 parent d3ed319 commit 4a33f20
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
29 changes: 29 additions & 0 deletions tests/test_trap.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,32 @@ def test_frames_no_module(self):
self.assertEqual(frames[0].func_index, 0)
self.assertEqual(frames[0].func_name, None)
self.assertEqual(frames[0].module_name, None)

def test_wasi_exit(self):
store = Store()
module = Module(store, """
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $exit (param i32)))
(func (export "exit") (param i32)
local.get 0
call $exit)
)
""")
linker = Linker(store)
wasi = WasiConfig()
linker.define_wasi(WasiInstance(store, "wasi_snapshot_preview1", wasi))
instance = linker.instantiate(module)
exit = instance.exports["exit"]
assert(isinstance(exit, Func))

try:
exit(0)
assert(False)
except ExitTrap as e:
assert(e.code == 0)

try:
exit(1)
assert(False)
except ExitTrap as e:
assert(e.code == 1)
3 changes: 2 additions & 1 deletion wasmtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from ._wat2wasm import wat2wasm
from ._module import Module
from ._value import Val, IntoVal
from ._trap import Trap, Frame
from ._trap import Trap, Frame, ExitTrap
from ._func import Func, Caller
from ._globals import Global
from ._table import Table
Expand Down Expand Up @@ -52,6 +52,7 @@
'Memory',
'Global',
'Trap',
'ExitTrap',
'Frame',
'Module',
'Instance',
Expand Down
6 changes: 6 additions & 0 deletions wasmtime/_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1972,6 +1972,12 @@ def wasmtime_interrupt_handle_new(store: Any) -> pointer:
def wasmtime_interrupt_handle_interrupt(handle: Any) -> None:
return _wasmtime_interrupt_handle_interrupt(handle) # type: ignore

_wasmtime_trap_exit_status = dll.wasmtime_trap_exit_status
_wasmtime_trap_exit_status.restype = c_bool
_wasmtime_trap_exit_status.argtypes = [POINTER(wasm_trap_t), POINTER(c_int)]
def wasmtime_trap_exit_status(arg0: Any, status: Any) -> c_bool:
return _wasmtime_trap_exit_status(arg0, status) # type: ignore

_wasmtime_frame_func_name = dll.wasmtime_frame_func_name
_wasmtime_frame_func_name.restype = POINTER(wasm_name_t)
_wasmtime_frame_func_name.argtypes = [POINTER(wasm_frame_t)]
Expand Down
32 changes: 28 additions & 4 deletions wasmtime/_trap.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from . import _ffi as ffi
from ctypes import byref, POINTER, pointer
from ctypes import byref, POINTER, pointer, c_int
from wasmtime import Store, WasmtimeError
from typing import Optional, Any, List

Expand All @@ -24,9 +24,16 @@ def __init__(self, store: Store, message: str):
def __from_ptr__(cls, ptr: "pointer[ffi.wasm_trap_t]") -> "Trap":
if not isinstance(ptr, POINTER(ffi.wasm_trap_t)):
raise TypeError("wrong pointer type")
trap: "Trap" = cls.__new__(cls)
trap.__ptr__ = ptr
return trap
exit_code = c_int(0)
if ffi.wasmtime_trap_exit_status(ptr, byref(exit_code)):
exit_trap: ExitTrap = ExitTrap.__new__(ExitTrap)
exit_trap.__ptr__ = ptr
exit_trap.code = exit_code.value
return exit_trap
else:
trap: Trap = cls.__new__(cls)
trap.__ptr__ = ptr
return trap

@property
def message(self) -> str:
Expand Down Expand Up @@ -60,6 +67,23 @@ def __del__(self) -> None:
ffi.wasm_trap_delete(self.__ptr__)


class ExitTrap(Trap):
"""
A special type of `Trap` which represents the process exiting via WASI's
`proc_exit` function call.
Whenever a WASI program exits via `proc_exit` a trap is raised, but the
trap will have this type instead of `Trap`, so you can catch just this
type instead of all traps (if desired). Exit traps have a `code` associated
with them which is the exit code provided at exit.
Note that `ExitTrap` is a subclass of `Trap`, so if you catch a trap you'll
also catch `ExitTrap`.
"""
code: int
pass


class Frame:
__ptr__: "pointer[ffi.wasm_frame_t]"
__owner__: Optional[Any]
Expand Down

0 comments on commit 4a33f20

Please sign in to comment.