Coverage for wasmtime/_trap.py: 96%
134 statements
« prev ^ index » next coverage.py v7.11.3, created at 2026-07-20 18:48 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2026-07-20 18:48 +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 = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_STACK_OVERFLOW.value
12 # An out-of-bounds memory access.
13 MEMORY_OUT_OF_BOUNDS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_MEMORY_OUT_OF_BOUNDS.value
14 # A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
15 HEAP_MISALIGNED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_HEAP_MISALIGNED.value
16 # An out-of-bounds access to a table.
17 TABLE_OUT_OF_BOUNDS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_TABLE_OUT_OF_BOUNDS.value
18 # Indirect call to a null table entry.
19 INDIRECT_CALL_TO_NULL = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_INDIRECT_CALL_TO_NULL.value
20 # Signature mismatch on indirect call.
21 BAD_SIGNATURE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_BAD_SIGNATURE.value
22 # An integer arithmetic operation caused an overflow.
23 INTEGER_OVERFLOW = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_INTEGER_OVERFLOW.value
24 # An integer division by zero.
25 INTEGER_DIVISION_BY_ZERO = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_INTEGER_DIVISION_BY_ZERO.value
26 # Failed float-to-int conversion.
27 BAD_CONVERSION_TO_INTEGER = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_BAD_CONVERSION_TO_INTEGER.value
28 # Code that was supposed to have been unreachable was reached.
29 UNREACHABLE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED.value
30 # Execution has potentially run too long and may be interrupted.
31 INTERRUPT = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_INTERRUPT.value
32 # Execution has run out of the configured fuel amount.
33 OUT_OF_FUEL = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_OUT_OF_FUEL.value
34 # Atomic wait on non-shared memory.
35 ATOMIC_WAIT_NON_SHARED_MEMORY = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_ATOMIC_WAIT_NON_SHARED_MEMORY.value
36 # Call to a null reference.
37 NULL_REFERENCE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_NULL_REFERENCE.value
38 # Attempt to access beyond the bounds of an array.
39 ARRAY_OUT_OF_BOUNDS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_ARRAY_OUT_OF_BOUNDS.value
40 # Attempted an allocation that was too large to succeed.
41 ALLOCATION_TOO_LARGE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_ALLOCATION_TOO_LARGE.value
42 # Attempted to cast a reference to a type that it is not an instance of.
43 CAST_FAILURE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CAST_FAILURE.value
44 # A component tried to call another component in violation of the reentrance rules.
45 CANNOT_ENTER_COMPONENT = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CANNOT_ENTER_COMPONENT.value
46 # Async-lifted export failed to produce a result before returning STATUS_DONE.
47 NO_ASYNC_RESULT = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_NO_ASYNC_RESULT.value
48 # Suspending to a tag for which there is no active handler.
49 UNHANDLED_TAG = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_UNHANDLED_TAG.value
50 # Attempt to resume a continuation twice.
51 CONTINUATION_ALREADY_CONSUMED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CONTINUATION_ALREADY_CONSUMED.value
52 # A Pulley opcode was executed that was disabled at compile time.
53 DISABLED_OPCODE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_DISABLED_OPCODE.value
54 # Async event loop deadlocked.
55 ASYNC_DEADLOCK = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_ASYNC_DEADLOCK.value
56 # A component tried to call an import when it was not allowed to.
57 CANNOT_LEAVE_COMPONENT = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CANNOT_LEAVE_COMPONENT.value
58 # A synchronous task attempted a potentially blocking call before returning.
59 CANNOT_BLOCK_SYNC_TASK = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CANNOT_BLOCK_SYNC_TASK.value
60 # A component tried to lift a char with an invalid bit pattern.
61 INVALID_CHAR = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_INVALID_CHAR.value
62 # Debug assertion: string encoding not finished.
63 DEBUG_ASSERT_STRING_ENCODING_FINISHED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_DEBUG_ASSERT_STRING_ENCODING_FINISHED.value
64 # Debug assertion: equal code units.
65 DEBUG_ASSERT_EQUAL_CODE_UNITS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_DEBUG_ASSERT_EQUAL_CODE_UNITS.value
66 # Debug assertion: pointer aligned.
67 DEBUG_ASSERT_POINTER_ALIGNED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_DEBUG_ASSERT_POINTER_ALIGNED.value
68 # Debug assertion: upper bits unset.
69 DEBUG_ASSERT_UPPER_BITS_UNSET = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_DEBUG_ASSERT_UPPER_BITS_UNSET.value
70 # A component tried to lift or lower a string past the end of its memory.
71 STRING_OUT_OF_BOUNDS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_STRING_OUT_OF_BOUNDS.value
72 # A component tried to lift or lower a list past the end of its memory.
73 LIST_OUT_OF_BOUNDS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_LIST_OUT_OF_BOUNDS.value
74 # A component used an invalid discriminant when lowering a variant value.
75 INVALID_DISCRIMINANT = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_INVALID_DISCRIMINANT.value
76 # A component passed an unaligned pointer when lifting or lowering a value.
77 UNALIGNED_POINTER = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_UNALIGNED_POINTER.value
78 # task.cancel invoked in an invalid way.
79 TASK_CANCEL_NOT_CANCELLED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_TASK_CANCEL_NOT_CANCELLED.value
80 # task.cancel or task.return called too many times.
81 TASK_CANCEL_OR_RETURN_TWICE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_TASK_CANCEL_OR_RETURN_TWICE.value
82 # subtask.cancel invoked after the subtask already finished.
83 SUBTASK_CANCEL_AFTER_TERMINAL = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_SUBTASK_CANCEL_AFTER_TERMINAL.value
84 # task.return invoked with an invalid type.
85 TASK_RETURN_INVALID = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_TASK_RETURN_INVALID.value
86 # waitable-set.drop invoked on a waitable set with waiters.
87 WAITABLE_SET_DROP_HAS_WAITERS = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_WAITABLE_SET_DROP_HAS_WAITERS.value
88 # subtask.drop invoked on a subtask that hasn't resolved yet.
89 SUBTASK_DROP_NOT_RESOLVED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_SUBTASK_DROP_NOT_RESOLVED.value
90 # thread.new-indirect invoked with a function that has an invalid type.
91 THREAD_NEW_INDIRECT_INVALID_TYPE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_THREAD_NEW_INDIRECT_INVALID_TYPE.value
92 # thread.new-indirect invoked with an uninitialized function reference.
93 THREAD_NEW_INDIRECT_UNINITIALIZED = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_THREAD_NEW_INDIRECT_UNINITIALIZED.value
94 # Backpressure-related intrinsics overflowed the built-in counter.
95 BACKPRESSURE_OVERFLOW = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_BACKPRESSURE_OVERFLOW.value
96 # Invalid code returned from the callback of an async-lifted function.
97 UNSUPPORTED_CALLBACK_CODE = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_UNSUPPORTED_CALLBACK_CODE.value
98 # Cannot resume a thread which is not suspended.
99 CANNOT_RESUME_THREAD = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CANNOT_RESUME_THREAD.value
100 # Cannot issue a read/write on a future/stream while there is a pending operation.
101 CONCURRENT_FUTURE_STREAM_OP = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_CONCURRENT_FUTURE_STREAM_OP.value
102 # A reference count overflowed the built-in counter.
103 REFERENCE_COUNT_OVERFLOW = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_REFERENCE_COUNT_OVERFLOW.value
104 # A stream operation was performed with a buffer that was too large.
105 STREAM_OP_TOO_BIG = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_STREAM_OP_TOO_BIG.value
106 # A waitable was used both synchronously and asynchronously.
107 WAITABLE_SYNC_AND_ASYNC = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_WAITABLE_SYNC_AND_ASYNC.value
108 # An exception was thrown and never caught.
109 UNCAUGHT_EXCEPTION = ffi.wasmtime_trap_code_enum.WASMTIME_TRAP_CODE_UNCAUGHT_EXCEPTION.value
112class Trap(Exception, Managed["ctypes._Pointer[ffi.wasm_trap_t]"]):
114 def __init__(self, message: str):
115 """
116 Creates a new trap with the given `message`
117 """
119 vec = message.encode('utf-8')
120 self._set_ptr(ffi.wasmtime_trap_new(ctypes.create_string_buffer(vec), len(vec)))
122 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_trap_t]") -> None:
123 ffi.wasm_trap_delete(ptr)
125 @classmethod
126 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_trap_t]") -> "Trap":
127 if not isinstance(ptr, POINTER(ffi.wasm_trap_t)):
128 raise TypeError("wrong pointer type")
129 trap: Trap = cls.__new__(cls)
130 trap._set_ptr(ptr)
131 return trap
133 @property
134 def message(self) -> str:
135 """
136 Returns the message for this trap
137 """
139 message = ffi.wasm_byte_vec_t()
140 ffi.wasm_trap_message(self.ptr(), byref(message))
141 # subtract one to chop off the trailing nul byte
142 message.size -= 1
143 ret = ffi.to_str(message)
144 message.size += 1
145 ffi.wasm_byte_vec_delete(byref(message))
146 return ret
148 @property
149 def frames(self) -> List["Frame"]:
150 frames = FrameList(self)
151 ffi.wasm_trap_trace(self.ptr(), byref(frames.vec))
152 ret = []
153 for i in range(0, frames.vec.size):
154 ret.append(Frame._from_ptr(frames.vec.data[i], frames))
155 return ret
157 @property
158 def trap_code(self) -> Optional[TrapCode]:
159 """
160 Returns an optional `TrapCode` that corresponds to why this trap
161 happened.
163 Note that `None` may be returned for manually created traps which do
164 not have an associated code with them.
165 """
166 code = ffi.wasmtime_trap_code_t()
167 if ffi.wasmtime_trap_code(self.ptr(), byref(code)):
168 return TrapCode(code.value)
169 return None
171 def __str__(self) -> str:
172 return self.message
175class Frame(Managed["ctypes._Pointer[ffi.wasm_frame_t]"]):
176 _owner: Optional[Any]
178 @classmethod
179 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_frame_t]", owner: Optional[Any]) -> "Frame":
180 if not isinstance(ptr, POINTER(ffi.wasm_frame_t)):
181 raise TypeError("wrong pointer type")
182 ty: "Frame" = cls.__new__(cls)
183 ty._set_ptr(ptr)
184 ty._owner = owner
185 return ty
187 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_frame_t]") -> None:
188 if self._owner is None:
189 ffi.wasm_frame_delete(ptr)
191 @property
192 def func_index(self) -> int:
193 """
194 Returns the function index this frame corresponds to in its wasm module
195 """
197 return ffi.wasm_frame_func_index(self.ptr())
199 @property
200 def func_name(self) -> Optional[str]:
201 """
202 Returns the name of the function this frame corresponds to
204 May return `None` if no name can be inferred
205 """
207 ptr = ffi.wasmtime_frame_func_name(self.ptr())
208 if ptr:
209 return ffi.to_str(ptr.contents)
210 else:
211 return None
213 @property
214 def module_name(self) -> Optional[str]:
215 """
216 Returns the name of the module this frame corresponds to
218 May return `None` if no name can be inferred
219 """
221 ptr = ffi.wasmtime_frame_module_name(self.ptr())
222 if ptr:
223 return ffi.to_str(ptr.contents)
224 else:
225 return None
227 @property
228 def module_offset(self) -> int:
229 """
230 Returns the offset of this frame's program counter into the original
231 wasm source module.
232 """
234 return ffi.wasm_frame_module_offset(self.ptr())
236 @property
237 def func_offset(self) -> int:
238 """
239 Returns the offset of this frame's program counter into the original
240 wasm function.
241 """
243 return ffi.wasm_frame_func_offset(self.ptr())
246class FrameList:
247 owner: Any
249 def __init__(self, owner: Any) -> None:
250 self.vec = ffi.wasm_frame_vec_t(0, None)
251 self.owner = owner
253 def __del__(self) -> None:
254 ffi.wasm_frame_vec_delete(byref(self.vec))