@@ -20,6 +20,7 @@ use crate::{
2020use bitflags:: bitflags;
2121use std:: mem;
2222use std:: ops:: Range ;
23+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
2324use std:: sync:: Arc ;
2425
2526/// Test whether the given buffer contains a valid WebAssembly module or component,
@@ -86,6 +87,23 @@ fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
8687 }
8788}
8889
90+ /// A unique identifier for a particular `Validator`.
91+ ///
92+ /// Allows you to save the `ValidatorId` of the [`Validator`][crate::Validator]
93+ /// you get identifiers out of (e.g. [`CoreTypeId`][crate::types::CoreTypeId])
94+ /// and then later assert that you are pairing those identifiers with the same
95+ /// `Validator` instance when accessing the identifier's associated data.
96+ #[ derive( Clone , Copy , PartialEq , Eq , Debug , Hash , PartialOrd , Ord ) ]
97+ pub struct ValidatorId ( usize ) ;
98+
99+ impl Default for ValidatorId {
100+ #[ inline]
101+ fn default ( ) -> Self {
102+ static ID_COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
103+ ValidatorId ( ID_COUNTER . fetch_add ( 1 , Ordering :: AcqRel ) )
104+ }
105+ }
106+
89107/// Validator for a WebAssembly binary module or component.
90108///
91109/// This structure encapsulates state necessary to validate a WebAssembly
@@ -113,6 +131,8 @@ fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
113131/// [core]: https://webassembly.github.io/spec/core/valid/index.html
114132#[ derive( Default ) ]
115133pub struct Validator {
134+ id : ValidatorId ,
135+
116136 /// The current state of the validator.
117137 state : State ,
118138
@@ -484,6 +504,100 @@ impl Validator {
484504 & self . features
485505 }
486506
507+ /// Reset this validator's state such that it is ready to validate a new
508+ /// Wasm module or component.
509+ ///
510+ /// This does *not* clear or reset the internal state keeping track of
511+ /// validated (and deduplicated and canonicalized) types, allowing you to
512+ /// use the same type identifiers (such as
513+ /// [`CoreTypeId`][crate::types::CoreTypeId]) for the same types that are
514+ /// defined multiple times across different modules and components.
515+ ///
516+ /// ```
517+ /// fn foo() -> anyhow::Result<()> {
518+ /// use wasmparser::Validator;
519+ ///
520+ /// let mut validator = Validator::default();
521+ ///
522+ /// // Two wasm modules, both of which define the same type, but at
523+ /// // different indices in their respective types index spaces.
524+ /// let wasm1 = wat::parse_str("
525+ /// (module
526+ /// (type $same_type (func (param i32) (result f64)))
527+ /// )
528+ /// ")?;
529+ /// let wasm2 = wat::parse_str("
530+ /// (module
531+ /// (type $different_type (func))
532+ /// (type $same_type (func (param i32) (result f64)))
533+ /// )
534+ /// ")?;
535+ ///
536+ /// // Validate the first Wasm module and get the ID of its type.
537+ /// let types = validator.validate_all(&wasm1)?;
538+ /// let id1 = types.core_type_at(0);
539+ ///
540+ /// // Reset the validator so we can parse the second wasm module inside
541+ /// // this validator's same context.
542+ /// validator.reset();
543+ ///
544+ /// // Validate the second Wasm module and get the ID of its second type,
545+ /// // which is the same type as the first Wasm module's only type.
546+ /// let types = validator.validate_all(&wasm2)?;
547+ /// let id2 = types.core_type_at(1);
548+ ///
549+ /// // Because both modules were processed in the same `Validator`, they
550+ /// // share the same types context and therefore the same type defined
551+ /// // multiple times across different modules will be deduplicated and
552+ /// // assigned the same identifier!
553+ /// assert_eq!(id1, id2);
554+ /// assert_eq!(types[id1.unwrap_sub()], types[id2.unwrap_sub()]);
555+ /// # Ok(())
556+ /// # }
557+ /// # foo().unwrap()
558+ /// ```
559+ pub fn reset ( & mut self ) {
560+ let Validator {
561+ // Not changing the identifier; users should be able to observe that
562+ // they are using the same validation context, even after resetting.
563+ id : _,
564+
565+ // Don't mess with `types`, we specifically want to reuse canonicalizations.
566+ types : _,
567+
568+ // Also leave features as they are. While this is perhaps not
569+ // strictly necessary, it helps us avoid weird bugs where we have
570+ // different views of what is or is not a valid type at different
571+ // times, despite using the same `TypeList` and hash consing
572+ // context, and therefore there could be moments in time where we
573+ // have "invalid" types inside our current types list.
574+ features : _,
575+
576+ state,
577+ module,
578+ components,
579+ } = self ;
580+
581+ assert ! (
582+ matches!( state, State :: End ) ,
583+ "cannot reset a validator that did not successfully complete validation"
584+ ) ;
585+ assert ! ( module. is_none( ) ) ;
586+ assert ! ( components. is_empty( ) ) ;
587+
588+ * state = State :: default ( ) ;
589+ }
590+
591+ /// Get this validator's unique identifier.
592+ ///
593+ /// Allows you to assert that you are always working with the same
594+ /// `Validator` instance, when you can't otherwise statically ensure that
595+ /// property by e.g. storing a reference to the validator inside your
596+ /// structure.
597+ pub fn id ( & self ) -> ValidatorId {
598+ self . id
599+ }
600+
487601 /// Validates an entire in-memory module or component with this validator.
488602 ///
489603 /// This function will internally create a [`Parser`] to parse the `bytes`
@@ -530,7 +644,7 @@ impl Validator {
530644 pub fn types ( & self , mut level : usize ) -> Option < TypesRef > {
531645 if let Some ( module) = & self . module {
532646 if level == 0 {
533- return Some ( TypesRef :: from_module ( & self . types , & module. module ) ) ;
647+ return Some ( TypesRef :: from_module ( self . id , & self . types , & module. module ) ) ;
534648 } else {
535649 level -= 1 ;
536650 }
@@ -539,7 +653,7 @@ impl Validator {
539653 self . components
540654 . iter ( )
541655 . nth_back ( level)
542- . map ( |component| TypesRef :: from_component ( & self . types , component) )
656+ . map ( |component| TypesRef :: from_component ( self . id , & self . types , component) )
543657 }
544658
545659 /// Convenience function to validate a single [`Payload`].
@@ -1372,6 +1486,7 @@ impl Validator {
13721486 }
13731487
13741488 Ok ( Types :: from_module (
1489+ self . id ,
13751490 self . types . commit ( ) ,
13761491 state. module . arc ( ) . clone ( ) ,
13771492 ) )
@@ -1396,7 +1511,11 @@ impl Validator {
13961511 self . state = State :: Component ;
13971512 }
13981513
1399- Ok ( Types :: from_component ( self . types . commit ( ) , component) )
1514+ Ok ( Types :: from_component (
1515+ self . id ,
1516+ self . types . commit ( ) ,
1517+ component,
1518+ ) )
14001519 }
14011520 }
14021521 }
0 commit comments