xref: /wasmtime-44.0.1/crates/c-api/src/trap.rs (revision cccc4e64)
1 use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
2 use anyhow::{anyhow, Error};
3 use std::cell::OnceCell;
4 use wasmtime::{Trap, WasmBacktrace};
5 
6 #[repr(C)]
7 pub 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.
15 impl 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 
23 wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
24 
25 impl 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)]
33 pub 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 
40 wasmtime_c_api_macros::declare_own!(wasm_frame_t);
41 
42 pub type wasm_message_t = wasm_name_t;
43 
44 #[unsafe(no_mangle)]
45 pub 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)]
60 pub 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)]
69 pub 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)]
78 pub 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)]
96 pub 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 
100 pub(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)]
119 pub 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)]
144 pub 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)]
149 pub 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)]
163 pub 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)]
178 pub 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)]
185 pub 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)]
190 pub 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)]
197 pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> {
198     Box::new(frame.clone())
199 }
200