WebAssembly Traps
WebAssembly traps are runtime exceptions that occur during WebAssembly execution when the program encounters an unrecoverable error. WasmtimeRuntime.jl provides the WasmTrap
type to handle these exceptional conditions.
WasmTrap Overview
WasmTrap
represents a WebAssembly trap - a runtime error that immediately terminates execution of the WebAssembly program. Traps are distinct from regular Julia exceptions in that they originate from the WebAssembly runtime itself.
struct WasmTrap <: Exception
ptr::Ptr{LibWasmtime.wasm_trap_t}
msg::AbstractString
end
Creating WasmTrap Instances
Traps are typically created automatically by the WebAssembly runtime, but you can also create them from existing trap pointers:
# From a C pointer (internal use)
# trap_ptr <--- Assume this is a valid pointer to a wasm_trap_t object
trap = WasmTrap(trap_ptr)
# The trap message is automatically extracted
println(trap.msg) # "integer divide by zero"
Common Trap Scenarios
Division by Zero
wasm_code = wat"""
(module
(func (export "divide") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.div_s))
"""
engine = Engine()
store = Store(engine)
module_obj = WasmModule(engine, wat2wasm(wasm_code))
instance = Instance(store, module_obj)
try
# This will trap due to division by zero
result = call(instance, "divide", [10, 0])
catch trap::WasmTrap
println("Caught trap: $(trap.msg)")
# Output: "Caught trap: integer divide by zero"
end
Memory Access Out of Bounds
wasm_code = wat"""
(module
(memory (export "memory") 1)
(func (export "load") (param i32) (result i32)
local.get 0
i32.load))
"""
engine = Engine()
store = Store(engine)
module_obj = WasmModule(engine, wat2wasm(wasm_code))
instance = Instance(store, module_obj)
try
# This will trap due to out-of-bounds memory access
result = call(instance, "load", [100000]) # Beyond memory bounds
catch trap::WasmTrap
println("Memory access trap: $(trap.msg)")
# Output: "Memory access trap: out of bounds memory access"
end
Stack Overflow
wasm_code = wat"""
(module
(func (export "recurse") (param i32) (result i32)
local.get 0
i32.const 1
i32.sub
local.tee 0
i32.const 0
i32.gt_s
if (result i32)
local.get 0
call 0 ; recursive call
else
local.get 0
end))
"""
engine = Engine()
store = Store(engine)
module_obj = WasmModule(engine, wat2wasm(wasm_code))
instance = Instance(store, module_obj)
try
# This will trap due to stack overflow
result = call(instance, "recurse", [10000])
catch trap::WasmTrap
println("Stack overflow trap: $(trap.msg)")
# Output: "Stack overflow trap: call stack exhausted"
end
Integer Overflow
wasm_code = wat"""
(module
(func (export "overflow") (param i32) (result i32)
local.get 0
i32.const -1
i32.div_s))
"""
engine = Engine()
store = Store(engine)
module_obj = WasmModule(engine, wat2wasm(wasm_code))
instance = Instance(store, module_obj)
try
# This will trap due to integer overflow
result = call(instance, "overflow", [typemin(Int32)])
catch trap::WasmTrap
println("Overflow trap: $(trap.msg)")
# Output: "Overflow trap: integer overflow"
end
Trap Handling Patterns
Basic Trap Handling
function safe_wasm_call(instance, func_name, params)
try
return call(instance, func_name, params)
catch trap::WasmTrap
@warn "WebAssembly trap occurred" function=func_name message=trap.msg
return nothing
end
end
Specific Trap Type Handling
function handle_specific_traps(instance, func_name, params)
try
return call(instance, func_name, params)
catch trap::WasmTrap
msg = lowercase(trap.msg)
if occursin("divide by zero", msg)
@warn "Division by zero detected, returning zero"
return 0
elseif occursin("out of bounds", msg)
@error "Memory access violation" function=func_name params=params
rethrow(trap)
elseif occursin("stack exhausted", msg)
@error "Stack overflow detected" function=func_name
rethrow(trap)
else
@error "Unknown trap type" message=trap.msg
rethrow(trap)
end
end
end
Trap Recovery with Fallback
function call_with_fallback(instance, primary_func, fallback_func, params)
try
return call(instance, primary_func, params)
catch trap::WasmTrap
@warn "Primary function trapped, trying fallback"
primary=primary_func fallback=fallback_func message=trap.msg
try
return call(instance, fallback_func, params)
catch fallback_trap::WasmTrap
@error "Both primary and fallback functions trapped"
primary_trap=trap.msg fallback_trap=fallback_trap.msg
rethrow(trap) # Rethrow original trap
end
end
end
WasmTrap API Reference
Fields
ptr::Ptr{LibWasmtime.wasm_trap_t}
- Raw pointer to the underlying C trap objectmsg::AbstractString
- Human-readable trap message
Methods
Constructors
WasmTrap(ptr::Ptr{LibWasmtime.wasm_trap_t})
Creates a WasmTrap
from a C pointer, automatically extracting the trap message.
Comparison Operations
trap1 == trap2 # Compare two traps
trap == ptr # Compare trap with C pointer
trap != other_trap # Inequality comparison
Utility Functions
Base.isvalid(trap) # Check if trap pointer is valid
Base.show(io, trap) # Display trap information
Base.showerror(io, trap) # Display trap as error
Conversion Functions
Base.unsafe_convert(::Type{WasmTrap}, ptr)
Base.unsafe_convert(::Type{Ptr{LibWasmtime.wasm_trap_t}}, trap)
Best Practices
1. Always Handle Traps
WebAssembly traps should always be handled, as they represent runtime errors:
# ✅ Good - Handle traps appropriately
try
result = call(instance, "risky_function", params)
return result
catch trap::WasmTrap
@error "Function trapped" message=trap.msg
return default_value
end
# ❌ Bad - Ignore potential traps
result = call(instance, "risky_function", params) # May throw unhandled trap
2. Log Trap Information
Include trap messages in logs for debugging:
# ✅ Good - Include trap context
catch trap::WasmTrap
@error "WebAssembly trap occurred"
func=func_name
params=params
message=trap.msg
stack_trace=stacktrace()
end
3. Validate Inputs
Prevent common traps by validating inputs:
function safe_divide(instance, a, b)
if b == 0
@warn "Division by zero prevented"
return 0
end
return call(instance, "divide", [a, b])
end
4. Use Appropriate Error Recovery
Choose recovery strategies based on trap type:
function adaptive_trap_handling(instance, func_name, params)
try
return call(instance, func_name, params)
catch trap::WasmTrap
msg = lowercase(trap.msg)
# Recoverable errors
if occursin("divide by zero", msg)
return 0 # Safe default
end
# Non-recoverable errors
if occursin("out of bounds", msg) || occursin("stack exhausted", msg)
rethrow(trap) # Let caller handle
end
# Unknown traps
@error "Unknown trap type, rethrowing" message=trap.msg
rethrow(trap)
end
end
Performance Considerations
Trap Overhead
Catching traps has minimal overhead, but creating trap objects involves:
- Message extraction from C runtime
- String allocation for the message
- Julia object creation
Avoiding Traps
The best performance strategy is preventing traps:
# ✅ Prevent traps when possible
function optimized_divide(instance, a, b)
if b == 0
return 0 # Avoid trap entirely
end
return call(instance, "divide", [a, b])
end
# ❌ Rely on trap handling
function slow_divide(instance, a, b)
try
return call(instance, "divide", [a, b])
catch trap::WasmTrap
return 0 # Trap handling is slower
end
end
Common Pitfalls
1. Ignoring Trap Messages
# ❌ Bad - Ignore valuable trap information
catch trap::WasmTrap
return nothing # Lost debugging information
end
# ✅ Good - Log trap details
catch trap::WasmTrap
@error "Trap occurred" message=trap.msg
return nothing
end
2. Incorrect Trap Classification
# ❌ Bad - Overly broad trap handling
catch trap::WasmTrap
return default_value # May mask serious errors
end
# ✅ Good - Specific trap handling
catch trap::WasmTrap
if occursin("divide by zero", trap.msg)
return 0 # Safe recovery
else
rethrow(trap) # Don't mask other errors
end
end
Summary
WasmTrap
provides robust handling for WebAssembly runtime errors. Key points:
- Traps represent unrecoverable WebAssembly runtime errors
- Always handle traps appropriately in production code
- Use trap messages for debugging and error analysis
- Implement appropriate recovery strategies based on trap type
- Prefer preventing traps over handling them when possible
- Log trap information for debugging and monitoring
Understanding and properly handling WebAssembly traps is essential for building robust applications with WasmtimeRuntime.jl.