Skip to content

Commit dd07a4b

Browse files
pchickeyyurydelendik
authored andcommitted
validator::{validate, validate_function_body} return Result instead of bool (bytecodealliance#133)
* validator::validate, validate_function_body return Result instead of bool so that we can communicate to users the reason and offset of validation failure. * validator: change tests to check result, rather than assert a bool
1 parent cc08289 commit dd07a4b

1 file changed

Lines changed: 47 additions & 46 deletions

File tree

src/validator.rs

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -793,67 +793,72 @@ impl<'b> ValidatingOperatorParser<'b> {
793793
/// The resources parameter contains all needed data to validate the operators.
794794
pub fn validate_function_body(
795795
bytes: &[u8],
796+
offset: usize,
796797
func_index: u32,
797798
resources: &dyn WasmModuleResources,
798799
operator_config: Option<OperatorValidatorConfig>,
799-
) -> bool {
800+
) -> Result<()> {
800801
let operator_config = operator_config.unwrap_or(DEFAULT_OPERATOR_VALIDATOR_CONFIG);
801-
let function_body = FunctionBody::new(0, bytes);
802-
let mut locals_reader = if let Ok(r) = function_body.get_locals_reader() {
803-
r
804-
} else {
805-
return false;
806-
};
802+
let function_body = FunctionBody::new(offset, bytes);
803+
let mut locals_reader = function_body.get_locals_reader()?;
807804
let local_count = locals_reader.get_count() as usize;
808805
if local_count > MAX_WASM_FUNCTION_LOCALS {
809-
return false;
806+
Err(BinaryReaderError {
807+
message: "locals exceed maximum",
808+
offset: locals_reader.original_position(),
809+
})?;
810810
}
811811
let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
812812
let mut locals_total: usize = 0;
813813
for _ in 0..local_count {
814-
let (count, ty) = if let Ok(r) = locals_reader.read() {
815-
r
816-
} else {
817-
return false;
818-
};
819-
locals_total = if let Some(r) = locals_total.checked_add(count as usize) {
820-
r
821-
} else {
822-
return false;
823-
};
814+
let (count, ty) = locals_reader.read()?;
815+
locals_total =
816+
locals_total
817+
.checked_add(count as usize)
818+
.ok_or_else(|| BinaryReaderError {
819+
message: "locals overflow",
820+
offset: locals_reader.original_position(),
821+
})?;
824822
if locals_total > MAX_WASM_FUNCTION_LOCALS {
825-
return false;
823+
Err(BinaryReaderError {
824+
message: "locals exceed maximum",
825+
offset: locals_reader.original_position(),
826+
})?;
826827
}
827828
locals.push((count, ty));
828829
}
829-
let operators_reader = if let Ok(r) = function_body.get_operators_reader() {
830-
r
831-
} else {
832-
return false;
833-
};
830+
let operators_reader = function_body.get_operators_reader()?;
834831
let func_type_index = resources.func_type_indices()[func_index as usize];
835832
let func_type = &resources.types()[func_type_index as usize];
836833
let mut operator_validator = OperatorValidator::new(func_type, &locals, operator_config);
837834
let mut eof_found = false;
838-
for op in operators_reader.into_iter() {
839-
let op = match op {
840-
Err(_) => return false,
841-
Ok(ref op) => op,
842-
};
843-
match operator_validator.process_operator(op, resources) {
844-
Err(_) => return false,
845-
Ok(FunctionEnd::Yes) => {
835+
let mut last_op = 0;
836+
for item in operators_reader.into_iter_with_offsets() {
837+
let (ref op, offset) = item?;
838+
match operator_validator
839+
.process_operator(op, resources)
840+
.map_err(|message| BinaryReaderError { message, offset })?
841+
{
842+
FunctionEnd::Yes => {
846843
eof_found = true;
847844
}
848-
Ok(FunctionEnd::No) => (),
845+
FunctionEnd::No => {
846+
last_op = offset;
847+
}
849848
}
850849
}
851-
eof_found
850+
if !eof_found {
851+
Err(BinaryReaderError {
852+
message: "end of function not found",
853+
offset: last_op,
854+
})?;
855+
}
856+
Ok(())
852857
}
853858

854859
/// Test whether the given buffer contains a valid WebAssembly module,
855860
/// analogous to WebAssembly.validate in the JS API.
856-
pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> bool {
861+
pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> Result<()> {
857862
let mut parser = ValidatingParser::new(bytes, config);
858863
let mut parser_input = None;
859864
let mut func_ranges = Vec::new();
@@ -862,7 +867,7 @@ pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> bool {
862867
let state = parser.read_with_input(next_input);
863868
match *state {
864869
ParserState::EndWasm => break,
865-
ParserState::Error(_) => return false,
870+
ParserState::Error(e) => Err(e)?,
866871
ParserState::BeginFunctionBody { range } => {
867872
parser_input = Some(ParserInput::SkipFunctionBody);
868873
func_ranges.push(range);
@@ -874,23 +879,19 @@ pub fn validate(bytes: &[u8], config: Option<ValidatingParserConfig>) -> bool {
874879
for (i, range) in func_ranges.into_iter().enumerate() {
875880
let function_body = range.slice(bytes);
876881
let function_index = i as u32 + parser.func_imports_count;
877-
if !validate_function_body(
882+
validate_function_body(
878883
function_body,
884+
range.start,
879885
function_index,
880886
&parser.resources,
881887
operator_config,
882-
) {
883-
return false;
884-
}
888+
)?;
885889
}
886-
true
890+
Ok(())
887891
}
888892

889893
#[test]
890894
fn test_validate() {
891-
assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0], None));
892-
assert!(!validate(
893-
&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0],
894-
None
895-
));
895+
assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0], None).is_ok());
896+
assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0], None).is_err());
896897
}

0 commit comments

Comments
 (0)