/// Resources necessary to perform validation of a 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. #[derive(Debug)] pubstruct FuncToValidate<T> { /// Reusable, heap allocated resources to drive the Wasm validation. pub resources: T, /// The core Wasm function index being validated. pub index: u32, /// The core Wasm type index of the function being validated, /// defining the results and parameters to the function. pub ty: u32, /// The Wasm features enabled to validate the function. pub features: WasmFeatures,
}
impl<T: WasmModuleResources> FuncToValidate<T> { /// Converts this [`FuncToValidate`] into a [`FuncValidator`] using the /// `allocs` provided. /// /// This method, in conjunction with [`FuncValidator::into_allocations`], /// provides a means to reuse allocations across validation of each /// individual function. Note that it is also sufficient to call this /// method with `Default::default()` if no prior allocations are /// available. /// /// # Panics /// /// If a `FuncToValidate` was created with an invalid `ty` index then this /// function will panic. pubfn into_validator(self, allocs: FuncValidatorAllocations) -> FuncValidator<T> { let FuncToValidate {
resources,
index,
ty,
features,
} = self; let validator =
OperatorValidator::new_func(ty, 0, &features, &resources, allocs.0).unwrap();
FuncValidator {
validator,
resources,
index,
}
}
}
/// Validation context for a WebAssembly function. /// /// This is a finalized validator which is ready to process a [`FunctionBody`]. /// This is created from the [`FuncToValidate::into_validator`] method. pubstruct FuncValidator<T> {
validator: OperatorValidator,
resources: T,
index: u32,
}
/// External handle to the internal allocations used during function validation. /// /// This is created with either the `Default` implementation or with /// [`FuncValidator::into_allocations`]. It is then passed as an argument to /// [`FuncToValidate::into_validator`] to provide a means of reusing allocations /// between each function. #[derive(Default)] pubstruct FuncValidatorAllocations(OperatorValidatorAllocations);
impl<T: WasmModuleResources> FuncValidator<T> { /// 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. pubfn validate(&mutself, body: &FunctionBody<'_>) -> Result<()> { letmut reader = body.get_binary_reader(); self.read_locals(&mut reader)?; #[cfg(feature = "features")]
{
reader.set_features(self.validator.features);
} while !reader.eof() { // In a debug build, verify that the validator's pops and pushes to and from // the operand stack match the operator's arity. #[cfg(debug_assertions)] let (pop_push_snapshot, arity) = ( self.validator.pop_push_count,
reader
.clone()
.read_operator()?
.operator_arity(&self.visitor(reader.original_position())),
);
/// Reads the local definitions 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. pubfn read_locals(&mutself, reader: &mut BinaryReader<'_>) -> Result<()> { for _ in0..reader.read_var_u32()? { let offset = reader.original_position(); let cnt = reader.read()?; let ty = reader.read()?; 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. pubfn define_locals(&mutself, offset: usize, count: u32, ty: ValType) -> Result<()> { self.validator
.define_locals(offset, count, ty, &self.resources)
}
/// 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. pubfn op(&mutself, offset: usize, operator: &Operator<'_>) -> Result<()> { self.visitor(offset).visit_operator(operator)
}
/// Get the operator visitor for the next operator in the function. /// /// The returned visitor is intended to visit just one instruction at the `offset`. /// /// # Example /// /// ``` /// # use wasmparser::{WasmModuleResources, FuncValidator, FunctionBody, Result}; /// pub fn validate<R>(validator: &mut FuncValidator<R>, body: &FunctionBody<'_>) -> Result<()> /// where R: WasmModuleResources /// { /// let mut operator_reader = body.get_binary_reader(); /// while !operator_reader.eof() { /// let mut visitor = validator.visitor(operator_reader.original_position()); /// operator_reader.visit_operator(&mut visitor)??; /// } /// validator.finish(operator_reader.original_position()) /// } /// ``` pubfn visitor<'this, 'a: 'this>(
&'this mut self,
offset: usize,
) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + 'this { self.validator.with_resources(&self.resources, offset)
}
/// 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. pubfn finish(&mutself, offset: usize) -> Result<()> { self.validator.finish(offset)
}
/// Returns the Wasm features enabled for this validator. pubfn features(&self) -> &WasmFeatures {
&self.validator.features
}
/// Returns the underlying module resources that this validator is using. pubfn resources(&self) -> &T {
&self.resources
}
/// The index of the function within the module's function index space that /// is being validated. pubfn index(&self) -> u32 { self.index
}
/// Returns the number of defined local variables in the function. pubfn len_locals(&self) -> u32 { self.validator.locals.len_locals()
}
/// Returns the type of the local variable at the given `index` if any. pubfn get_local_type(&self, index: u32) -> Option<ValType> { self.validator.locals.get(index)
}
/// Get the current height of the operand stack. /// /// This returns the height of the whole operand stack for this function, /// not just for the current control frame. pubfn operand_stack_height(&self) -> u32 { self.validator.operand_stack_height() as u32
}
/// Returns the optional value type of the value operand at the given /// `depth` from the top of the operand stack. /// /// - Returns `None` if the `depth` is out of bounds. /// - Returns `Some(None)` if there is a value with unknown type /// at the given `depth`. /// /// # Note /// /// A `depth` of 0 will refer to the last operand on the stack. pubfn get_operand_type(&self, depth: usize) -> Option<Option<ValType>> { self.validator.peek_operand_at(depth)
}
/// Returns the number of frames on the control flow stack. /// /// This returns the height of the whole control stack for this function, /// not just for the current control frame. pubfn control_stack_height(&self) -> u32 { self.validator.control_stack_height() as u32
}
/// Returns a shared reference to the control flow [`Frame`] of the /// control flow stack at the given `depth` if any. /// /// Returns `None` if the `depth` is out of bounds. /// /// # Note /// /// A `depth` of 0 will refer to the last frame on the stack. pubfn get_control_frame(&self, depth: usize) -> Option<&Frame> { self.validator.get_frame(depth)
}
/// Consumes this validator and returns the underlying allocations that /// were used during the validation process. /// /// The returned value here can be paired with /// [`FuncToValidate::into_validator`] to reuse the allocations already /// created by this validator. pubfn into_allocations(self) -> FuncValidatorAllocations {
FuncValidatorAllocations(self.validator.into_allocations())
}
}
#[cfg(test)] mod tests { usesuper::*; usecrate::types::CoreTypeId; usecrate::{HeapType, RefType};
// Initially zero values on the stack.
assert_eq!(v.operand_stack_height(), 0);
// Pushing a constant value makes use have one value on the stack.
assert!(v.op(0, &Operator::I32Const { value: 0 }).is_ok());
assert_eq!(v.operand_stack_height(), 1);
// Entering a new control block does not affect the stack height.
assert!(v
.op( 1,
&Operator::Block {
blockty: crate::BlockType::Empty
}
)
.is_ok());
assert_eq!(v.operand_stack_height(), 1);
// Pushing another constant value makes use have two values on the stack.
assert!(v.op(2, &Operator::I32Const { value: 99 }).is_ok());
assert_eq!(v.operand_stack_height(), 2);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-24)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.