1use std::sync::Arc;
2use thiserror::Error;
3use wasmer_types::{FrameInfo, ImportError, TrapCode};
4
5use crate::{AsStoreMut, AsStoreRef, BackendTrap as Trap, Exception, Value};
6
7pub use wasmer_types::error::AtomicsError;
10
11#[derive(Debug, Clone)]
18#[cfg_attr(feature = "std", derive(Error))]
19#[cfg_attr(feature = "std", error("Link error: {0}"))]
20pub enum LinkError {
21 #[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))]
23 Import(String, String, ImportError),
24
25 #[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))]
27 Trap(#[cfg_attr(feature = "std", source)] RuntimeError),
28 #[cfg_attr(feature = "std", error("Insufficient resources: {0}"))]
30 Resource(String),
31}
32
33#[derive(Debug, Clone)]
42#[cfg_attr(feature = "std", derive(Error))]
43pub enum InstantiationError {
44 #[cfg_attr(feature = "std", error(transparent))]
46 Link(LinkError),
47
48 #[cfg_attr(feature = "std", error(transparent))]
50 Start(RuntimeError),
51
52 #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))]
55 CpuFeature(String),
56
57 #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))]
60 DifferentStores,
61
62 #[cfg_attr(feature = "std", error("incorrect OS or architecture"))]
65 DifferentArchOS,
66}
67
68#[derive(Clone)]
71pub struct RuntimeError {
72 pub(crate) inner: Arc<RuntimeErrorInner>,
73}
74
75#[derive(Debug)]
76struct RuntimeStringError {
77 details: String,
78}
79
80impl RuntimeStringError {
81 fn new(msg: String) -> Self {
82 Self { details: msg }
83 }
84}
85
86impl std::fmt::Display for RuntimeStringError {
87 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88 write!(f, "{}", self.details)
89 }
90}
91
92impl std::error::Error for RuntimeStringError {
93 fn description(&self) -> &str {
94 &self.details
95 }
96}
97
98pub(crate) struct RuntimeErrorInner {
99 pub(crate) source: Trap,
101 trap_code: Option<TrapCode>,
103 wasm_trace: Vec<FrameInfo>,
105}
106
107impl RuntimeError {
108 pub fn new<I: Into<String>>(message: I) -> Self {
116 let msg = message.into();
117 let source = RuntimeStringError::new(msg);
118 Self::user(Box::new(source))
119 }
120
121 pub fn new_from_source(
136 source: Trap,
137 wasm_trace: Vec<FrameInfo>,
138 trap_code: Option<TrapCode>,
139 ) -> Self {
140 Self {
141 inner: Arc::new(RuntimeErrorInner {
142 source,
143 wasm_trace,
144 trap_code,
145 }),
146 }
147 }
148
149 pub fn user(error: Box<dyn std::error::Error + Send + Sync>) -> Self {
154 match error.downcast::<Self>() {
155 Ok(err) => *err,
156 Err(error) => error.into(),
157 }
158 }
159
160 pub fn exception(ctx: &impl AsStoreRef, exception: Exception) -> Self {
165 let exnref = exception.vm_exceptionref();
166 let store = ctx.as_store_ref();
167 match store.inner.objects {
168 #[cfg(feature = "sys")]
169 crate::StoreObjects::Sys(ref store_objects) => {
170 crate::backend::sys::vm::Trap::uncaught_exception(
171 exnref.unwrap_sys_ref().clone(),
172 store_objects,
173 )
174 .into()
175 }
176 _ => panic!("exceptions are only supported in the `sys` backend"),
177 }
178 }
179
180 pub fn message(&self) -> String {
182 if let Some(trap_code) = self.inner.trap_code {
183 trap_code.message().to_string()
184 } else {
185 self.inner.source.to_string()
186 }
187 }
188
189 pub fn trace(&self) -> &[FrameInfo] {
192 &self.inner.wasm_trace
193 }
194
195 pub fn to_trap(self) -> Option<TrapCode> {
197 self.inner.trap_code
198 }
199
200 pub fn downcast<T: std::error::Error + 'static>(self) -> Result<T, Self> {
207 match Arc::try_unwrap(self.inner) {
208 Ok(inner) if inner.source.is::<T>() => Ok(inner.source.downcast::<T>().unwrap()),
209 Ok(inner) => Err(Self {
210 inner: Arc::new(inner),
211 }),
212 Err(inner) => Err(Self { inner }),
213 }
214 }
215
216 pub fn downcast_ref<T: std::error::Error + 'static>(&self) -> Option<&T> {
218 self.inner.as_ref().source.downcast_ref::<T>()
219 }
220
221 pub fn is<T: std::error::Error + 'static>(&self) -> bool {
223 self.inner.source.is::<T>()
224 }
225
226 pub fn is_exception(&self) -> bool {
228 self.inner.source.is_exception()
229 }
230
231 pub fn to_exception(&self) -> Option<Exception> {
233 self.inner.source.to_exception()
234 }
235
236 pub fn display<'a>(&'a self, store: &'a mut impl AsStoreMut) -> RuntimeErrorDisplay<'a> {
238 if let Some(exception) = self.to_exception() {
239 RuntimeErrorDisplay::Exception(exception.payload(store), self.trace())
240 } else {
241 RuntimeErrorDisplay::Other(self)
242 }
243 }
244
245 pub fn write_trace(trace: &[FrameInfo], f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247 if trace.is_empty() {
248 return Ok(());
249 }
250 for frame in trace.iter() {
251 let name = frame.module_name();
252 let func_index = frame.func_index();
253 writeln!(f)?;
254 write!(f, " at ")?;
255 match frame.function_name() {
256 Some(name) => {
257 #[cfg(feature = "demangle")]
258 write!(f, "{}", symbolic_demangle::demangle(name))?;
259 #[cfg(not(feature = "demangle"))]
260 write!(f, "{name}")?;
261 }
262 None => write!(f, "<unnamed>")?,
263 }
264 write!(
265 f,
266 " ({}[{}]:0x{:x})",
267 name,
268 func_index,
269 frame.module_offset()
270 )?;
271 }
272 Ok(())
273 }
274
275 pub(crate) fn from_dyn(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
276 match err.downcast::<Self>() {
277 Ok(runtime_error) => *runtime_error,
278 Err(error) => Trap::user(error),
279 }
280 }
281}
282
283impl std::fmt::Debug for RuntimeError {
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 f.debug_struct("RuntimeError")
286 .field("source", &self.inner.source)
287 .field("wasm_trace", &self.inner.wasm_trace)
288 .finish()
289 }
290}
291
292impl std::fmt::Display for RuntimeError {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294 write!(f, "RuntimeError: {}", self.message())?;
295 Self::write_trace(self.trace(), f)
296 }
297}
298
299pub enum RuntimeErrorDisplay<'a> {
301 Exception(Vec<Value>, &'a [FrameInfo]),
303 Other(&'a RuntimeError),
305}
306
307impl std::fmt::Display for RuntimeErrorDisplay<'_> {
308 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309 match self {
310 RuntimeErrorDisplay::Exception(payload, trace) => {
311 write!(f, "Uncaught exception")?;
312 if !payload.is_empty() {
313 write!(f, " with payload: {payload:?}")?;
314 }
315 RuntimeError::write_trace(trace, f)
316 }
317 RuntimeErrorDisplay::Other(err) => write!(f, "{err}"),
318 }
319 }
320}
321
322impl std::error::Error for RuntimeError {
323 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
324 self.inner.source.source()
325 }
326}
327
328impl From<Box<dyn std::error::Error + Send + Sync>> for RuntimeError {
329 fn from(error: Box<dyn std::error::Error + Send + Sync>) -> Self {
330 match error.downcast::<Self>() {
331 Ok(runtime_error) => *runtime_error,
333 Err(error) => Trap::user(error),
334 }
335 }
336}