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
use crate::panic_or_trap;
use core::fmt::{Display, Formatter};
/// The errors that a system call can return.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Error {
/// A CBOR data item is invalid CBOR or encodes an unsupported type or value.
CborDecode,
/// A buffer provided for the syscall to write into is too short.
BufferTooShort,
/// A component UUID refers to a component that does not exist or cannot be accessed.
NoSuchComponent,
/// A method invocation refers to a method that does not exist.
NoSuchMethod,
/// The parameters are incorrect in a way that does not have a more specific error code.
BadParameters,
/// A queue is full.
QueueFull,
/// A queue is empty.
QueueEmpty,
/// A descriptor is negative or not open.
BadDescriptor,
/// There are too many open descriptors.
TooManyDescriptors,
/// The operation failed for an otherwise unspecified reason.
Other,
/// A system call returned an error code that does not correspond to any known value.
///
/// It is likely that OC-Wasm has been updated to a version which adds new error codes, and
/// OC-Wasm-Safe has not been updated to match.
Unknown,
}
impl Error {
/// Returns a string describing the error.
#[must_use = "This function is only useful for its return value"]
pub fn as_str(self) -> &'static str {
match self {
Self::CborDecode => "CBOR decode error",
Self::BufferTooShort => "Buffer too short",
Self::NoSuchComponent => "No such component",
Self::NoSuchMethod => "No such method",
Self::BadParameters => "Bad parameters",
Self::QueueFull => "Queue full",
Self::QueueEmpty => "Queue empty",
Self::BadDescriptor => "Bad descriptor",
Self::TooManyDescriptors => "Too many descriptors",
Self::Other => "Other error",
Self::Unknown => "Unknown error",
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str(self.as_str())
}
}
impl Error {
/// Checks a system call return value of type `isize` for an error value.
///
/// Returns a `Result` containing an `Error` if the value is negative, or the original value if
/// it was nonnegative.
///
/// # Errors
/// This function fails if the parameter is negative, decoding the represented error code.
///
/// # Panics
/// This function panics if the syscall error code is `MemoryFault` or `StringDecode`. These
/// syscall errors should be impossible in safe code because the type system prohibits them:
/// `MemoryFault` should be impossible because all memory regions are taken as slices which are
/// always valid, and `StringDecode` should be impossible because all strings are taken as
/// string-slices (`&str`) which are always valid UTF-8.
pub fn from_isize(value: isize) -> Result<usize> {
match value {
-1 => panic_or_trap!("Memory fault"), // Impossible due to memory safety
-2 => Err(Self::CborDecode),
-3 => panic_or_trap!("String decode error"), // Impossible due to type safety of &str
-4 => Err(Self::BufferTooShort),
-5 => Err(Self::NoSuchComponent),
-6 => Err(Self::NoSuchMethod),
-7 => Err(Self::BadParameters),
-8 => Err(Self::QueueFull),
-9 => Err(Self::QueueEmpty),
-10 => Err(Self::BadDescriptor),
-11 => Err(Self::TooManyDescriptors),
-12 => Err(Self::Other),
x if x < 0 => Err(Self::Unknown),
_ => {
// Cast from isize to usize is safe because the match arm verifies that x ≥ 0.
#[allow(clippy::cast_sign_loss)]
Ok(value as usize)
}
}
}
/// Checks a system call return value of type `i32` for an error value.
///
/// Returns a `Result` containing an `Error` if the value is negative, or the original value if
/// it was nonnegative.
///
/// # Errors
/// This function fails if the parameter is negative, decoding the represented error code.
///
/// # Panics
/// This function panics if the syscall error code is `MemoryFault` or `StringDecode`. These
/// syscall errors should be impossible in safe code because the type system prohibits them:
/// `MemoryFault` should be impossible because all memory regions are taken as slices which are
/// always valid, and `StringDecode` should be impossible because all strings are taken as
/// string-slices (`&str`) which are always valid UTF-8.
pub fn from_i32(value: i32) -> Result<u32> {
// Cast from i32 to isize is safe because Wasm is a 32-bit target (or more), so isize is at
// least 32 bits. Cast from usize back to u32 is safe because the value was originally an
// i32, and from_isize returns an unsigned value.
#[allow(clippy::cast_possible_truncation)]
Ok(Self::from_isize(value as isize)? as u32)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;