xref: /wasmtime-44.0.1/crates/c-api/src/trap.rs (revision f820750b)
1 use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
2 use std::cell::OnceCell;
3 use 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`.
8 const _: () = {
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     assert!(Trap::TaskCancelNotCancelled as u8 == 34);
44     assert!(Trap::TaskCancelOrReturnTwice as u8 == 35);
45     assert!(Trap::SubtaskCancelAfterTerminal as u8 == 36);
46     assert!(Trap::TaskReturnInvalid as u8 == 37);
47     assert!(Trap::WaitableSetDropHasWaiters as u8 == 38);
48     assert!(Trap::SubtaskDropNotResolved as u8 == 39);
49     assert!(Trap::ThreadNewIndirectInvalidType as u8 == 40);
50     assert!(Trap::ThreadNewIndirectUninitialized as u8 == 41);
51     assert!(Trap::BackpressureOverflow as u8 == 42);
52     assert!(Trap::UnsupportedCallbackCode as u8 == 43);
53     assert!(Trap::CannotResumeThread as u8 == 44);
54     assert!(Trap::ConcurrentFutureStreamOp as u8 == 45);
55 };
56 
57 #[repr(C)]
58 pub struct wasm_trap_t {
59     pub(crate) error: Error,
60 }
61 
62 // This is currently only needed for the `wasm_trap_copy` API in the C API.
63 //
64 // For now the impl here is "fake it til you make it" since this is losing
65 // context by only cloning the error string.
66 impl Clone for wasm_trap_t {
clone(&self) -> wasm_trap_t67     fn clone(&self) -> wasm_trap_t {
68         wasm_trap_t {
69             error: format_err!("{:?}", self.error),
70         }
71     }
72 }
73 
74 wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
75 
76 impl wasm_trap_t {
new(error: Error) -> wasm_trap_t77     pub(crate) fn new(error: Error) -> wasm_trap_t {
78         wasm_trap_t { error }
79     }
80 }
81 
82 #[repr(C)]
83 #[derive(Clone)]
84 pub struct wasm_frame_t<'a> {
85     trace: &'a WasmBacktrace,
86     idx: usize,
87     func_name: OnceCell<Option<wasm_name_t>>,
88     module_name: OnceCell<Option<wasm_name_t>>,
89 }
90 
91 wasmtime_c_api_macros::declare_own!(wasm_frame_t);
92 
93 pub type wasm_message_t = wasm_name_t;
94 
95 #[unsafe(no_mangle)]
wasm_trap_new( _store: &wasm_store_t, message: &wasm_message_t, ) -> Box<wasm_trap_t>96 pub extern "C" fn wasm_trap_new(
97     _store: &wasm_store_t,
98     message: &wasm_message_t,
99 ) -> Box<wasm_trap_t> {
100     let message = message.as_slice();
101     if message[message.len() - 1] != 0 {
102         panic!("wasm_trap_new message stringz expected");
103     }
104     let message = String::from_utf8_lossy(&message[..message.len() - 1]);
105     Box::new(wasm_trap_t {
106         error: Error::msg(message.into_owned()),
107     })
108 }
109 
110 #[unsafe(no_mangle)]
wasmtime_trap_new(message: *const u8, len: usize) -> Box<wasm_trap_t>111 pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Box<wasm_trap_t> {
112     let bytes = crate::slice_from_raw_parts(message, len);
113     let message = String::from_utf8_lossy(&bytes);
114     Box::new(wasm_trap_t {
115         error: Error::msg(message.into_owned()),
116     })
117 }
118 
119 #[unsafe(no_mangle)]
wasmtime_trap_new_code(code: u8) -> Box<wasm_trap_t>120 pub unsafe extern "C" fn wasmtime_trap_new_code(code: u8) -> Box<wasm_trap_t> {
121     let trap = Trap::from_u8(code).unwrap();
122     Box::new(wasm_trap_t {
123         error: Error::new(trap),
124     })
125 }
126 
127 #[unsafe(no_mangle)]
wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t)128 pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) {
129     let mut buffer = Vec::new();
130     buffer.extend_from_slice(format!("{:?}", trap.error).as_bytes());
131     buffer.reserve_exact(1);
132     buffer.push(0);
133     out.set_buffer(buffer);
134 }
135 
136 #[unsafe(no_mangle)]
wasm_trap_origin(raw: &wasm_trap_t) -> Option<Box<wasm_frame_t<'_>>>137 pub extern "C" fn wasm_trap_origin(raw: &wasm_trap_t) -> Option<Box<wasm_frame_t<'_>>> {
138     let trace = match raw.error.downcast_ref::<WasmBacktrace>() {
139         Some(trap) => trap,
140         None => return None,
141     };
142     if trace.frames().len() > 0 {
143         Some(Box::new(wasm_frame_t {
144             trace,
145             idx: 0,
146             func_name: OnceCell::new(),
147             module_name: OnceCell::new(),
148         }))
149     } else {
150         None
151     }
152 }
153 
154 #[unsafe(no_mangle)]
wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>)155 pub extern "C" fn wasm_trap_trace<'a>(raw: &'a wasm_trap_t, out: &mut wasm_frame_vec_t<'a>) {
156     error_trace(&raw.error, out)
157 }
158 
error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>)159 pub(crate) fn error_trace<'a>(error: &'a Error, out: &mut wasm_frame_vec_t<'a>) {
160     let trace = match error.downcast_ref::<WasmBacktrace>() {
161         Some(trap) => trap,
162         None => return out.set_buffer(Vec::new()),
163     };
164     let vec = (0..trace.frames().len())
165         .map(|idx| {
166             Some(Box::new(wasm_frame_t {
167                 trace,
168                 idx,
169                 func_name: OnceCell::new(),
170                 module_name: OnceCell::new(),
171             }))
172         })
173         .collect();
174     out.set_buffer(vec);
175 }
176 
177 #[unsafe(no_mangle)]
wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool178 pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool {
179     let trap = match raw.error.downcast_ref::<Trap>() {
180         Some(trap) => trap,
181         None => return false,
182     };
183     *code = *trap as u8;
184     true
185 }
186 
187 #[unsafe(no_mangle)]
wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32188 pub extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t<'_>) -> u32 {
189     frame.trace.frames()[frame.idx].func_index()
190 }
191 
192 #[unsafe(no_mangle)]
wasmtime_frame_func_name<'a>( frame: &'a wasm_frame_t<'_>, ) -> Option<&'a wasm_name_t>193 pub extern "C" fn wasmtime_frame_func_name<'a>(
194     frame: &'a wasm_frame_t<'_>,
195 ) -> Option<&'a wasm_name_t> {
196     frame
197         .func_name
198         .get_or_init(|| {
199             frame.trace.frames()[frame.idx]
200                 .func_name()
201                 .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
202         })
203         .as_ref()
204 }
205 
206 #[unsafe(no_mangle)]
wasmtime_frame_module_name<'a>( frame: &'a wasm_frame_t<'_>, ) -> Option<&'a wasm_name_t>207 pub extern "C" fn wasmtime_frame_module_name<'a>(
208     frame: &'a wasm_frame_t<'_>,
209 ) -> Option<&'a wasm_name_t> {
210     frame
211         .module_name
212         .get_or_init(|| {
213             frame.trace.frames()[frame.idx]
214                 .module()
215                 .name()
216                 .map(|s| wasm_name_t::from(s.to_string().into_bytes()))
217         })
218         .as_ref()
219 }
220 
221 #[unsafe(no_mangle)]
wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize222 pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t<'_>) -> usize {
223     frame.trace.frames()[frame.idx]
224         .func_offset()
225         .unwrap_or(usize::MAX)
226 }
227 
228 #[unsafe(no_mangle)]
wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t229 pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t<'_>) -> *mut wasm_instance_t {
230     unimplemented!("wasm_frame_instance")
231 }
232 
233 #[unsafe(no_mangle)]
wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize234 pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t<'_>) -> usize {
235     frame.trace.frames()[frame.idx]
236         .module_offset()
237         .unwrap_or(usize::MAX)
238 }
239 
240 #[unsafe(no_mangle)]
wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>>241 pub extern "C" fn wasm_frame_copy<'a>(frame: &wasm_frame_t<'a>) -> Box<wasm_frame_t<'a>> {
242     Box::new(frame.clone())
243 }
244