Validate the locals count in the begging

This commit is contained in:
Sergey Pepyakin 2018-06-16 16:30:58 +03:00
parent b2b9d62939
commit 0f6da829de
2 changed files with 27 additions and 27 deletions

View File

@ -173,7 +173,7 @@ impl Validator {
let ins_size_estimate = body.code().elements().len(); let ins_size_estimate = body.code().elements().len();
let mut context = FunctionValidationContext::new( let mut context = FunctionValidationContext::new(
&module, &module,
Locals::new(params, body.locals()), Locals::new(params, body.locals())?,
DEFAULT_VALUE_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT,
DEFAULT_FRAME_STACK_LIMIT, DEFAULT_FRAME_STACK_LIMIT,
result_ty, result_ty,
@ -375,9 +375,8 @@ impl Validator {
)?; )?;
} }
let locals_count = context.locals.count()?;
let DropKeep { drop, keep } = drop_keep_return( let DropKeep { drop, keep } = drop_keep_return(
locals_count, &context.locals,
&context.value_stack, &context.value_stack,
&context.frame_stack, &context.frame_stack,
); );
@ -442,9 +441,8 @@ impl Validator {
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
} }
let locals_count = context.locals.count()?;
let DropKeep { drop, keep } = drop_keep_return( let DropKeep { drop, keep } = drop_keep_return(
locals_count, &context.locals,
&context.value_stack, &context.value_stack,
&context.frame_stack &context.frame_stack
); );
@ -1589,7 +1587,7 @@ fn require_target(
} }
fn drop_keep_return( fn drop_keep_return(
locals_count: u32, locals: &Locals,
value_stack: &StackWithLimit<StackValueType>, value_stack: &StackWithLimit<StackValueType>,
frame_stack: &StackWithLimit<BlockFrame>, frame_stack: &StackWithLimit<BlockFrame>,
) -> DropKeep { ) -> DropKeep {
@ -1602,7 +1600,7 @@ fn drop_keep_return(
let mut drop_keep = require_target(deepest, value_stack, frame_stack).drop_keep; let mut drop_keep = require_target(deepest, value_stack, frame_stack).drop_keep;
// Drop all local variables and parameters upon exit. // Drop all local variables and parameters upon exit.
drop_keep.drop += locals_count; drop_keep.drop += locals.count();
drop_keep drop_keep
} }
@ -1618,7 +1616,7 @@ fn relative_local_depth(
) -> Result<u32, Error> { ) -> Result<u32, Error> {
// TODO: Comment stack layout // TODO: Comment stack layout
let value_stack_height = value_stack.len() as u32; let value_stack_height = value_stack.len() as u32;
let locals_and_params_count = locals.count()?; let locals_and_params_count = locals.count();
let depth = value_stack_height let depth = value_stack_height
.checked_add(locals_and_params_count) .checked_add(locals_and_params_count)

View File

@ -10,14 +10,26 @@ use validation::Error;
pub struct Locals<'a> { pub struct Locals<'a> {
params: &'a [ValueType], params: &'a [ValueType],
local_groups: &'a [Local], local_groups: &'a [Local],
count: u32,
} }
impl<'a> Locals<'a> { impl<'a> Locals<'a> {
pub fn new(params: &'a [ValueType], local_groups: &'a [Local]) -> Locals<'a> { /// Create a new wrapper around declared variables and parameters.
Locals { pub fn new(params: &'a [ValueType], local_groups: &'a [Local]) -> Result<Locals<'a>, Error> {
let mut acc = params.len() as u32;
for locals_group in local_groups {
acc = acc
.checked_add(locals_group.count())
.ok_or_else(||
Error(String::from("Locals range no in 32-bit range"))
)?;
}
Ok(Locals {
params, params,
local_groups, local_groups,
} count: acc,
})
} }
/// Returns parameter count. /// Returns parameter count.
@ -26,18 +38,8 @@ impl<'a> Locals<'a> {
} }
/// Returns total count of all declared locals and paramaterers. /// Returns total count of all declared locals and paramaterers.
/// pub fn count(&self) -> u32 {
/// Returns `Err` if count overflows 32-bit value. self.count
pub fn count(&self) -> Result<u32, Error> {
let mut acc = self.param_count();
for locals_group in self.local_groups {
acc = acc
.checked_add(locals_group.count())
.ok_or_else(||
Error(String::from("Locals range no in 32-bit range"))
)?;
}
Ok(acc)
} }
/// Returns the type of a local variable (either a declared local or a param). /// Returns the type of a local variable (either a declared local or a param).
@ -82,7 +84,7 @@ mod tests {
fn locals_it_works() { fn locals_it_works() {
let params = vec![ValueType::I32, ValueType::I64]; let params = vec![ValueType::I32, ValueType::I64];
let local_groups = vec![Local::new(2, ValueType::F32), Local::new(2, ValueType::F64)]; let local_groups = vec![Local::new(2, ValueType::F32), Local::new(2, ValueType::F64)];
let locals = Locals::new(&params, &local_groups); let locals = Locals::new(&params, &local_groups).unwrap();
assert_matches!(locals.type_of_local(0), Ok(ValueType::I32)); assert_matches!(locals.type_of_local(0), Ok(ValueType::I32));
assert_matches!(locals.type_of_local(1), Ok(ValueType::I64)); assert_matches!(locals.type_of_local(1), Ok(ValueType::I64));
@ -96,7 +98,7 @@ mod tests {
#[test] #[test]
fn locals_no_declared_locals() { fn locals_no_declared_locals() {
let params = vec![ValueType::I32]; let params = vec![ValueType::I32];
let locals = Locals::new(&params, &[]); let locals = Locals::new(&params, &[]).unwrap();
assert_matches!(locals.type_of_local(0), Ok(ValueType::I32)); assert_matches!(locals.type_of_local(0), Ok(ValueType::I32));
assert_matches!(locals.type_of_local(1), Err(_)); assert_matches!(locals.type_of_local(1), Err(_));
@ -105,7 +107,7 @@ mod tests {
#[test] #[test]
fn locals_no_params() { fn locals_no_params() {
let local_groups = vec![Local::new(2, ValueType::I32), Local::new(3, ValueType::I64)]; let local_groups = vec![Local::new(2, ValueType::I32), Local::new(3, ValueType::I64)];
let locals = Locals::new(&[], &local_groups); let locals = Locals::new(&[], &local_groups).unwrap();
assert_matches!(locals.type_of_local(0), Ok(ValueType::I32)); assert_matches!(locals.type_of_local(0), Ok(ValueType::I32));
assert_matches!(locals.type_of_local(1), Ok(ValueType::I32)); assert_matches!(locals.type_of_local(1), Ok(ValueType::I32));
@ -121,7 +123,7 @@ mod tests {
Local::new(u32::max_value(), ValueType::I32), Local::new(u32::max_value(), ValueType::I32),
Local::new(1, ValueType::I64), Local::new(1, ValueType::I64),
]; ];
let locals = Locals::new(&[], &local_groups); let locals = Locals::new(&[], &local_groups).unwrap();
assert_matches!( assert_matches!(
locals.type_of_local(u32::max_value() - 1), locals.type_of_local(u32::max_value() - 1),