cosmwasm_vm/errors/
communication_error.rs

1use std::fmt::Debug;
2use thiserror::Error;
3
4use super::region_validation_error::RegionValidationError;
5use crate::memory::Region;
6
7/// An error in the communication between contract and host. Those happen around imports and exports.
8#[derive(Error, Debug)]
9#[non_exhaustive]
10pub enum CommunicationError {
11    #[error(
12        "The Wasm memory address {} provided by the contract could not be dereferenced: {}",
13        offset,
14        msg
15    )]
16    DerefErr {
17        /// the position in a Wasm linear memory
18        offset: u32,
19        msg: String,
20    },
21    #[error("Got an invalid value for iteration order: {}", value)]
22    InvalidOrder { value: i32 },
23    #[error("Got an invalid region: {}", source)]
24    InvalidRegion {
25        #[from]
26        source: RegionValidationError,
27    },
28    /// When the contract supplies invalid section data to the host. See also `decode_sections` [crate::sections::decode_sections].
29    #[error("Got an invalid section: {}", msg)]
30    InvalidSection { msg: String },
31    /// Whenever UTF-8 bytes cannot be decoded into a unicode string, e.g. in String::from_utf8 or str::from_utf8.
32    #[error("Cannot decode UTF8 bytes into string: {}", msg)]
33    InvalidUtf8 { msg: String },
34    #[error("Region length too big. Got {}, limit {}", length, max_length)]
35    // Note: this only checks length, not capacity
36    RegionLengthTooBig { length: usize, max_length: usize },
37    #[error("Region too small. Got {}, required {}", size, required)]
38    RegionTooSmall { size: usize, required: usize },
39    #[error("Tried to access memory of region {:?} in Wasm memory of size {} bytes. This typically happens when the given Region pointer does not point to a proper Region struct.", region, memory_size)]
40    RegionAccessErr {
41        region: Region,
42        /// Current size of the linear memory in bytes
43        memory_size: usize,
44    },
45    #[error("Got a zero Wasm address")]
46    ZeroAddress {},
47}
48
49impl CommunicationError {
50    pub(crate) fn deref_err(offset: u32, msg: impl Into<String>) -> Self {
51        CommunicationError::DerefErr {
52            offset,
53            msg: msg.into(),
54        }
55    }
56
57    #[allow(dead_code)]
58    pub(crate) fn invalid_order(value: i32) -> Self {
59        CommunicationError::InvalidOrder { value }
60    }
61
62    pub(crate) fn invalid_section(msg: impl Into<String>) -> Self {
63        CommunicationError::InvalidSection { msg: msg.into() }
64    }
65
66    #[allow(dead_code)]
67    pub(crate) fn invalid_utf8(msg: impl ToString) -> Self {
68        CommunicationError::InvalidUtf8 {
69            msg: msg.to_string(),
70        }
71    }
72
73    pub(crate) fn region_length_too_big(length: usize, max_length: usize) -> Self {
74        CommunicationError::RegionLengthTooBig { length, max_length }
75    }
76
77    pub(crate) fn region_too_small(size: usize, required: usize) -> Self {
78        CommunicationError::RegionTooSmall { size, required }
79    }
80
81    pub(crate) fn region_access_err(region: Region, memory_size: usize) -> Self {
82        CommunicationError::RegionAccessErr {
83            region,
84            memory_size,
85        }
86    }
87
88    pub(crate) fn zero_address() -> Self {
89        CommunicationError::ZeroAddress {}
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    // constructors
98
99    #[test]
100    fn deref_err() {
101        let error = CommunicationError::deref_err(345, "broken stuff");
102        match error {
103            CommunicationError::DerefErr { offset, msg, .. } => {
104                assert_eq!(offset, 345);
105                assert_eq!(msg, "broken stuff");
106            }
107            e => panic!("Unexpected error: {e:?}"),
108        }
109    }
110
111    #[test]
112    fn invalid_order() {
113        let error = CommunicationError::invalid_order(-745);
114        match error {
115            CommunicationError::InvalidOrder { value, .. } => assert_eq!(value, -745),
116            e => panic!("Unexpected error: {e:?}"),
117        }
118    }
119
120    #[test]
121    fn invalid_utf8() {
122        let error = CommunicationError::invalid_utf8("broken");
123        match error {
124            CommunicationError::InvalidUtf8 { msg, .. } => assert_eq!(msg, "broken"),
125            e => panic!("Unexpected error: {e:?}"),
126        }
127    }
128
129    #[test]
130    fn region_length_too_big_works() {
131        let error = CommunicationError::region_length_too_big(50, 20);
132        match error {
133            CommunicationError::RegionLengthTooBig {
134                length, max_length, ..
135            } => {
136                assert_eq!(length, 50);
137                assert_eq!(max_length, 20);
138            }
139            e => panic!("Unexpected error: {e:?}"),
140        }
141    }
142
143    #[test]
144    fn region_too_small_works() {
145        let error = CommunicationError::region_too_small(12, 33);
146        match error {
147            CommunicationError::RegionTooSmall { size, required, .. } => {
148                assert_eq!(size, 12);
149                assert_eq!(required, 33);
150            }
151            e => panic!("Unexpected error: {e:?}"),
152        }
153    }
154
155    #[test]
156    fn zero_address() {
157        let error = CommunicationError::zero_address();
158        match error {
159            CommunicationError::ZeroAddress { .. } => {}
160            e => panic!("Unexpected error: {e:?}"),
161        }
162    }
163}