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) => write!(f, "{}", symbolic_demangle::demangle(name))?,
257 None => write!(f, "<unnamed>")?,
258 }
259 write!(
260 f,
261 " ({}[{}]:0x{:x})",
262 name,
263 func_index,
264 frame.module_offset()
265 )?;
266 }
267 Ok(())
268 }
269
270 pub(crate) fn from_dyn(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
271 match err.downcast::<Self>() {
272 Ok(runtime_error) => *runtime_error,
273 Err(error) => Trap::user(error),
274 }
275 }
276}
277
278impl std::fmt::Debug for RuntimeError {
279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280 f.debug_struct("RuntimeError")
281 .field("source", &self.inner.source)
282 .field("wasm_trace", &self.inner.wasm_trace)
283 .finish()
284 }
285}
286
287impl std::fmt::Display for RuntimeError {
288 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289 write!(f, "RuntimeError: {}", self.message())?;
290 Self::write_trace(self.trace(), f)
291 }
292}
293
294pub enum RuntimeErrorDisplay<'a> {
296 Exception(Vec<Value>, &'a [FrameInfo]),
298 Other(&'a RuntimeError),
300}
301
302impl std::fmt::Display for RuntimeErrorDisplay<'_> {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 match self {
305 RuntimeErrorDisplay::Exception(payload, trace) => {
306 write!(f, "Uncaught exception")?;
307 if !payload.is_empty() {
308 write!(f, " with payload: {payload:?}")?;
309 }
310 RuntimeError::write_trace(trace, f)
311 }
312 RuntimeErrorDisplay::Other(err) => write!(f, "{err}"),
313 }
314 }
315}
316
317impl std::error::Error for RuntimeError {
318 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
319 self.inner.source.source()
320 }
321}
322
323impl From<Box<dyn std::error::Error + Send + Sync>> for RuntimeError {
324 fn from(error: Box<dyn std::error::Error + Send + Sync>) -> Self {
325 match error.downcast::<Self>() {
326 Ok(runtime_error) => *runtime_error,
328 Err(error) => Trap::user(error),
329 }
330 }
331}