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