wasmtime_c_api/
trap.rs

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