Skip to main content

wasmparser/
error.rs

1use core::fmt;
2
3use crate::WasmFeatures;
4use crate::prelude::*;
5
6/// A binary reader for WebAssembly modules.
7#[derive(Debug, Clone)]
8pub struct Error {
9    // Wrap the actual error data in a `Box` so that the error is just one
10    // word. This means that we can continue returning small `Result`s in
11    // registers.
12    pub(crate) inner: Box<ErrorInner>,
13}
14
15#[derive(Debug, Clone)]
16pub(crate) struct ErrorInner {
17    message: String,
18    kind: ErrorKind,
19    offset: u64,
20    needed_hint: Option<usize>,
21}
22
23#[derive(Debug, Clone, Copy)]
24pub(crate) enum ErrorKind {
25    Uncategorized,
26    InvalidHeapType,
27    WasmFeature(WasmFeatures),
28}
29
30/// The result for `BinaryReader` operations.
31pub type Result<T, E = Error> = core::result::Result<T, E>;
32
33impl core::error::Error for Error {}
34
35impl fmt::Display for Error {
36    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37        write!(
38            f,
39            "{} (at offset 0x{:x})",
40            self.inner.message, self.inner.offset
41        )
42    }
43}
44
45impl Error {
46    #[cold]
47    pub(crate) fn _new(kind: ErrorKind, message: String, offset: u64) -> Self {
48        Error {
49            inner: Box::new(ErrorInner {
50                kind,
51                message,
52                offset,
53                needed_hint: None,
54            }),
55        }
56    }
57
58    #[cold]
59    pub(crate) fn new(message: impl Into<String>, offset: u64) -> Self {
60        Self::_new(ErrorKind::Uncategorized, message.into(), offset)
61    }
62
63    #[cold]
64    pub(crate) fn invalid_heap_type(msg: &'static str, offset: u64) -> Self {
65        Self::_new(ErrorKind::InvalidHeapType, msg.into(), offset)
66    }
67
68    #[cold]
69    pub(crate) fn wasm_feature(
70        feature: crate::WasmFeatures,
71        msg: impl fmt::Display,
72        offset: u64,
73    ) -> Self {
74        Self::_new(ErrorKind::WasmFeature(feature), msg.to_string(), offset)
75    }
76
77    #[cold]
78    pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: u64) -> Self {
79        Error::new(args.to_string(), offset)
80    }
81
82    #[cold]
83    pub(crate) fn eof(offset: u64, needed_hint: usize) -> Self {
84        let mut err = Error::new("unexpected end-of-file", offset);
85        err.inner.needed_hint = Some(needed_hint);
86        err
87    }
88
89    pub(crate) fn kind(&self) -> ErrorKind {
90        self.inner.kind
91    }
92
93    /// Get this error's message.
94    pub fn message(&self) -> &str {
95        &self.inner.message
96    }
97
98    /// Get the offset within the Wasm binary where the error occurred.
99    pub fn offset(&self) -> u64 {
100        self.inner.offset
101    }
102
103    /// Returns `Some` if this error is due to a disabled Wasm feature.
104    ///
105    /// If the `features` crate feature is enabled, a returned [`WasmFeatures`]
106    /// will contain a feature that could be enabled to prevent this error.
107    ///
108    /// **Note:** This is not comprehensive; `None` may be returned in some
109    /// cases where enabling a feature could avoid the error.
110    pub fn missing_wasm_feature(&self) -> Option<WasmFeatures> {
111        match self.inner.kind {
112            ErrorKind::WasmFeature(features) => Some(features),
113            _ => None,
114        }
115    }
116
117    #[cfg(all(feature = "validate", feature = "component-model"))]
118    pub(crate) fn add_context(&mut self, context: String) {
119        self.inner.message = format!("{context}\n{}", self.inner.message);
120    }
121
122    pub(crate) fn set_message(&mut self, message: impl Into<String>) {
123        self.inner.message = message.into();
124    }
125
126    pub(crate) fn needed_hint(&self) -> Option<usize> {
127        self.inner.needed_hint
128    }
129
130    pub(crate) fn without_needed_hint(mut self) -> Self {
131        self.inner.needed_hint = None;
132        self
133    }
134}