Skip to main content

wasmtime_c_api/
trap.rs

1use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
2use std::cell::OnceCell;
3use wasmtime::{Error, Trap, WasmBacktrace, format_err};
4
5// Help ensure the Rust enum matches the C one.  If any of these assertions
6// fail, please update both this code and `trap.h` to sync them with
7// `trap_encoding.rs`.
8const _: () = {
9    assert!(Trap::StackOverflow as u8 == 0);
10    assert!(Trap::MemoryOutOfBounds as u8 == 1);
11    assert!(Trap::HeapMisaligned as u8 == 2);
12    assert!(Trap::TableOutOfBounds as u8 == 3);
13    assert!(Trap::IndirectCallToNull as u8 == 4);
14    assert!(Trap::BadSignature as u8 == 5);
15    assert!(Trap::IntegerOverflow as u8 == 6);
16    assert!(Trap::IntegerDivisionByZero as u8 == 7);
17    assert!(Trap::BadConversionToInteger as u8 == 8);
18    assert!(Trap::UnreachableCodeReached as u8 == 9);
19    assert!(Trap::Interrupt as u8 == 10);
20    assert!(Trap::OutOfFuel as u8 == 11);
21    assert!(Trap::AtomicWaitNonSharedMemory as u8 == 12);
22    assert!(Trap::NullReference as u8 == 13);
23    assert!(Trap::ArrayOutOfBounds as u8 == 14);
24    assert!(Trap::AllocationTooLarge as u8 == 15);
25    assert!(Trap::CastFailure as u8 == 16);
26    assert!(Trap::CannotEnterComponent as u8 == 17);
27    assert!(Trap::NoAsyncResult as u8 == 18);
28    assert!(Trap::UnhandledTag as u8 == 19);
29    assert!(Trap::ContinuationAlreadyConsumed as u8 == 20);
30    assert!(Trap::DisabledOpcode as u8 == 21);
31    assert!(Trap::AsyncDeadlock as u8 == 22);
32    assert!(Trap::CannotLeaveComponent as u8 == 23);
33    assert!(Trap::CannotBlockSyncTask as u8 == 24);
34    assert!(Trap::InvalidChar as u8 == 25);
35    assert!(Trap::DebugAssertStringEncodingFinished as u8 == 26);
36    assert!(Trap::DebugAssertEqualCodeUnits as u8 == 27);
37    assert!(Trap::DebugAssertPointerAligned as u8 == 28);
38    assert!(Trap::DebugAssertUpperBitsUnset as u8 == 29);
39    assert!(Trap::StringOutOfBounds as u8 == 30);
40    assert!(Trap::ListOutOfBounds as u8 == 31);
41    assert!(Trap::InvalidDiscriminant as u8 == 32);
42    assert!(Trap::UnalignedPointer as u8 == 33);
43};
44
45#[repr(C)]
46pub struct wasm_trap_t {
47    pub(crate) error: Error,
48}
49
50// This is currently only needed for the `wasm_trap_copy` API in the C API.
51//
52// For now the impl here is "fake it til you make it" since this is losing
53// context by only cloning the error string.
54impl Clone for wasm_trap_t {
55    fn clone(&self) -> wasm_trap_t {
56        wasm_trap_t {
57            error: format_err!("{:?}", self.error),
58        }
59    }
60}
61
62wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
63
64impl wasm_trap_t {
65    pub(crate) fn new(error: Error) -> wasm_trap_t {
66        wasm_trap_t { error }
67    }
68}
69
70#[repr(C)]
71#[derive(Clone)]
72pub struct wasm_frame_t<'a> {
73    trace: &'a WasmBacktrace,
74    idx: usize,
75    func_name: OnceCell<Option<wasm_name_t>>,
76    module_name: OnceCell<Option<wasm_name_t>>,
77}
78
79wasmtime_c_api_macros::declare_own!(wasm_frame_t);
80
81pub type wasm_message_t = wasm_name_t;
82
83#[unsafe(no_mangle)]
84pub extern "C" fn wasm_trap_new(
85    _store: &wasm_store_t,
86    message: &wasm_message_t,
87) -> Box<wasm_trap_t> {
88    let message = message.as_slice();
89    if message[message.len() - 1] != 0 {
90        panic!("wasm_trap_new message stringz expected");
91    }
92    let message = String::from_utf8_lossy(&message[..message.len() - 1]);
93    Box::new(wasm_trap_t {
94        error: Error::msg(message.into_owned()),
95    })
96}
97
98#[unsafe(no_mangle)]
99pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Box<wasm_trap_t> {
100    let bytes = crate::slice_from_raw_parts(message, len);
101    let message = String::from_utf8_lossy(&bytes);
102    Box::new(wasm_trap_t {
103        error: Error::msg(message.into_owned()),
104    })
105}
106
107#[unsafe(no_mangle)]
108pub unsafe extern "C" fn wasmtime_trap_new_code(code: u8) -> Box<wasm_trap_t> {
109    let trap = Trap::from_u8(code).unwrap();
110    Box::new(wasm_trap_t {
111        error: Error::new(trap),
112    })
113}
114
115#[unsafe(no_mangle)]
116pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) {
117    let mut buffer = Vec::new();
118    buffer.extend_from_slice(format!("{:?}", trap.error).as_bytes());
119    buffer.reserve_exact(1);
120    buffer.push(0);
121    out.set_buffer(buffer);
122}
123
124#[unsafe(no_mangle)]
125pub extern "C" fn wasm_trap_origin(raw: &wasm_trap_t) -> Option<Box<wasm_frame_t<'_>>> {
126    let trace = match raw.error.downcast_ref::<WasmBacktrace>() {
127        Some(trap) => trap,
128        None => return None,
129    };
130    if trace.frames().len() > 0 {
131        Some(Box::new(wasm_frame_t {
132            trace,
133            idx: 0,
134            func_name: OnceCell::new(),
135            module_name: OnceCell::new(),
136        }))
137    } else {
138        None
139    }
140}
141
142#[unsafe(no_mangle)]
143pub extern "C" fn wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>) {
144    error_trace(&raw.error, out)
145}
146
147pub(crate) fn error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>) {
148    let trace = match error.downcast_ref::<WasmBacktrace>() {
149        Some(trap) => trap,
150        None => return out.set_buffer(Vec::new()),
151    };
152    let vec = (0..trace.frames().len())
153        .map(|idx| {
154            Some(Box::new(wasm_frame_t {
155                trace,
156                idx,
157                func_name: OnceCell::new(),
158                module_name: OnceCell::new(),
159            }))
160        })
161        .collect();
162    out.set_buffer(vec);
163}
164
165#[unsafe(no_mangle)]
166pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool {
167    let trap = match raw.error.downcast_ref::<Trap>() {
168        Some(trap) => trap,
169        None => return false,
170    };
171    *code = *trap as u8;
172    true
173}
174
175#[unsafe(no_mangle)]
176pub extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32 {
177    frame.trace.frames()[frame.idx].func_index()
178}
179
180#[unsafe(no_mangle)]
181pub extern "C" fn wasmtime_frame_func_name<'a>(
182    frame: &'a wasm_frame_t<'_>,
183) -> Option<&'a wasm_name_t> {
184    frame
185        .func_name
186        .get_or_init(|| {
187            frame.trace.frames()[frame.idx]
188                .func_name()
189                .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
190        })
191        .as_ref()
192}
193
194#[unsafe(no_mangle)]
195pub extern "C" fn wasmtime_frame_module_name<'a>(
196    frame: &'a wasm_frame_t<'_>,
197) -> Option<&'a wasm_name_t> {
198    frame
199        .module_name
200        .get_or_init(|| {
201            frame.trace.frames()[frame.idx]
202                .module()
203                .name()
204                .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
205        })
206        .as_ref()
207}
208
209#[unsafe(no_mangle)]
210pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize {
211    frame.trace.frames()[frame.idx]
212        .func_offset()
213        .unwrap_or(usize::MAX)
214}
215
216#[unsafe(no_mangle)]
217pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t {
218    unimplemented!("wasm_frame_instance")
219}
220
221#[unsafe(no_mangle)]
222pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize {
223    frame.trace.frames()[frame.idx]
224        .module_offset()
225        .unwrap_or(usize::MAX)
226}
227
228#[unsafe(no_mangle)]
229pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> {
230    Box::new(frame.clone())
231}