1use crate::source::describe_position;
2use std::fmt;
3use std::str::Utf8Error;
4
5#[cfg_attr(test, derive(Debug))]
6pub enum ErrorKind {
7 IntOverflow {
8 ty: &'static str,
9 got: Option<u64>,
10 },
11 UnexpectedEof {
12 expected: &'static str,
13 },
14 WasmMagicNotFound,
15 VersionMismatch([u8; 4]),
16 LengthOutOfInput {
17 input: usize,
18 specified: usize,
19 what: &'static str,
20 },
21 InvalidUtf8 {
22 what: &'static str,
23 error: Utf8Error,
24 },
25 UnexpectedByte {
26 expected: Vec<u8>,
27 got: u8,
28 what: &'static str,
29 },
30 FuncCodeLengthMismatch {
31 num_funcs: usize,
32 num_codes: usize,
33 },
34 TooManyLocalVariables(usize),
35 MalformedSectionSize {
36 name: &'static str,
37 remaining_bytes: usize,
38 },
39 MalformedCodeSize {
40 remaining_bytes: usize,
41 },
42 ExpectedEof(u8),
43}
44
45#[cfg_attr(test, derive(Debug))]
46pub struct Error<'source> {
47 pub kind: ErrorKind,
48 pub pos: usize,
49 pub source: &'source [u8],
50 pub when: &'static str,
51}
52
53impl<'s> Error<'s> {
54 pub(crate) fn new(kind: ErrorKind, pos: usize, source: &'s [u8], when: &'static str) -> Box<Error<'s>> {
55 Box::new(Error {
56 kind,
57 pos,
58 source,
59 when,
60 })
61 }
62}
63
64impl<'s> fmt::Display for Error<'s> {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 use ErrorKind::*;
67 match &self.kind {
68 IntOverflow { ty, got: Some(got) } => {
69 write!(f, "LEB128-encoded integer '{:x}' is too large for {} value", got, ty)?
70 }
71 IntOverflow { ty, got: None } => write!(f, "LEB128-encoded integer is too large for {} value", ty)?,
72 UnexpectedEof { expected } => {
73 write!(f, "expected {} but reached end of current section or input", expected)?
74 }
75 WasmMagicNotFound => write!(f, "WebAssembly binary must start with magic 0x00 0x61 0x73 0x6d")?,
76 VersionMismatch(v) => write!(f, "expected version [1, 0, 0, 0] but got {:?}", v)?,
77 LengthOutOfInput { input, specified, what } => write!(
78 f,
79 "{} ({} bytes) is larger than the rest of input ({} bytes)",
80 what, specified, input
81 )?,
82 InvalidUtf8 { what, error } => write!(f, "{} must be UTF-8 sequence: {}", what, error)?,
83 UnexpectedByte { expected, got, what } if expected.is_empty() => {
84 write!(f, "unexpected byte 0x{:02x} at {}", got, what,)?
85 }
86 UnexpectedByte { expected, got, what } if expected.len() == 1 => write!(
87 f,
88 "expected byte 0x{:02x} for {} but got 0x{:02x}",
89 expected[0], what, got
90 )?,
91 UnexpectedByte { expected, got, what } => {
92 f.write_str("expected one of ")?;
93 let mut first = true;
94 for b in expected.iter() {
95 if !first {
96 f.write_str(", ")?;
97 }
98 write!(f, "0x{:02x}", b)?;
99 first = false;
100 }
101 write!(f, " for {} but got byte 0x{:02x}", what, got)?;
102 }
103 FuncCodeLengthMismatch { num_funcs, num_codes } => write!(
104 f,
105 "number of function sections '{}' does not match to number of code sections '{}'",
106 num_funcs, num_codes,
107 )?,
108 TooManyLocalVariables(num) => write!(f, "too many ({}) local variables", num)?,
109 MalformedSectionSize { name, remaining_bytes } => write!(
110 f,
111 "expected end of {} but trailing {} bytes still remain",
112 name, remaining_bytes
113 )?,
114 MalformedCodeSize { remaining_bytes } => write!(
115 f,
116 "expected end of code but trailing {} bytes still remain",
117 remaining_bytes
118 )?,
119 ExpectedEof(b) => write!(f, "expected end of input but byte 0x{:02x} is still following", b)?,
120 }
121 write!(f, " while parsing {}.", self.when)?;
122 describe_position(f, self.source, self.pos)
123 }
124}
125
126pub type Result<'s, T> = ::std::result::Result<T, Box<Error<'s>>>;