Coverage for wasmtime/_trap.py: 95%
130 statements
« prev ^ index » next coverage.py v7.11.3, created at 2026-05-07 14:30 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2026-05-07 14:30 +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
32 # Execution has run out of the configured fuel amount.
33 OUT_OF_FUEL = 11
34 # Atomic wait on non-shared memory.
35 ATOMIC_WAIT_NON_SHARED_MEMORY = 12
36 # Call to a null reference.
37 NULL_REFERENCE = 13
38 # Attempt to access beyond the bounds of an array.
39 ARRAY_OUT_OF_BOUNDS = 14
40 # Attempted an allocation that was too large to succeed.
41 ALLOCATION_TOO_LARGE = 15
42 # Attempted to cast a reference to a type that it is not an instance of.
43 CAST_FAILURE = 16
44 # A component tried to call another component in violation of the reentrance rules.
45 CANNOT_ENTER_COMPONENT = 17
46 # Async-lifted export failed to produce a result before returning STATUS_DONE.
47 NO_ASYNC_RESULT = 18
48 # Suspending to a tag for which there is no active handler.
49 UNHANDLED_TAG = 19
50 # Attempt to resume a continuation twice.
51 CONTINUATION_ALREADY_CONSUMED = 20
52 # A Pulley opcode was executed that was disabled at compile time.
53 DISABLED_OPCODE = 21
54 # Async event loop deadlocked.
55 ASYNC_DEADLOCK = 22
56 # A component tried to call an import when it was not allowed to.
57 CANNOT_LEAVE_COMPONENT = 23
58 # A synchronous task attempted a potentially blocking call before returning.
59 CANNOT_BLOCK_SYNC_TASK = 24
60 # A component tried to lift a char with an invalid bit pattern.
61 INVALID_CHAR = 25
62 # Debug assertion: string encoding not finished.
63 DEBUG_ASSERT_STRING_ENCODING_FINISHED = 26
64 # Debug assertion: equal code units.
65 DEBUG_ASSERT_EQUAL_CODE_UNITS = 27
66 # Debug assertion: pointer aligned.
67 DEBUG_ASSERT_POINTER_ALIGNED = 28
68 # Debug assertion: upper bits unset.
69 DEBUG_ASSERT_UPPER_BITS_UNSET = 29
70 # A component tried to lift or lower a string past the end of its memory.
71 STRING_OUT_OF_BOUNDS = 30
72 # A component tried to lift or lower a list past the end of its memory.
73 LIST_OUT_OF_BOUNDS = 31
74 # A component used an invalid discriminant when lowering a variant value.
75 INVALID_DISCRIMINANT = 32
76 # A component passed an unaligned pointer when lifting or lowering a value.
77 UNALIGNED_POINTER = 33
78 # task.cancel invoked in an invalid way.
79 TASK_CANCEL_NOT_CANCELLED = 34
80 # task.cancel or task.return called too many times.
81 TASK_CANCEL_OR_RETURN_TWICE = 35
82 # subtask.cancel invoked after the subtask already finished.
83 SUBTASK_CANCEL_AFTER_TERMINAL = 36
84 # task.return invoked with an invalid type.
85 TASK_RETURN_INVALID = 37
86 # waitable-set.drop invoked on a waitable set with waiters.
87 WAITABLE_SET_DROP_HAS_WAITERS = 38
88 # subtask.drop invoked on a subtask that hasn't resolved yet.
89 SUBTASK_DROP_NOT_RESOLVED = 39
90 # thread.new-indirect invoked with a function that has an invalid type.
91 THREAD_NEW_INDIRECT_INVALID_TYPE = 40
92 # thread.new-indirect invoked with an uninitialized function reference.
93 THREAD_NEW_INDIRECT_UNINITIALIZED = 41
94 # Backpressure-related intrinsics overflowed the built-in counter.
95 BACKPRESSURE_OVERFLOW = 42
96 # Invalid code returned from the callback of an async-lifted function.
97 UNSUPPORTED_CALLBACK_CODE = 43
98 # Cannot resume a thread which is not suspended.
99 CANNOT_RESUME_THREAD = 44
100 # Cannot issue a read/write on a future/stream while there is a pending operation.
101 CONCURRENT_FUTURE_STREAM_OP = 45
104class Trap(Exception, Managed["ctypes._Pointer[ffi.wasm_trap_t]"]):
106 def __init__(self, message: str):
107 """
108 Creates a new trap with the given `message`
109 """
111 vec = message.encode('utf-8')
112 self._set_ptr(ffi.wasmtime_trap_new(ctypes.create_string_buffer(vec), len(vec)))
114 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_trap_t]") -> None:
115 ffi.wasm_trap_delete(ptr)
117 @classmethod
118 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_trap_t]") -> "Trap":
119 if not isinstance(ptr, POINTER(ffi.wasm_trap_t)):
120 raise TypeError("wrong pointer type")
121 trap: Trap = cls.__new__(cls)
122 trap._set_ptr(ptr)
123 return trap
125 @property
126 def message(self) -> str:
127 """
128 Returns the message for this trap
129 """
131 message = ffi.wasm_byte_vec_t()
132 ffi.wasm_trap_message(self.ptr(), byref(message))
133 # subtract one to chop off the trailing nul byte
134 message.size -= 1
135 ret = ffi.to_str(message)
136 message.size += 1
137 ffi.wasm_byte_vec_delete(byref(message))
138 return ret
140 @property
141 def frames(self) -> List["Frame"]:
142 frames = FrameList(self)
143 ffi.wasm_trap_trace(self.ptr(), byref(frames.vec))
144 ret = []
145 for i in range(0, frames.vec.size):
146 ret.append(Frame._from_ptr(frames.vec.data[i], frames))
147 return ret
149 @property
150 def trap_code(self) -> Optional[TrapCode]:
151 """
152 Returns an optional `TrapCode` that corresponds to why this trap
153 happened.
155 Note that `None` may be returned for manually created traps which do
156 not have an associated code with them.
157 """
158 code = ffi.wasmtime_trap_code_t()
159 if ffi.wasmtime_trap_code(self.ptr(), byref(code)):
160 return TrapCode(code.value)
161 return None
163 def __str__(self) -> str:
164 return self.message
167class Frame(Managed["ctypes._Pointer[ffi.wasm_frame_t]"]):
168 _owner: Optional[Any]
170 @classmethod
171 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_frame_t]", owner: Optional[Any]) -> "Frame":
172 if not isinstance(ptr, POINTER(ffi.wasm_frame_t)):
173 raise TypeError("wrong pointer type")
174 ty: "Frame" = cls.__new__(cls)
175 ty._set_ptr(ptr)
176 ty._owner = owner
177 return ty
179 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_frame_t]") -> None:
180 if self._owner is None:
181 ffi.wasm_frame_delete(ptr)
183 @property
184 def func_index(self) -> int:
185 """
186 Returns the function index this frame corresponds to in its wasm module
187 """
189 return ffi.wasm_frame_func_index(self.ptr())
191 @property
192 def func_name(self) -> Optional[str]:
193 """
194 Returns the name of the function this frame corresponds to
196 May return `None` if no name can be inferred
197 """
199 ptr = ffi.wasmtime_frame_func_name(self.ptr())
200 if ptr:
201 return ffi.to_str(ptr.contents)
202 else:
203 return None
205 @property
206 def module_name(self) -> Optional[str]:
207 """
208 Returns the name of the module this frame corresponds to
210 May return `None` if no name can be inferred
211 """
213 ptr = ffi.wasmtime_frame_module_name(self.ptr())
214 if ptr:
215 return ffi.to_str(ptr.contents)
216 else:
217 return None
219 @property
220 def module_offset(self) -> int:
221 """
222 Returns the offset of this frame's program counter into the original
223 wasm source module.
224 """
226 return ffi.wasm_frame_module_offset(self.ptr())
228 @property
229 def func_offset(self) -> int:
230 """
231 Returns the offset of this frame's program counter into the original
232 wasm function.
233 """
235 return ffi.wasm_frame_func_offset(self.ptr())
238class FrameList:
239 owner: Any
241 def __init__(self, owner: Any) -> None:
242 self.vec = ffi.wasm_frame_vec_t(0, None)
243 self.owner = owner
245 def __del__(self) -> None:
246 ffi.wasm_frame_vec_delete(byref(self.vec))