1use core::fmt;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct ByteOffset(pub usize);
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum DecodeContext {
19 Magic,
21 Version,
23 SectionHeader,
25 SectionBody { id: u8 },
27 Leb128,
29 TypeSection,
31 ImportSection,
33 FunctionSection,
35 TableSection,
37 GlobalSection,
39 MemorySection,
41 ExportSection,
43 StartSection,
45 ElementSection,
47 DataSection,
49 DataCountSection,
51 CodeSection,
53}
54
55impl fmt::Display for DecodeContext {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 match self {
58 DecodeContext::Magic => write!(f, "WASM magic number"),
59 DecodeContext::Version => write!(f, "WASM version"),
60 DecodeContext::SectionHeader => write!(f, "section header"),
61 DecodeContext::SectionBody { id } => write!(f, "section body (id={id})"),
62 DecodeContext::Leb128 => write!(f, "LEB128 value"),
63 DecodeContext::TypeSection => write!(f, "type section"),
64 DecodeContext::ImportSection => write!(f, "import section"),
65 DecodeContext::FunctionSection => write!(f, "function section"),
66 DecodeContext::TableSection => write!(f, "table section"),
67 DecodeContext::GlobalSection => write!(f, "global section"),
68 DecodeContext::MemorySection => write!(f, "memory section"),
69 DecodeContext::ExportSection => write!(f, "export section"),
70 DecodeContext::StartSection => write!(f, "start section"),
71 DecodeContext::ElementSection => write!(f, "element section"),
72 DecodeContext::DataSection => write!(f, "data section"),
73 DecodeContext::DataCountSection => write!(f, "data count section"),
74 DecodeContext::CodeSection => write!(f, "code section"),
75 }
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
81pub struct DecodeError {
82 pub offset: ByteOffset,
84 pub context: DecodeContext,
86 pub kind: DecodeErrorKind,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
92pub enum DecodeErrorKind {
93 UnexpectedEof,
95 InvalidMagic,
97 UnsupportedVersion { found: u32 },
99 Leb128TooLong,
101 Leb128Overflow,
103 UnknownSectionId { id: u8 },
105 SectionOverflow,
107 SectionOutOfOrder { prev: u8, current: u8 },
109 DuplicateSection { id: u8 },
111 UnknownValType { byte: u8 },
113 UnknownRefType { byte: u8 },
115 UnknownImportDesc { byte: u8 },
117 UnknownExportDesc { byte: u8 },
119 InvalidMutability { byte: u8 },
121 InvalidUtf8,
123 FunctionCodeLengthMismatch { functions: u32, codes: u32 },
125 TooManyLocals,
127 UnknownOpcode { byte: u8 },
129 UnknownSimdOpcode { opcode: u32 },
131 UnexpectedByte { expected: u8, found: u8 },
133 SectionSizeMismatch { expected: u32, consumed: u32 },
135}
136
137impl fmt::Display for DecodeError {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 write!(
140 f,
141 "decode error at byte {}: {}: {}",
142 self.offset.0, self.context, self.kind
143 )
144 }
145}
146
147impl fmt::Display for DecodeErrorKind {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 match self {
150 DecodeErrorKind::UnexpectedEof => write!(f, "unexpected end of input"),
151 DecodeErrorKind::InvalidMagic => write!(f, "invalid magic number (expected \\0asm)"),
152 DecodeErrorKind::UnsupportedVersion { found } => {
153 write!(f, "unsupported WASM version {found} (expected 1)")
154 }
155 DecodeErrorKind::Leb128TooLong => write!(f, "LEB128 encoding too long"),
156 DecodeErrorKind::TooManyLocals => write!(f, "too many locals"),
157 DecodeErrorKind::Leb128Overflow => write!(f, "LEB128 overflow (unused bits set)"),
158 DecodeErrorKind::UnknownSectionId { id } => {
159 write!(f, "unknown section ID {id:#04x}")
160 }
161 DecodeErrorKind::SectionOverflow => {
162 write!(f, "section extends beyond end of binary")
163 }
164 DecodeErrorKind::SectionOutOfOrder { prev, current } => {
165 write!(
166 f,
167 "section {current} appears after section {prev} (out of order)"
168 )
169 }
170 DecodeErrorKind::DuplicateSection { id } => {
171 write!(f, "duplicate section (id={id})")
172 }
173 DecodeErrorKind::UnknownValType { byte } => {
174 write!(f, "unknown value type {byte:#04x}")
175 }
176 DecodeErrorKind::UnknownRefType { byte } => {
177 write!(f, "unknown reference type {byte:#04x}")
178 }
179 DecodeErrorKind::UnknownImportDesc { byte } => {
180 write!(f, "unknown import descriptor {byte:#04x}")
181 }
182 DecodeErrorKind::UnknownExportDesc { byte } => {
183 write!(f, "unknown export descriptor {byte:#04x}")
184 }
185 DecodeErrorKind::InvalidMutability { byte } => {
186 write!(f, "invalid mutability {byte:#04x}")
187 }
188 DecodeErrorKind::InvalidUtf8 => write!(f, "invalid UTF-8 string"),
189 DecodeErrorKind::FunctionCodeLengthMismatch { functions, codes } => {
190 write!(
191 f,
192 "function/code section length mismatch: {functions} declarations, {codes} bodies"
193 )
194 }
195 DecodeErrorKind::UnknownOpcode { byte } => {
196 write!(f, "unknown opcode {byte:#04x}")
197 }
198 DecodeErrorKind::UnknownSimdOpcode { opcode } => {
199 write!(f, "unknown SIMD opcode {opcode:#04x}")
200 }
201 DecodeErrorKind::UnexpectedByte { expected, found } => {
202 write!(f, "expected {expected:#04x}, found {found:#04x}")
203 }
204 DecodeErrorKind::SectionSizeMismatch { expected, consumed } => {
205 write!(
206 f,
207 "section size mismatch: declared {expected} bytes, consumed {consumed}"
208 )
209 }
210 }
211 }
212}
213
214#[cfg(feature = "std")]
215impl std::error::Error for DecodeError {}
216
217#[cfg(not(feature = "std"))]
219impl core::error::Error for DecodeError {}