Coverage for wasmtime/_trap.py: 94%
97 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-20 16:25 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-20 16:25 +0000
1from . import _ffi as ffi
2from enum import Enum
3from ctypes import byref, POINTER
4import ctypes
5from typing import Optional, Any, List
6from wasmtime import Managed
9class TrapCode(Enum):
10 # The current stack space was exhausted.
11 STACK_OVERFLOW = 0
12 # An out-of-bounds memory access.
13 MEMORY_OUT_OF_BOUNDS = 1
14 # A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
15 HEAP_MISALIGNED = 2
16 # An out-of-bounds access to a table.
17 TABLE_OUT_OF_BOUNDS = 3
18 # Indirect call to a null table entry.
19 INDIRECT_CALL_TO_NULL = 4
20 # Signature mismatch on indirect call.
21 BAD_SIGNATURE = 5
22 # An integer arithmetic operation caused an overflow.
23 INTEGER_OVERFLOW = 6
24 # An integer division by zero.
25 INTEGER_DIVISION_BY_ZERO = 7
26 # Failed float-to-int conversion.
27 BAD_CONVERSION_TO_INTEGER = 8
28 # Code that was supposed to have been unreachable was reached.
29 UNREACHABLE = 9
30 # Execution has potentially run too long and may be interrupted.
31 INTERRUPT = 10
34class Trap(Exception, Managed["ctypes._Pointer[ffi.wasm_trap_t]"]):
36 def __init__(self, message: str):
37 """
38 Creates a new trap with the given `message`
39 """
41 vec = message.encode('utf-8')
42 self._set_ptr(ffi.wasmtime_trap_new(ffi.create_string_buffer(vec), len(vec)))
44 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_trap_t]") -> None:
45 ffi.wasm_trap_delete(ptr)
47 @classmethod
48 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_trap_t]") -> "Trap":
49 if not isinstance(ptr, POINTER(ffi.wasm_trap_t)):
50 raise TypeError("wrong pointer type")
51 trap: Trap = cls.__new__(cls)
52 trap._set_ptr(ptr)
53 return trap
55 @property
56 def message(self) -> str:
57 """
58 Returns the message for this trap
59 """
61 message = ffi.wasm_byte_vec_t()
62 ffi.wasm_trap_message(self.ptr(), byref(message))
63 # subtract one to chop off the trailing nul byte
64 message.size -= 1
65 ret = ffi.to_str(message)
66 message.size += 1
67 ffi.wasm_byte_vec_delete(byref(message))
68 return ret
70 @property
71 def frames(self) -> List["Frame"]:
72 frames = FrameList(self)
73 ffi.wasm_trap_trace(self.ptr(), byref(frames.vec))
74 ret = []
75 for i in range(0, frames.vec.size):
76 ret.append(Frame._from_ptr(frames.vec.data[i], frames))
77 return ret
79 @property
80 def trap_code(self) -> Optional[TrapCode]:
81 """
82 Returns an optional `TrapCode` that corresponds to why this trap
83 happened.
85 Note that `None` may be returned for manually created traps which do
86 not have an associated code with them.
87 """
88 code = ffi.wasmtime_trap_code_t()
89 if ffi.wasmtime_trap_code(self.ptr(), byref(code)):
90 return TrapCode(code.value)
91 return None
93 def __str__(self) -> str:
94 return self.message
97class Frame(Managed["ctypes._Pointer[ffi.wasm_frame_t]"]):
98 _owner: Optional[Any]
100 @classmethod
101 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_frame_t]", owner: Optional[Any]) -> "Frame":
102 if not isinstance(ptr, POINTER(ffi.wasm_frame_t)):
103 raise TypeError("wrong pointer type")
104 ty: "Frame" = cls.__new__(cls)
105 ty._set_ptr(ptr)
106 ty._owner = owner
107 return ty
109 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_frame_t]") -> None:
110 if self._owner is None:
111 ffi.wasm_frame_delete(ptr)
113 @property
114 def func_index(self) -> int:
115 """
116 Returns the function index this frame corresponds to in its wasm module
117 """
119 return ffi.wasm_frame_func_index(self.ptr())
121 @property
122 def func_name(self) -> Optional[str]:
123 """
124 Returns the name of the function this frame corresponds to
126 May return `None` if no name can be inferred
127 """
129 ptr = ffi.wasmtime_frame_func_name(self.ptr())
130 if ptr:
131 return ffi.to_str(ptr.contents)
132 else:
133 return None
135 @property
136 def module_name(self) -> Optional[str]:
137 """
138 Returns the name of the module this frame corresponds to
140 May return `None` if no name can be inferred
141 """
143 ptr = ffi.wasmtime_frame_module_name(self.ptr())
144 if ptr:
145 return ffi.to_str(ptr.contents)
146 else:
147 return None
149 @property
150 def module_offset(self) -> int:
151 """
152 Returns the offset of this frame's program counter into the original
153 wasm source module.
154 """
156 return ffi.wasm_frame_module_offset(self.ptr())
158 @property
159 def func_offset(self) -> int:
160 """
161 Returns the offset of this frame's program counter into the original
162 wasm function.
163 """
165 return ffi.wasm_frame_func_offset(self.ptr())
168class FrameList:
169 owner: Any
171 def __init__(self, owner: Any) -> None:
172 self.vec = ffi.wasm_frame_vec_t(0, None)
173 self.owner = owner
175 def __del__(self) -> None:
176 ffi.wasm_frame_vec_delete(byref(self.vec))