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
use crate::operators_validator::{FunctionEnd, OperatorValidator}; use crate::{BinaryReader, BinaryReaderError, Result, Type}; use crate::{FunctionBody, Operator, WasmFeatures, WasmModuleResources}; /// Validation context for a WebAssembly function. /// /// This structure is created by /// [`Validator::code_section_entry`](crate::Validator::code_section_entry) /// and is created per-function in a WebAssembly module. This structure is /// suitable for sending to other threads while the original /// [`Validator`](crate::Validator) continues processing other functions. pub struct FuncValidator<T> { validator: OperatorValidator, resources: T, eof_found: bool, } impl<T: WasmModuleResources> FuncValidator<T> { /// Creates a new `FuncValidator`. /// /// The returned `FuncValidator` can be used to validate a function with /// the type `ty` specified. The `resources` indicate what the containing /// module has for the function to use, and the `features` configure what /// WebAssembly proposals are enabled for this function. /// /// The returned validator can be used to then parse a [`FunctionBody`], for /// example, to read locals and validate operators. pub fn new(ty: &T::FuncType, resources: T, features: &WasmFeatures) -> FuncValidator<T> { FuncValidator { validator: OperatorValidator::new(ty, features), resources, eof_found: false, } } /// Convenience function to validate an entire function's body. /// /// You may not end up using this in final implementations because you'll /// often want to interleave validation with parsing. pub fn validate(&mut self, body: &FunctionBody<'_>) -> Result<()> { let mut reader = body.get_binary_reader(); self.read_locals(&mut reader)?; while !reader.eof() { let pos = reader.original_position(); let op = reader.read_operator()?; self.op(pos, &op)?; } self.finish(reader.original_position()) } /// Reads the local defintions from the given `BinaryReader`, often sourced /// from a `FunctionBody`. /// /// This function will automatically advance the `BinaryReader` forward, /// leaving reading operators up to the caller afterwards. pub fn read_locals(&mut self, reader: &mut BinaryReader<'_>) -> Result<()> { for _ in 0..reader.read_var_u32()? { let offset = reader.original_position(); let cnt = reader.read_var_u32()?; let ty = reader.read_type()?; self.define_locals(offset, cnt, ty)?; } Ok(()) } /// Defines locals into this validator. /// /// This should be used if the application is already reading local /// definitions and there's no need to re-parse the function again. pub fn define_locals(&mut self, offset: usize, count: u32, ty: Type) -> Result<()> { self.validator.define_locals(offset, count, ty) } /// Validates the next operator in a function. /// /// This functions is expected to be called once-per-operator in a /// WebAssembly function. Each operator's offset in the original binary and /// the operator itself are passed to this function to provide more useful /// error messages. pub fn op(&mut self, offset: usize, operator: &Operator<'_>) -> Result<()> { let end = self .validator .process_operator(operator, &self.resources) .map_err(|e| e.set_offset(offset))?; match end { FunctionEnd::Yes => self.eof_found = true, FunctionEnd::No => {} } Ok(()) } /// Function that must be called after the last opcode has been processed. /// /// This will validate that the function was properly terminated with the /// `end` opcode. If this function is not called then the function will not /// be properly validated. /// /// The `offset` provided to this function will be used as a position for an /// error if validation fails. pub fn finish(&mut self, offset: usize) -> Result<()> { if !self.eof_found { return Err(BinaryReaderError::new("end of function not found", offset)); } Ok(()) } /// Returns the underlying module resources that this validator is using. pub fn resources(&self) -> &T { &self.resources } }