1#[cfg(feature = "js")]
2use crate::js::trap::Trap;
3#[cfg(feature = "jsc")]
4use crate::jsc::trap::Trap;
5use std::fmt;
6use std::sync::Arc;
7use thiserror::Error;
8use wasmer_types::{FrameInfo, TrapCode};
9#[cfg(feature = "sys")]
10use wasmer_vm::Trap;
11
12use wasmer_types::ImportError;
13
14#[derive(Debug, Clone)]
21#[cfg_attr(feature = "std", derive(Error))]
22#[cfg_attr(feature = "std", error("Link error: {0}"))]
23pub enum LinkError {
24 #[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))]
26 Import(String, String, ImportError),
27
28 #[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))]
30 Trap(#[source] RuntimeError),
31 #[cfg_attr(feature = "std", error("Insufficient resources: {0}"))]
33 Resource(String),
34}
35
36#[derive(Debug, Clone)]
45#[cfg_attr(feature = "std", derive(Error))]
46pub enum InstantiationError {
47 #[cfg_attr(feature = "std", error(transparent))]
49 Link(LinkError),
50
51 #[cfg_attr(feature = "std", error(transparent))]
53 Start(RuntimeError),
54
55 #[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))]
58 CpuFeature(String),
59
60 #[cfg_attr(feature = "std", error("cannot mix imports from different stores"))]
63 DifferentStores,
64
65 #[cfg_attr(feature = "std", error("incorrect OS or architecture"))]
68 DifferentArchOS,
69}
70
71#[derive(Clone)]
74pub struct RuntimeError {
75 pub(crate) inner: Arc<RuntimeErrorInner>,
76}
77
78#[derive(Debug)]
79struct RuntimeStringError {
80 details: String,
81}
82
83impl RuntimeStringError {
84 fn new(msg: String) -> Self {
85 Self { details: msg }
86 }
87}
88
89impl fmt::Display for RuntimeStringError {
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 write!(f, "{}", self.details)
92 }
93}
94
95impl std::error::Error for RuntimeStringError {
96 fn description(&self) -> &str {
97 &self.details
98 }
99}
100
101pub(crate) struct RuntimeErrorInner {
102 pub(crate) source: Trap,
104 trap_code: Option<TrapCode>,
106 wasm_trace: Vec<FrameInfo>,
108}
109
110impl RuntimeError {
111 pub fn new<I: Into<String>>(message: I) -> Self {
119 let msg = message.into();
120 let source = RuntimeStringError::new(msg);
121 Self::user(Box::new(source))
122 }
123
124 pub fn new_from_source(
139 source: Trap,
140 wasm_trace: Vec<FrameInfo>,
141 trap_code: Option<TrapCode>,
142 ) -> Self {
143 Self {
144 inner: Arc::new(RuntimeErrorInner {
145 source,
146 wasm_trace,
147 trap_code,
148 }),
149 }
150 }
151
152 pub fn user(error: Box<dyn std::error::Error + Send + Sync>) -> Self {
157 match error.downcast::<Self>() {
158 Ok(err) => *err,
159 Err(error) => error.into(),
160 }
161 }
162
163 pub fn message(&self) -> String {
165 if let Some(trap_code) = self.inner.trap_code {
166 trap_code.message().to_string()
167 } else {
168 self.inner.source.to_string()
169 }
170 }
171
172 pub fn trace(&self) -> &[FrameInfo] {
175 &self.inner.wasm_trace
176 }
177
178 pub fn to_trap(self) -> Option<TrapCode> {
180 self.inner.trap_code
181 }
182
183 pub fn downcast<T: std::error::Error + 'static>(self) -> Result<T, Self> {
190 match Arc::try_unwrap(self.inner) {
191 Ok(inner) if inner.source.is::<T>() => Ok(inner.source.downcast::<T>().unwrap()),
192 Ok(inner) => Err(Self {
193 inner: Arc::new(inner),
194 }),
195 Err(inner) => Err(Self { inner }),
196 }
197 }
198
199 pub fn downcast_ref<T: std::error::Error + 'static>(&self) -> Option<&T> {
201 self.inner.as_ref().source.downcast_ref::<T>()
202 }
203
204 pub fn is<T: std::error::Error + 'static>(&self) -> bool {
206 self.inner.source.is::<T>()
207 }
208}
209
210impl fmt::Debug for RuntimeError {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 f.debug_struct("RuntimeError")
213 .field("source", &self.inner.source)
214 .field("wasm_trace", &self.inner.wasm_trace)
215 .finish()
216 }
217}
218
219impl fmt::Display for RuntimeError {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 write!(f, "RuntimeError: {}", self.message())?;
222 let trace = self.trace();
223 if trace.is_empty() {
224 return Ok(());
225 }
226 for frame in self.trace().iter() {
227 let name = frame.module_name();
228 let func_index = frame.func_index();
229 writeln!(f)?;
230 write!(f, " at ")?;
231 match frame.function_name() {
232 Some(name) => match rustc_demangle::try_demangle(name) {
233 Ok(name) => write!(f, "{}", name)?,
234 Err(_) => write!(f, "{}", name)?,
235 },
236 None => write!(f, "<unnamed>")?,
237 }
238 write!(
239 f,
240 " ({}[{}]:0x{:x})",
241 name,
242 func_index,
243 frame.module_offset()
244 )?;
245 }
246 Ok(())
247 }
248}
249
250impl std::error::Error for RuntimeError {
251 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
252 self.inner.source.source()
253 }
254}
255
256impl From<Box<dyn std::error::Error + Send + Sync>> for RuntimeError {
257 fn from(error: Box<dyn std::error::Error + Send + Sync>) -> Self {
258 match error.downcast::<Self>() {
259 Ok(runtime_error) => *runtime_error,
261 Err(error) => Trap::user(error).into(),
262 }
263 }
264}
265
266#[derive(PartialEq, Eq, Debug, Error)]
269#[non_exhaustive]
270pub enum AtomicsError {
271 Unimplemented,
273 TooManyWaiters,
275 AtomicsDisabled,
277}
278
279impl std::fmt::Display for AtomicsError {
280 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281 match self {
282 Self::Unimplemented => write!(f, "Atomic operations are not supported"),
283 Self::TooManyWaiters => write!(f, "Too many waiters for address"),
284 Self::AtomicsDisabled => write!(f, "Atomic operations are disabled"),
285 }
286 }
287}