1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use crate::core::indices::GlobalIdx;
use crate::validation_stack::LabelKind;
use core::fmt::{Display, Formatter};
use core::str::Utf8Error;

use crate::core::reader::section_header::SectionTy;
use crate::core::reader::types::ValType;

use super::indices::{DataIdx, MemIdx};

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RuntimeError {
    DivideBy0,
    UnrepresentableResult,
    FunctionNotFound,
    StackSmash,
    // https://github.com/wasmi-labs/wasmi/blob/37d1449524a322817c55026eb21eb97dd693b9ce/crates/core/src/trap.rs#L265C5-L265C27
    BadConversionToInteger,
    MemoryAccessOutOfBounds,
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Error {
    /// The magic number at the very start of the given WASM file is invalid.
    InvalidMagic,
    InvalidVersion,
    MalformedUtf8String(Utf8Error),
    Eof,
    InvalidSectionType(u8),
    SectionOutOfOrder(SectionTy),
    InvalidNumType,
    InvalidVecType,
    InvalidFuncType,
    InvalidRefType,
    InvalidValType,
    InvalidExportDesc(u8),
    InvalidImportDesc(u8),
    ExprMissingEnd,
    InvalidInstr(u8),
    InvalidMultiByteInstr(u8, u8),
    EndInvalidValueStack,
    InvalidLocalIdx,
    InvalidValidationStackValType(Option<ValType>),
    ExpectedAnOperand,
    InvalidLimitsType(u8),
    InvalidMutType(u8),
    MoreThanOneMemory,
    InvalidLimit,
    MemSizeTooBig,
    InvalidGlobalIdx(GlobalIdx),
    GlobalIsConst,
    RuntimeError(RuntimeError),
    FoundLabel(LabelKind),
    MemoryIsNotDefined(MemIdx),
    //           mem.align, wanted alignment
    ErroneousAlignment(u32, u32),
    NoDataSegments,
    DataSegmentNotFound(DataIdx),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        match self {
            Error::InvalidMagic => {
                f.write_str("The magic number at the very start of the given WASM file is invalid.")
            }
            Error::InvalidVersion => f.write_str("The version in the WASM file header is invalid"),
            Error::MalformedUtf8String(err) => f.write_fmt(format_args!(
                "A name could not be parsed as it was invalid UTF8: {err}"
            )),
            Error::Eof => f.write_str(
                "A value was expected in the WASM binary but the end of file was reached instead",
            ),
            Error::InvalidSectionType(ty) => f.write_fmt(format_args!(
                "An invalid section type id was found in a section header: {ty}"
            )),
            Error::SectionOutOfOrder(ty) => {
                f.write_fmt(format_args!("The section {ty:?} is out of order"))
            }
            Error::InvalidNumType => {
                f.write_str("An invalid byte was read where a numtype was expected")
            }
            Error::InvalidVecType => {
                f.write_str("An invalid byte was read where a vectype was expected")
            }
            Error::InvalidFuncType => {
                f.write_str("An invalid byte was read where a functype was expected")
            }
            Error::InvalidRefType => {
                f.write_str("An invalid byte was read where a reftype was expected")
            }
            Error::InvalidValType => {
                f.write_str("An invalid byte was read where a valtype was expected")
            }
            Error::InvalidExportDesc(byte) => f.write_fmt(format_args!(
                "An invalid byte `{byte:#x?}` was read where an exportdesc was expected"
            )),
            Error::InvalidImportDesc(byte) => f.write_fmt(format_args!(
                "An invalid byte `{byte:#x?}` was read where an importdesc was expected"
            )),
            Error::ExprMissingEnd => f.write_str("An expr is missing an end byte"),
            Error::InvalidInstr(byte) => f.write_fmt(format_args!(
                "An invalid instruction opcode was found: `{byte:#x?}`"
            )),
            Error::InvalidMultiByteInstr(byte1, byte2) => f.write_fmt(format_args!(
                "An invalid multi-byte instruction opcode was found: `{byte1:#x?} {byte2:#x?}`"
            )),
            Error::EndInvalidValueStack => f.write_str(
                "Different value stack types were expected at the end of a block/function.",
            ),
            Error::InvalidLocalIdx => f.write_str("An invalid localidx was used"),
            Error::InvalidValidationStackValType(ty) => f.write_fmt(format_args!(
                "An unexpected type was found on the stack when trying to pop another: `{ty:?}`"
            )),
            Error::InvalidLimitsType(ty) => {
                f.write_fmt(format_args!("An invalid limits type was found: {ty:#x?}"))
            }
            Error::InvalidMutType(byte) => f.write_fmt(format_args!(
                "An invalid mut/const byte was found: {byte:#x?}"
            )),
            Error::MoreThanOneMemory => {
                f.write_str("As of not only one memory is allowed per module.")
            }
            Error::InvalidLimit => f.write_str("Size minimum must not be greater than maximum"),
            Error::MemSizeTooBig => f.write_str("Memory size must be at most 65536 pages (4GiB)"),
            Error::InvalidGlobalIdx(idx) => f.write_fmt(format_args!(
                "An invalid global index `{idx}` was specified"
            )),
            Error::GlobalIsConst => f.write_str("A const global cannot be written to"),
            Error::RuntimeError(err) => err.fmt(f),
            Error::FoundLabel(lk) => f.write_fmt(format_args!(
                "Expecting a ValType, a Label was found: {lk:?}"
            )),
            Error::ExpectedAnOperand => f.write_str("Expected a ValType"), // Error => f.write_str("Expected an operand (ValType) on the stack")
            Error::MemoryIsNotDefined(memidx) => f.write_fmt(format_args!(
                "C.mems[{}] is NOT defined when it should be",
                memidx
            )),
            Error::ErroneousAlignment(mem_align, minimum_wanted_alignment) => {
                f.write_fmt(format_args!(
                    "Alignment ({}) is not less or equal to {}",
                    mem_align, minimum_wanted_alignment
                ))
            }
            Error::NoDataSegments => f.write_str("Data Count is None"),
            Error::DataSegmentNotFound(data_idx) => {
                f.write_fmt(format_args!("Data Segment {} not found", data_idx))
            }
        }
    }
}

impl Display for RuntimeError {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        match self {
            RuntimeError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
            RuntimeError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
            RuntimeError::FunctionNotFound => f.write_str("Function not found"),
            RuntimeError::StackSmash => f.write_str("Stack smashed"),
            RuntimeError::BadConversionToInteger => f.write_str("Bad conversion to integer"),
            RuntimeError::MemoryAccessOutOfBounds => f.write_str("Memory access out of bounds"),
        }
    }
}

pub type Result<T> = core::result::Result<T, Error>;

impl From<RuntimeError> for Error {
    fn from(value: RuntimeError) -> Self {
        Self::RuntimeError(value)
    }
}