Skip to content

Commit

Permalink
chore: .unwrap() tackling
Browse files Browse the repository at this point in the history
Signed-off-by: nerodesu017 <[email protected]>
  • Loading branch information
nerodesu017 committed Dec 11, 2024
1 parent 3700ad1 commit 7f6597e
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 53 deletions.
6 changes: 5 additions & 1 deletion src/core/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::format;
use alloc::string::{String, ToString};

use crate::core::indices::GlobalIdx;
use crate::validation_stack::LabelKind;
use crate::validation_stack::{LabelKind, ValidationStackEntry};
use crate::RefType;
use core::fmt::{Display, Formatter};
use core::str::Utf8Error;
Expand Down Expand Up @@ -57,6 +57,7 @@ pub enum Error {
EndInvalidValueStack,
InvalidLocalIdx,
InvalidValidationStackValType(Option<ValType>),
InvalidValidationStackType(ValidationStackEntry),
ExpectedAnOperand,
InvalidLimitsType(u8),
InvalidMutType(u8),
Expand Down Expand Up @@ -140,6 +141,9 @@ impl Display for Error {
Error::InvalidValidationStackValType(ty) => f.write_fmt(format_args!(
"An unexpected type was found on the stack when trying to pop another: `{ty:?}`"
)),
Error::InvalidValidationStackType(ty) => f.write_fmt(format_args!(
"An unexpected type was found on the stack: `{ty:?}`"
)),
Error::InvalidLimitsType(ty) => {
f.write_fmt(format_args!("An invalid limits type was found: {ty:#x?}"))
}
Expand Down
16 changes: 12 additions & 4 deletions src/core/reader/types/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::{
indices::MemIdx,
reader::{span::Span, WasmReadable},
},
read_constant_expression::read_constant_instructions,
read_constant_expression::read_constant_expression,
validation_stack::ValidationStack,
};

use super::UnwrapValidatedExt;
Expand All @@ -31,12 +32,17 @@ pub struct DataModeActive {

impl WasmReadable for DataSegment {
fn read(wasm: &mut crate::core::reader::WasmReader) -> crate::Result<Self> {
use crate::{NumType, ValType};
let mode = wasm.read_var_u32()?;
let data_sec: DataSegment = match mode {
0 => {
// active { memory 0, offset e }
trace!("Data section: active");
let offset = { read_constant_instructions(wasm, None, None, None)? };
let mut valid_stack = ValidationStack::new();
let offset =
{ read_constant_expression(wasm, &mut valid_stack, None, None, None)? };

valid_stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;

let byte_vec = wasm.read_vec(|el| el.read_u8())?;

Expand Down Expand Up @@ -81,8 +87,10 @@ impl WasmReadable for DataSegment {
0 => {
// active { memory 0, offset e }
trace!("Data section: active");
let offset =
{ read_constant_instructions(wasm, None, None, None).unwrap_validated() };
let offset = {
read_constant_expression(wasm, &mut ValidationStack::new(), None, None, None)
.unwrap_validated()
};

let byte_vec = wasm
.read_vec(|el| Ok(el.read_u8().unwrap_validated()))
Expand Down
44 changes: 41 additions & 3 deletions src/core/reader/types/element.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::RefType;
use crate::core::reader::span::Span;
use crate::core::reader::WasmReader;
use crate::read_constant_expression::read_constant_instructions;
use crate::read_constant_expression::read_constant_expression;
use crate::validation_stack::ValidationStack;
use crate::{Error, Result};

use alloc::collections::btree_set::BTreeSet;
Expand Down Expand Up @@ -83,7 +84,12 @@ impl ElemType {
return Err(Error::UnknownTable);
}

let init_expr = read_constant_instructions(wasm, None, None, Some(functions))?;
let mut valid_stack = ValidationStack::new();
let init_expr =
read_constant_expression(wasm, &mut valid_stack, None, None, Some(functions))?;

// on top of the stack it's supposed to be the
valid_stack.assert_pop_val_type(super::ValType::NumType(super::NumType::I32))?;

ElemMode::Active(ActiveElem {
table_idx,
Expand Down Expand Up @@ -114,7 +120,39 @@ impl ElemType {
let items: ElemItems = if third_bit_set {
ElemItems::Exprs(
reftype_or_elemkind.unwrap_or(RefType::FuncRef),
wasm.read_vec(|w| read_constant_instructions(w, None, None, Some(functions)))?,
wasm.read_vec(|w| {
let mut valid_stack = ValidationStack::new();
let span = read_constant_expression(
w,
&mut valid_stack,
None,
None,
Some(functions),
);

use crate::validation_stack::ValidationStackEntry::*;

if let Some(val) = valid_stack.peek_stack() {
if let Val(val) = val {
match val {
crate::ValType::RefType(_) => {}
crate::ValType::NumType(crate::NumType::I32) => {}
crate::ValType::NumType(_) => {
return Err(Error::InvalidValidationStackValType(Some(val)))
}
_ => {
return Err(Error::InvalidValidationStackValType(Some(val)))
}
}
} else {
return Err(Error::InvalidValidationStackType(val));
}
} else {
return Err(Error::InvalidValidationStackValType(None));
}

span
})?,
)
} else {
assert!(reftype_or_elemkind.is_none());
Expand Down
6 changes: 4 additions & 2 deletions src/core/reader/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,10 @@ impl WasmReadable for Limits {
other => return Err(Error::InvalidLimitsType(other)),
};

if limits.max.is_some() && limits.min > limits.max.unwrap() {
return Err(Error::InvalidLimit);
if let Some(max) = limits.max {
if limits.min > max {
return Err(Error::InvalidLimit);
}
}

Ok(limits)
Expand Down
42 changes: 21 additions & 21 deletions src/execution/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use alloc::borrow::ToOwned;
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
Expand Down Expand Up @@ -414,12 +413,14 @@ where
ElemMode::Active(active_elem) => {
let table_idx = active_elem.table_idx as usize;

// TODO
let offset = get_address_offset(
run_const_span(validation_info.wasm, &active_elem.init_expr, ())
.unwrap_validated(),
)
.unwrap_validated() as usize;
let offset =
match run_const_span(validation_info.wasm, &active_elem.init_expr, ())
.unwrap_validated()
{
Value::I32(offset) => offset as usize,
// We are already asserting that on top of the stack there is an I32 at validation time
_ => unreachable!(),
};

let table = &mut tables[table_idx];
// This can't be verified at validation-time because we don't keep track of actual values when validating expressions
Expand All @@ -446,33 +447,35 @@ where
.iter()
.map(|d| {
use crate::core::reader::types::data::DataMode;
use crate::NumType;
if let DataMode::Active(active_data) = d.mode.clone() {
let mem_idx = active_data.memory_idx;
if mem_idx != 0 {
todo!("Active data has memory_idx different than 0");
}
assert!(memory_instances.len() > mem_idx);

let value = {
let boxed_value = {
let mut wasm = WasmReader::new(validation_info.wasm);
wasm.move_start_to(active_data.offset).unwrap_validated();
let mut stack = Stack::new();
run_const(wasm, &mut stack, ());
stack.peek_unknown_value().ok_or(MissingValueOnTheStack)?
stack.pop_value(ValType::NumType(NumType::I32))
// stack.peek_unknown_value().ok_or(MissingValueOnTheStack)?
};

// TODO: this shouldn't be a simple value, should it? I mean it can't be, but it can also be any type of ValType
// TODO: also, do we need to forcefully make it i32?
let offset: u32 = match value {
let offset: u32 = match boxed_value {
Value::I32(val) => val,
Value::I64(val) => {
if val > u32::MAX as u64 {
return Err(I64ValueOutOfReach("data segment".to_owned()));
}
val as u32
}
// Value::I64(val) => {
// if val > u32::MAX as u64 {
// return Err(I64ValueOutOfReach("data segment".to_owned()));
// }
// val as u32
// }
// TODO: implement all value types
_ => unimplemented!(),
_ => todo!(),
};

let mem_inst = memory_instances.get_mut(mem_idx).unwrap();
Expand Down Expand Up @@ -543,10 +546,7 @@ fn get_address_offset(value: Value) -> Option<u32> {
Value::Ref(rref) => match rref {
Ref::Extern(_) => todo!("Not yet implemented"),
// TODO: fix
Ref::Func(func_addr) => match func_addr.addr {
Some(addr) => Some(addr as u32),
None => None,
},
Ref::Func(func_addr) => func_addr.addr.map(|addr| addr as u32),
},
// INFO: from wasmtime - implement only global
_ => unreachable!(),
Expand Down
8 changes: 5 additions & 3 deletions src/validation/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ use alloc::vec::Vec;
use crate::core::reader::section_header::{SectionHeader, SectionTy};
use crate::core::reader::types::global::{Global, GlobalType};
use crate::core::reader::{WasmReadable, WasmReader};
use crate::read_constant_expression::read_constant_instructions;
use crate::read_constant_expression::read_constant_expression;
use crate::validation_stack::ValidationStack;
use crate::Result;

/// Validate the global section.
///
/// The global section is a vector of global variables. Each [Global] variable is composed of a [GlobalType] and an
/// initialization expression represented by a constant expression.
///
/// See [read_constant_instructions] for more information.
/// See [`read_constant_expression`] for more information.
pub(super) fn validate_global_section(
wasm: &mut WasmReader,
section_header: SectionHeader,
Expand All @@ -20,8 +21,9 @@ pub(super) fn validate_global_section(

wasm.read_vec(|wasm| {
let ty = GlobalType::read(wasm)?;
let init_expr = read_constant_instructions(
let init_expr = read_constant_expression(
wasm,
&mut ValidationStack::new(),
Some(ty.ty),
Some(&[/* todo!(imported globals tpyes) */]),
// we can't refer to any functions
Expand Down
6 changes: 2 additions & 4 deletions src/validation/read_constant_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,15 @@ use super::validation_stack::ValidationStack;
/// - `ref.null`
/// - `ref.func`
/// - `global.get`
pub fn read_constant_instructions(
pub fn read_constant_expression(
wasm: &mut WasmReader,
stack: &mut ValidationStack,
this_global_valtype: Option<ValType>,
_globals_ty: Option<&[GlobalType]>,
funcs: Option<&[usize]>,
) -> Result<Span> {
let start_pc = wasm.pc;

// Compared to the code validation, we create the validation stack here as opposed to taking it as an argument.
let mut stack = ValidationStack::new();

loop {
let Ok(first_instr_byte) = wasm.read_u8() else {
return Err(Error::ExprMissingEnd);
Expand Down
34 changes: 19 additions & 15 deletions src/validation/validation_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,35 @@ use alloc::vec::Vec;
use crate::{Error, RefType, ValType};

#[derive(Debug, PartialEq, Eq)]
pub(super) struct ValidationStack {
pub struct ValidationStack {
stack: Vec<ValidationStackEntry>,
}

impl ValidationStack {
/// Initialize a new ValidationStack
pub(super) fn new() -> Self {
pub fn new() -> Self {
Self { stack: Vec::new() }
}

pub(super) fn len(&self) -> usize {
pub fn len(&self) -> usize {
self.stack.len()
}

pub(super) fn push_valtype(&mut self, valtype: ValType) {
pub fn push_valtype(&mut self, valtype: ValType) {
self.stack.push(ValidationStackEntry::Val(valtype));
}

pub(super) fn push_label(&mut self, label_info: LabelInfo) {
pub fn push_label(&mut self, label_info: LabelInfo) {
self.stack.push(ValidationStackEntry::Label(label_info));
}

pub fn peek_stack(&self) -> Option<ValidationStackEntry> {
self.stack.last().cloned()
}

/// Similar to [`ValidationStack::pop`], because it pops a value from the stack,
/// but more public and doesn't actually return the popped value.
pub(super) fn drop_val(&mut self) -> Result<()> {
pub fn drop_val(&mut self) -> Result<()> {
match self.stack.pop().ok_or(Error::EndInvalidValueStack)? {
ValidationStackEntry::Val(_) => Ok(()),
_ => Err(Error::ExpectedAnOperand),
Expand All @@ -46,7 +50,7 @@ impl ValidationStack {
/// To undo this, a new label has to be pushed or an existing one has to be popped.
///
/// See the documentation for [`ValidationStackEntry::UnspecifiedValTypes`] for more info.
pub(super) fn make_unspecified(&mut self) {
pub fn make_unspecified(&mut self) {
// Pop everything until next label or until the stack is empty.
// This is okay, because these values cannot be accessed during execution ever again.
while let Some(entry) = self.stack.last() {
Expand Down Expand Up @@ -74,7 +78,7 @@ impl ValidationStack {
.ok_or(Error::InvalidValidationStackValType(None))
}

pub(super) fn assert_pop_ref_type(&mut self, expected_ty: Option<RefType>) -> Result<()> {
pub fn assert_pop_ref_type(&mut self, expected_ty: Option<RefType>) -> Result<()> {
let val = self.pop()?;
match val {
ValidationStackEntry::Val(v) => match v {
Expand Down Expand Up @@ -102,7 +106,7 @@ impl ValidationStack {
/// - Returns `Ok(())` if the top-most [`ValidationStackEntry`] is a [`ValType`] identical to
/// `expected_ty`.
/// - Returns `Err(_)` otherwise.
pub(super) fn assert_pop_val_type(&mut self, expected_ty: ValType) -> Result<()> {
pub fn assert_pop_val_type(&mut self, expected_ty: ValType) -> Result<()> {
if let Some(ValidationStackEntry::UnspecifiedValTypes) = self.stack.last() {
// An unspecified value is always correct, and will never disappear by popping.
return Ok(());
Expand Down Expand Up @@ -132,7 +136,7 @@ impl ValidationStack {
///
/// - `Ok(_)`, the tail of the stack matches the `expected_val_types`
/// - `Err(_)` otherwise
pub(super) fn assert_val_types_on_top(&self, expected_val_types: &[ValType]) -> Result<()> {
pub fn assert_val_types_on_top(&self, expected_val_types: &[ValType]) -> Result<()> {
let stack_tail = self
.stack
.get(self.stack.len() - expected_val_types.len()..)
Expand Down Expand Up @@ -170,7 +174,7 @@ impl ValidationStack {
///
/// - `Ok(())` if all expected valtypes were found
/// - `Err(_)` otherwise
pub(super) fn assert_val_types(&self, expected_val_types: &[ValType]) -> Result<()> {
pub fn assert_val_types(&self, expected_val_types: &[ValType]) -> Result<()> {
let topmost_label_index = self.find_topmost_label_idx();

let first_valtype = topmost_label_index.map(|idx| idx + 1).unwrap_or(0);
Expand Down Expand Up @@ -237,15 +241,15 @@ impl ValidationStack {
}

/// Return true if the stack has at least one remaining label
pub(super) fn has_remaining_label(&self) -> bool {
pub fn has_remaining_label(&self) -> bool {
self.stack
.iter()
.any(|e| matches!(e, ValidationStackEntry::Label(_)))
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
enum ValidationStackEntry {
pub enum ValidationStackEntry {
/// A value
Val(ValType),

Expand All @@ -262,8 +266,8 @@ enum ValidationStackEntry {
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct LabelInfo {
pub(crate) kind: LabelKind,
pub struct LabelInfo {
pub kind: LabelKind,
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down

0 comments on commit 7f6597e

Please sign in to comment.