Skip to content

Commit ce788d8

Browse files
committed
chore: Convert panics to errors
1 parent d6144f9 commit ce788d8

File tree

6 files changed

+52
-31
lines changed

6 files changed

+52
-31
lines changed

src/core/error.rs

+18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use core::str::Utf8Error;
55
use crate::core::reader::section_header::SectionTy;
66
use crate::core::reader::types::ValType;
77

8+
use super::indices::FuncIdx;
9+
810
#[derive(Debug, PartialEq, Eq, Clone)]
911
pub enum RuntimeError {
1012
DivideBy0,
@@ -38,8 +40,12 @@ pub enum Error {
3840
InvalidMutType(u8),
3941
MoreThanOneMemory,
4042
InvalidGlobalIdx(GlobalIdx),
43+
InvalidFunctionIdx(FuncIdx),
4144
GlobalIsConst,
4245
RuntimeError(RuntimeError),
46+
NotYetImplemented(&'static str),
47+
InvalidParameterTypes,
48+
InvalidResultTypes,
4349
}
4450

4551
impl Display for Error {
@@ -108,12 +114,24 @@ impl Display for Error {
108114
Error::InvalidGlobalIdx(idx) => f.write_fmt(format_args!(
109115
"An invalid global index `{idx}` was specified"
110116
)),
117+
Error::InvalidFunctionIdx(idx) => f.write_fmt(format_args!(
118+
"An invalid function index `{idx}` was specified"
119+
)),
111120
Error::GlobalIsConst => f.write_str("A const global cannot be written to"),
112121
Error::RuntimeError(err) => match err {
113122
RuntimeError::DivideBy0 => f.write_str("Divide by zero is not permitted"),
114123
RuntimeError::UnrepresentableResult => f.write_str("Result is unrepresentable"),
115124
RuntimeError::FunctionNotFound => f.write_str("Function not found"),
116125
},
126+
Error::NotYetImplemented(msg) => {
127+
f.write_fmt(format_args!("Not yet implemented: {msg}"))
128+
},
129+
Error::InvalidParameterTypes => {
130+
f.write_str("The given parameter types do not match the function's signature")
131+
},
132+
Error::InvalidResultTypes => {
133+
f.write_str("The given result types do not match the function's signature")
134+
},
117135
}
118136
}
119137
}

src/core/reader/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ impl<'a> WasmReader<'a> {
8989
let bytes = &self.full_wasm_binary[self.pc..(self.pc + N)];
9090
self.pc += N;
9191

92-
Ok(bytes.try_into().expect("the slice length to be exactly N"))
92+
Ok(bytes.try_into().map_err(|_err| Error::Eof)?)
9393
}
9494

9595
/// Read the current byte without advancing the [`pc`](Self::pc)

src/core/reader/section_header.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl WasmReadable for SectionHeader {
8787
let size: u32 = wasm.read_var_u32().unwrap_validated();
8888
let contents_span = wasm
8989
.make_span(size as usize)
90-
.expect("TODO remove this expect");
90+
.expect("Expected to be able to read section due to prior validation");
9191

9292
SectionHeader {
9393
ty,

src/core/reader/types/import.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ impl WasmReadable for ImportDesc {
6060
fn read(wasm: &mut WasmReader) -> Result<Self> {
6161
let desc = match wasm.read_u8()? {
6262
0x00 => Self::Func(wasm.read_var_u32()? as TypeIdx),
63-
0x01 => todo!("read TableType"),
64-
0x02 => todo!("read MemType"),
65-
0x03 => todo!("read GlobalType"),
63+
0x01 => return Err(Error::NotYetImplemented("read TableType")),
64+
0x02 => return Err(Error::NotYetImplemented("read MemType")),
65+
0x03 => return Err(Error::NotYetImplemented("read GlobalType")),
6666
other => return Err(Error::InvalidImportDesc(other)),
6767
};
6868

src/execution/mod.rs

+24-23
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::execution::store::{FuncInst, GlobalInst, MemInst, Store};
1414
use crate::execution::value::Value;
1515
use crate::validation::code::read_declared_locals;
1616
use crate::value::InteropValueList;
17-
use crate::Error::RuntimeError;
17+
use crate::Error::{self, RuntimeError};
1818
use crate::RuntimeError::{DivideBy0, FunctionNotFound, UnrepresentableResult};
1919
use crate::{Result, ValidationInfo};
2020

@@ -51,7 +51,7 @@ where
5151
pub fn new_with_hooks(validation_info: &'_ ValidationInfo<'b>, hook_set: H) -> Result<Self> {
5252
trace!("Starting instantiation of bytecode");
5353

54-
let store = Self::init_store(validation_info);
54+
let store = Self::init_store(validation_info)?;
5555

5656
let mut instance = RuntimeInstance {
5757
wasm_bytecode: validation_info.wasm,
@@ -100,15 +100,16 @@ where
100100
params: Param,
101101
) -> Result<Returns> {
102102
// -=-= Verification =-=-
103-
let func_inst = self.store.funcs.get(func_idx).expect("valid FuncIdx");
103+
// TODO(george-cosma): Do we want this to be a RuntimeError(FunctionNotFound)?
104+
let func_inst = self.store.funcs.get(func_idx).ok_or(Error::InvalidFunctionIdx(func_idx))?;
104105
let func_ty = self.types.get(func_inst.ty).unwrap_validated();
105106

106107
// Check correct function parameters and return types
107108
if func_ty.params.valtypes != Param::TYS {
108-
panic!("Invalid `Param` generics");
109+
return Err(Error::InvalidParameterTypes);
109110
}
110111
if func_ty.returns.valtypes != Returns::TYS {
111-
panic!("Invalid `Returns` generics");
112+
return Err(Error::InvalidResultTypes);
112113
}
113114

114115
// -=-= Invoke the function =-=-
@@ -143,19 +144,20 @@ where
143144
ret_types: &[ValType],
144145
) -> Result<Vec<Value>> {
145146
// -=-= Verification =-=-
146-
let func_inst = self.store.funcs.get(func_idx).expect("valid FuncIdx");
147+
// TODO(george-cosma): Do we want this to be a RuntimeError(FunctionNotFound)?
148+
let func_inst = self.store.funcs.get(func_idx).ok_or(Error::InvalidFunctionIdx(func_idx))?;
147149
let func_ty = self.types.get(func_inst.ty).unwrap_validated();
148150

149151
// Verify that the given parameters match the function parameters
150152
let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
151153

152154
if func_ty.params.valtypes != param_types {
153-
panic!("Invalid parameters for function");
155+
return Err(Error::InvalidParameterTypes);
154156
}
155157

156158
// Verify that the given return types match the function return types
157159
if func_ty.returns.valtypes != ret_types {
158-
panic!("Invalid return types for function");
160+
return Err(Error::InvalidResultTypes);
159161
}
160162

161163
// -=-= Invoke the function =-=-
@@ -169,9 +171,10 @@ where
169171
let error = self.function(func_idx, &mut stack);
170172
error?;
171173

172-
let func_inst = self.store.funcs.get(func_idx).expect("valid FuncIdx");
174+
// TODO(george-cosma): Do we want this to be a RuntimeError(FunctionNotFound)?
175+
let func_inst = self.store.funcs.get(func_idx).ok_or(Error::InvalidFunctionIdx(func_idx))?;
173176
let func_ty = self.types.get(func_inst.ty).unwrap_validated();
174-
177+
175178
// Pop return values from stack
176179
let return_values = func_ty
177180
.returns
@@ -263,9 +266,9 @@ where
263266
let address = address as usize;
264267
mem.data.get(address..(address + 4))
265268
})
266-
.expect("TODO trap here");
269+
.expect("TODO trap here"); // ???
267270

268-
let data: [u8; 4] = data.try_into().expect("this to be exactly 4 bytes");
271+
let data: [u8; 4] = data.try_into().expect("this to be exactly 4 bytes"); // ???
269272
u32::from_le_bytes(data)
270273
};
271274

@@ -289,7 +292,7 @@ where
289292
let address = address as usize;
290293
mem.data.get_mut(address..(address + 4))
291294
})
292-
.expect("TODO trap here");
295+
.expect("TODO trap here"); // ???
293296

294297
memory_location.copy_from_slice(&data_to_store.to_le_bytes());
295298
trace!("Instruction: i32.store [{relative_address} {data_to_store}] -> []");
@@ -663,7 +666,7 @@ where
663666
Ok(())
664667
}
665668

666-
fn init_store(validation_info: &ValidationInfo) -> Store {
669+
fn init_store(validation_info: &ValidationInfo) -> Result<Store> {
667670
let function_instances: Vec<FuncInst> = {
668671
let mut wasm_reader = WasmReader::new(validation_info.wasm);
669672

@@ -674,24 +677,22 @@ where
674677
.zip(func_blocks)
675678
.map(|(ty, func)| {
676679
wasm_reader
677-
.move_start_to(*func)
678-
.expect("function index to be in the bounds of the WASM binary");
680+
.move_start_to(*func)?;
679681

680682
let (locals, bytes_read) = wasm_reader
681683
.measure_num_read_bytes(read_declared_locals)
682684
.unwrap_validated();
683685

684686
let code_expr = wasm_reader
685-
.make_span(func.len() - bytes_read)
686-
.expect("TODO remove this expect");
687+
.make_span(func.len() - bytes_read)?;
687688

688-
FuncInst {
689+
Ok(FuncInst {
689690
ty: *ty,
690691
locals,
691692
code_expr,
692-
}
693+
})
693694
})
694-
.collect()
695+
.collect::<Result<Vec<FuncInst>>>()?
695696
};
696697

697698
let memory_instances: Vec<MemInst> = validation_info
@@ -714,10 +715,10 @@ where
714715
})
715716
.collect();
716717

717-
Store {
718+
Ok(Store {
718719
funcs: function_instances,
719720
mems: memory_instances,
720721
globals: global_instances,
721-
}
722+
})
722723
}
723724
}

src/validation/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,13 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo> {
121121
while (skip_section(&mut wasm, &mut header)?).is_some() {}
122122

123123
let _: Option<()> = handle_section(&mut wasm, &mut header, SectionTy::Element, |_, _| {
124-
todo!("element section not yet supported")
124+
Err(Error::NotYetImplemented("element section not yet supported"))
125125
})?;
126126

127127
while (skip_section(&mut wasm, &mut header)?).is_some() {}
128128

129129
let _: Option<()> = handle_section(&mut wasm, &mut header, SectionTy::DataCount, |_, _| {
130-
todo!("data count section not yet supported")
130+
Err(Error::NotYetImplemented("data count section not yet supported"))
131131
})?;
132132

133133
while (skip_section(&mut wasm, &mut header)?).is_some() {}
@@ -142,7 +142,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo> {
142142
while (skip_section(&mut wasm, &mut header)?).is_some() {}
143143

144144
let _: Option<()> = handle_section(&mut wasm, &mut header, SectionTy::Data, |_, _| {
145-
todo!("data section not yet supported")
145+
Err(Error::NotYetImplemented("data section not yet supported"))
146146
})?;
147147

148148
while (skip_section(&mut wasm, &mut header)?).is_some() {}
@@ -183,6 +183,8 @@ fn handle_section<T, F: FnOnce(&mut WasmReader, SectionHeader) -> Result<T>>(
183183
) -> Result<Option<T>> {
184184
match &header {
185185
Some(SectionHeader { ty, .. }) if *ty == section_ty => {
186+
// We just checked that the header is of type "Some", so
187+
// it is safe to unwrap here.
186188
let h = header.take().unwrap();
187189
trace!("Handling section {:?}", h.ty);
188190
let ret = handler(wasm, h)?;

0 commit comments

Comments
 (0)