Skip to main content

wasmparser/
validator.rs

1/* Copyright 2018 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16use crate::prelude::*;
17use crate::{
18    AbstractHeapType, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser,
19    Payload, RefType, Result, SectionLimited, ValType, WASM_MODULE_VERSION, WasmFeatures,
20    limits::*,
21};
22use ::core::mem;
23use ::core::ops::Range;
24use ::core::sync::atomic::{AtomicUsize, Ordering};
25use alloc::sync::Arc;
26
27/// Test whether the given buffer contains a valid WebAssembly module or component,
28/// analogous to [`WebAssembly.validate`][js] in the JS API.
29///
30/// This functions requires the bytes to validate are entirely resident in memory.
31/// Additionally this validates the given bytes with the default set of WebAssembly
32/// features implemented by `wasmparser`.
33///
34/// For more fine-tuned control over validation it's recommended to review the
35/// documentation of [`Validator`].
36///
37/// Upon success, the type information for the top-level module or component will
38/// be returned.
39///
40/// [js]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/validate
41pub fn validate(bytes: &[u8]) -> Result<Types> {
42    Validator::new().validate_all(bytes)
43}
44
45#[test]
46fn test_validate() {
47    assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0]).is_ok());
48    assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0]).is_err());
49}
50
51#[cfg(feature = "component-model")]
52mod component;
53#[cfg(feature = "component-model")]
54pub mod component_types;
55mod core;
56mod func;
57#[cfg(feature = "component-model")]
58pub mod names;
59mod operators;
60pub mod types;
61
62#[cfg(feature = "component-model")]
63use self::component::*;
64pub use self::core::ValidatorResources;
65use self::core::*;
66use self::types::{TypeAlloc, Types, TypesRef};
67pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
68pub use operators::Frame;
69
70fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
71    if max
72        .checked_sub(cur_len)
73        .and_then(|amt| amt.checked_sub(amt_added as usize))
74        .is_none()
75    {
76        if max == 1 {
77            bail!(offset, "multiple {desc}");
78        }
79
80        bail!(offset, "{desc} count exceeds limit of {max}");
81    }
82
83    Ok(())
84}
85
86fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
87    match a.checked_add(b) {
88        Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
89        _ => Err(format_err!(
90            offset,
91            "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
92        )),
93    }
94}
95
96/// A unique identifier for a particular `Validator`.
97///
98/// Allows you to save the `ValidatorId` of the [`Validator`][crate::Validator]
99/// you get identifiers out of (e.g. [`CoreTypeId`][crate::types::CoreTypeId])
100/// and then later assert that you are pairing those identifiers with the same
101/// `Validator` instance when accessing the identifier's associated data.
102#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
103pub struct ValidatorId(usize);
104
105impl Default for ValidatorId {
106    #[inline]
107    fn default() -> Self {
108        static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
109        ValidatorId(ID_COUNTER.fetch_add(1, Ordering::AcqRel))
110    }
111}
112
113/// Validator for a WebAssembly binary module or component.
114///
115/// This structure encapsulates state necessary to validate a WebAssembly
116/// binary. This implements validation as defined by the [core
117/// specification][core]. A `Validator` is designed, like
118/// [`Parser`], to accept incremental input over time.
119/// Additionally a `Validator` is also designed for parallel validation of
120/// functions as they are received.
121///
122/// It's expected that you'll be using a [`Parser`] in tandem with a
123/// `Validator`. As each [`Payload`](crate::Payload) is received from a
124/// [`Parser`] you'll pass it into a `Validator` to test the validity of the
125/// payload. Note that all payloads received from a [`Parser`] are expected to
126/// be passed to a [`Validator`]. For example if you receive
127/// [`Payload::TypeSection`](crate::Payload) you'll call
128/// [`Validator::type_section`] to validate this.
129///
130/// The design of [`Validator`] is intended that you'll interleave, in your own
131/// application's processing, calls to validation. Each variant, after it's
132/// received, will be validated and then your application would proceed as
133/// usual. At all times, however, you'll have access to the [`Validator`] and
134/// the validation context up to that point. This enables applications to check
135/// the types of functions and learn how many globals there are, for example.
136///
137/// [core]: https://webassembly.github.io/spec/core/valid/index.html
138#[derive(Default)]
139pub struct Validator {
140    id: ValidatorId,
141
142    /// The current state of the validator.
143    state: State,
144
145    /// The global type space used by the validator and any sub-validators.
146    types: TypeAlloc,
147
148    /// The module state when parsing a WebAssembly module.
149    module: Option<ModuleState>,
150
151    /// With the component model enabled, this stores the pushed component states.
152    /// The top of the stack is the current component state.
153    #[cfg(feature = "component-model")]
154    components: Vec<ComponentState>,
155
156    /// Enabled WebAssembly feature flags, dictating what's valid and what
157    /// isn't.
158    features: WasmFeatures,
159}
160
161#[derive(Debug, Clone, Copy, Eq, PartialEq)]
162enum State {
163    /// A header has not yet been parsed.
164    ///
165    /// The value is the expected encoding for the header.
166    Unparsed(Option<Encoding>),
167    /// A module header has been parsed.
168    ///
169    /// The associated module state is available via [`Validator::module`].
170    Module,
171    /// A component header has been parsed.
172    ///
173    /// The associated component state exists at the top of the
174    /// validator's [`Validator::components`] stack.
175    #[cfg(feature = "component-model")]
176    Component,
177    /// The parse has completed and no more data is expected.
178    End,
179}
180
181impl State {
182    fn ensure_parsable(&self, offset: usize) -> Result<()> {
183        match self {
184            Self::Module => Ok(()),
185            #[cfg(feature = "component-model")]
186            Self::Component => Ok(()),
187            Self::Unparsed(_) => Err(BinaryReaderError::new(
188                "unexpected section before header was parsed",
189                offset,
190            )),
191            Self::End => Err(BinaryReaderError::new(
192                "unexpected section after parsing has completed",
193                offset,
194            )),
195        }
196    }
197
198    fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
199        self.ensure_parsable(offset)?;
200        let _ = section;
201
202        match self {
203            Self::Module => Ok(()),
204            #[cfg(feature = "component-model")]
205            Self::Component => Err(format_err!(
206                offset,
207                "unexpected module {section} section while parsing a component",
208            )),
209            _ => unreachable!(),
210        }
211    }
212
213    #[cfg(feature = "component-model")]
214    fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
215        self.ensure_parsable(offset)?;
216
217        match self {
218            Self::Component => Ok(()),
219            Self::Module => Err(format_err!(
220                offset,
221                "unexpected component {section} section while parsing a module",
222            )),
223            _ => unreachable!(),
224        }
225    }
226}
227
228impl Default for State {
229    fn default() -> Self {
230        Self::Unparsed(None)
231    }
232}
233
234impl WasmFeatures {
235    /// NOTE: This only checks that the value type corresponds to the feature set!!
236    ///
237    /// To check that reference types are valid, we need access to the module
238    /// types. Use module.check_value_type.
239    pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
240        match ty {
241            ValType::I32 | ValType::I64 => Ok(()),
242            ValType::F32 | ValType::F64 => {
243                if self.floats() {
244                    Ok(())
245                } else {
246                    Err("floating-point support is disabled")
247                }
248            }
249            ValType::Ref(r) => self.check_ref_type(r),
250            ValType::V128 => {
251                if self.simd() {
252                    Ok(())
253                } else {
254                    Err("SIMD support is not enabled")
255                }
256            }
257        }
258    }
259
260    pub(crate) fn check_ref_type(&self, r: RefType) -> Result<(), &'static str> {
261        if !self.reference_types() {
262            return Err("reference types support is not enabled");
263        }
264        match r.heap_type() {
265            HeapType::Concrete(_) => {
266                // Note that `self.gc_types()` is not checked here because
267                // concrete pointers to function types are allowed. GC types
268                // are disallowed by instead rejecting the definition of
269                // array/struct types and only allowing the definition of
270                // function types.
271
272                // Indexed types require either the function-references or gc
273                // proposal as gc implies function references here.
274                if self.function_references() || self.gc() {
275                    Ok(())
276                } else {
277                    Err("function references required for index reference types")
278                }
279            }
280            HeapType::Exact(_) => {
281                // Exact types were introduced with the custom descriptors
282                // proposal.
283                if self.custom_descriptors() {
284                    Ok(())
285                } else {
286                    Err("custom descriptors required for exact reference types")
287                }
288            }
289            HeapType::Abstract { shared, ty } => {
290                use AbstractHeapType::*;
291                if shared && !self.shared_everything_threads() {
292                    return Err(
293                        "shared reference types require the shared-everything-threads proposal",
294                    );
295                }
296
297                // Apply the "gc-types" feature which disallows all heap types
298                // except exnref/funcref.
299                if !self.gc_types() && ty != Func && ty != Exn {
300                    return Err("gc types are disallowed but found type which requires gc");
301                }
302
303                match (ty, r.is_nullable()) {
304                    // funcref/externref only require `reference-types`.
305                    (Func, true) | (Extern, true) => Ok(()),
306
307                    // Non-nullable func/extern references requires the
308                    // `function-references` proposal.
309                    (Func | Extern, false) => {
310                        if self.function_references() {
311                            Ok(())
312                        } else {
313                            Err("function references required for non-nullable types")
314                        }
315                    }
316
317                    // These types were added in the gc proposal.
318                    (Any | None | Eq | Struct | Array | I31 | NoExtern | NoFunc, _) => {
319                        if self.gc() {
320                            Ok(())
321                        } else {
322                            Err("heap types not supported without the gc feature")
323                        }
324                    }
325
326                    // These types were added in the exception-handling proposal.
327                    (Exn | NoExn, _) => {
328                        if self.exceptions() {
329                            Ok(())
330                        } else {
331                            Err(
332                                "exception refs not supported without the exception handling feature",
333                            )
334                        }
335                    }
336
337                    // These types were added in the stack switching proposal.
338                    (Cont | NoCont, _) => {
339                        if self.stack_switching() {
340                            Ok(())
341                        } else {
342                            Err(
343                                "continuation refs not supported without the stack switching feature",
344                            )
345                        }
346                    }
347                }
348            }
349        }
350    }
351}
352
353/// Possible return values from [`Validator::payload`].
354#[allow(clippy::large_enum_variant)]
355pub enum ValidPayload<'a> {
356    /// The payload validated, no further action need be taken.
357    Ok,
358    /// The payload validated, but it started a nested module or component.
359    ///
360    /// This result indicates that the specified parser should be used instead
361    /// of the currently-used parser until this returned one ends.
362    Parser(Parser),
363    /// A function was found to be validated.
364    Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
365    /// The end payload was validated and the types known to the validator
366    /// are provided.
367    End(Types),
368}
369
370impl Validator {
371    /// Creates a new [`Validator`] ready to validate a WebAssembly module
372    /// or component.
373    ///
374    /// The new validator will receive payloads parsed from
375    /// [`Parser`], and expects the first payload received to be
376    /// the version header from the parser.
377    pub fn new() -> Validator {
378        Validator::default()
379    }
380
381    /// Creates a new [`Validator`] which has the specified set of wasm
382    /// features activated for validation.
383    ///
384    /// This function is the same as [`Validator::new`] except it also allows
385    /// you to customize the active wasm features in use for validation. This
386    /// can allow enabling experimental proposals or also turning off
387    /// on-by-default wasm proposals.
388    pub fn new_with_features(features: WasmFeatures) -> Validator {
389        let mut ret = Validator::new();
390        ret.features = features;
391        ret
392    }
393
394    /// Returns the wasm features used for this validator.
395    pub fn features(&self) -> &WasmFeatures {
396        &self.features
397    }
398
399    /// Reset this validator's state such that it is ready to validate a new
400    /// Wasm module or component.
401    ///
402    /// This does *not* clear or reset the internal state keeping track of
403    /// validated (and deduplicated and canonicalized) types, allowing you to
404    /// use the same type identifiers (such as
405    /// [`CoreTypeId`][crate::types::CoreTypeId]) for the same types that are
406    /// defined multiple times across different modules and components.
407    ///
408    /// # Panics
409    ///
410    /// This function will panic if the validator was mid-way through
411    /// validating a binary. Validation must complete entirely or not have
412    /// started at all for this method to be called.
413    ///
414    /// # Examples
415    ///
416    /// ```
417    /// fn foo() -> anyhow::Result<()> {
418    /// use wasmparser::Validator;
419    ///
420    /// let mut validator = Validator::default();
421    ///
422    /// // Two wasm modules, both of which define the same type, but at
423    /// // different indices in their respective types index spaces.
424    /// let wasm1 = wat::parse_str("
425    ///     (module
426    ///         (type $same_type (func (param i32) (result f64)))
427    ///     )
428    /// ")?;
429    /// let wasm2 = wat::parse_str("
430    ///     (module
431    ///         (type $different_type (func))
432    ///         (type $same_type (func (param i32) (result f64)))
433    ///     )
434    /// ")?;
435    ///
436    /// // Validate the first Wasm module and get the ID of its type.
437    /// let types = validator.validate_all(&wasm1)?;
438    /// let id1 = types.as_ref().core_type_at_in_module(0);
439    ///
440    /// // Reset the validator so we can parse the second wasm module inside
441    /// // this validator's same context.
442    /// validator.reset();
443    ///
444    /// // Validate the second Wasm module and get the ID of its second type,
445    /// // which is the same type as the first Wasm module's only type.
446    /// let types = validator.validate_all(&wasm2)?;
447    /// let id2 = types.as_ref().core_type_at_in_module(1);
448    ///
449    /// // Because both modules were processed in the same `Validator`, they
450    /// // share the same types context and therefore the same type defined
451    /// // multiple times across different modules will be deduplicated and
452    /// // assigned the same identifier!
453    /// assert_eq!(id1, id2);
454    /// assert_eq!(types[id1], types[id2]);
455    /// # Ok(())
456    /// # }
457    /// # foo().unwrap()
458    /// ```
459    pub fn reset(&mut self) {
460        let Validator {
461            // Not changing the identifier; users should be able to observe that
462            // they are using the same validation context, even after resetting.
463            id: _,
464
465            // Don't mess with `types`, we specifically want to reuse canonicalization.
466            types: _,
467
468            // Also leave features as they are. While this is perhaps not
469            // strictly necessary, it helps us avoid weird bugs where we have
470            // different views of what is or is not a valid type at different
471            // times, despite using the same `TypeList` and hash consing
472            // context, and therefore there could be moments in time where we
473            // have "invalid" types inside our current types list.
474            features: _,
475
476            state,
477            module,
478            #[cfg(feature = "component-model")]
479            components,
480        } = self;
481
482        assert!(
483            matches!(state, State::End) || matches!(state, State::Unparsed(None)),
484            "cannot reset a validator that did not successfully complete validation"
485        );
486        assert!(module.is_none());
487        #[cfg(feature = "component-model")]
488        assert!(components.is_empty());
489
490        *state = State::default();
491    }
492
493    /// Get this validator's unique identifier.
494    ///
495    /// Allows you to assert that you are always working with the same
496    /// `Validator` instance, when you can't otherwise statically ensure that
497    /// property by e.g. storing a reference to the validator inside your
498    /// structure.
499    pub fn id(&self) -> ValidatorId {
500        self.id
501    }
502
503    /// Validates an entire in-memory module or component with this validator.
504    ///
505    /// This function will internally create a [`Parser`] to parse the `bytes`
506    /// provided. The entire module or component specified by `bytes` will be
507    /// parsed and validated.
508    ///
509    /// Upon success, the type information for the top-level module or component
510    /// will be returned.
511    pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
512        let mut functions_to_validate = Vec::new();
513        let mut last_types = None;
514        let mut parser = Parser::new(0);
515        let _ = &mut parser;
516        #[cfg(feature = "features")]
517        parser.set_features(self.features);
518        for payload in parser.parse_all(bytes) {
519            match self.payload(&payload?)? {
520                ValidPayload::Func(a, b) => {
521                    functions_to_validate.push((a, b));
522                }
523                ValidPayload::End(types) => {
524                    // Only the last (top-level) type information will be returned
525                    last_types = Some(types);
526                }
527                _ => {}
528            }
529        }
530
531        let mut allocs = FuncValidatorAllocations::default();
532        for (func, body) in functions_to_validate {
533            let mut validator = func.into_validator(allocs);
534            validator.validate(&body)?;
535            allocs = validator.into_allocations();
536        }
537
538        Ok(last_types.unwrap())
539    }
540
541    /// Gets the types known by the validator so far within the
542    /// module/component `level` modules/components up from the
543    /// module/component currently being parsed.
544    ///
545    /// For instance, calling `validator.types(0)` will get the types of the
546    /// module/component currently being parsed, and `validator.types(1)` will
547    /// get the types of the component containing that module/component.
548    ///
549    /// Returns `None` if there is no module/component that many levels up.
550    pub fn types(&self, mut level: usize) -> Option<TypesRef<'_>> {
551        if let Some(module) = &self.module {
552            if level == 0 {
553                return Some(TypesRef::from_module(self.id, &self.types, &module.module));
554            } else {
555                level -= 1;
556                let _ = level;
557            }
558        }
559
560        #[cfg(feature = "component-model")]
561        return self
562            .components
563            .iter()
564            .nth_back(level)
565            .map(|component| TypesRef::from_component(self.id, &self.types, component));
566        #[cfg(not(feature = "component-model"))]
567        return None;
568    }
569
570    /// Convenience function to validate a single [`Payload`].
571    ///
572    /// This function is intended to be used as a convenience. It will
573    /// internally perform any validation necessary to validate the [`Payload`]
574    /// provided. The convenience part is that you're likely already going to
575    /// be matching on [`Payload`] in your application, at which point it's more
576    /// appropriate to call the individual methods on [`Validator`] per-variant
577    /// in [`Payload`], such as [`Validator::type_section`].
578    ///
579    /// This function returns a [`ValidPayload`] variant on success, indicating
580    /// one of a few possible actions that need to be taken after a payload is
581    /// validated. For example function contents are not validated here, they're
582    /// returned through [`ValidPayload`] for validation by the caller.
583    pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
584        use crate::Payload::*;
585        match payload {
586            Version {
587                num,
588                encoding,
589                range,
590            } => self.version(*num, *encoding, range)?,
591
592            // Module sections
593            TypeSection(s) => self.type_section(s)?,
594            ImportSection(s) => self.import_section(s)?,
595            FunctionSection(s) => self.function_section(s)?,
596            TableSection(s) => self.table_section(s)?,
597            MemorySection(s) => self.memory_section(s)?,
598            TagSection(s) => self.tag_section(s)?,
599            GlobalSection(s) => self.global_section(s)?,
600            ExportSection(s) => self.export_section(s)?,
601            StartSection { func, range } => self.start_section(*func, range)?,
602            ElementSection(s) => self.element_section(s)?,
603            DataCountSection { count, range } => self.data_count_section(*count, range)?,
604            CodeSectionStart {
605                count: _,
606                range,
607                size: _,
608            } => self.code_section_start(range)?,
609            CodeSectionEntry(body) => {
610                let func_validator = self.code_section_entry(body)?;
611                return Ok(ValidPayload::Func(func_validator, body.clone()));
612            }
613            DataSection(s) => self.data_section(s)?,
614
615            // Component sections
616            #[cfg(feature = "component-model")]
617            ModuleSection {
618                parser,
619                unchecked_range: range,
620                ..
621            } => {
622                self.module_section(range)?;
623                return Ok(ValidPayload::Parser(parser.clone()));
624            }
625            #[cfg(feature = "component-model")]
626            InstanceSection(s) => self.instance_section(s)?,
627            #[cfg(feature = "component-model")]
628            CoreTypeSection(s) => self.core_type_section(s)?,
629            #[cfg(feature = "component-model")]
630            ComponentSection {
631                parser,
632                unchecked_range: range,
633                ..
634            } => {
635                self.component_section(range)?;
636                return Ok(ValidPayload::Parser(parser.clone()));
637            }
638            #[cfg(feature = "component-model")]
639            ComponentInstanceSection(s) => self.component_instance_section(s)?,
640            #[cfg(feature = "component-model")]
641            ComponentAliasSection(s) => self.component_alias_section(s)?,
642            #[cfg(feature = "component-model")]
643            ComponentTypeSection(s) => self.component_type_section(s)?,
644            #[cfg(feature = "component-model")]
645            ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
646            #[cfg(feature = "component-model")]
647            ComponentStartSection { start, range } => self.component_start_section(start, range)?,
648            #[cfg(feature = "component-model")]
649            ComponentImportSection(s) => self.component_import_section(s)?,
650            #[cfg(feature = "component-model")]
651            ComponentExportSection(s) => self.component_export_section(s)?,
652
653            End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
654
655            CustomSection { .. } => {} // no validation for custom sections
656            UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
657        }
658        Ok(ValidPayload::Ok)
659    }
660
661    /// Validates [`Payload::Version`](crate::Payload).
662    pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
663        match &self.state {
664            State::Unparsed(expected) => {
665                if let Some(expected) = expected {
666                    if *expected != encoding {
667                        bail!(
668                            range.start,
669                            "expected a version header for a {}",
670                            match expected {
671                                Encoding::Module => "module",
672                                Encoding::Component => "component",
673                            }
674                        );
675                    }
676                }
677            }
678            _ => {
679                return Err(BinaryReaderError::new(
680                    "wasm version header out of order",
681                    range.start,
682                ));
683            }
684        }
685
686        self.state = match encoding {
687            Encoding::Module => {
688                if num == WASM_MODULE_VERSION {
689                    assert!(self.module.is_none());
690                    self.module = Some(ModuleState::new(self.features));
691                    State::Module
692                } else {
693                    bail!(range.start, "unknown binary version: {num:#x}");
694                }
695            }
696            Encoding::Component => {
697                if !self.features.component_model() {
698                    bail!(
699                        range.start,
700                        "unknown binary version and encoding combination: {num:#x} and 0x1, \
701                        note: encoded as a component but the WebAssembly component model feature \
702                        is not enabled - enable the feature to allow component validation",
703                    );
704                }
705                #[cfg(feature = "component-model")]
706                if num == crate::WASM_COMPONENT_VERSION {
707                    self.components
708                        .push(ComponentState::new(ComponentKind::Component, self.features));
709                    State::Component
710                } else if num < crate::WASM_COMPONENT_VERSION {
711                    bail!(range.start, "unsupported component version: {num:#x}");
712                } else {
713                    bail!(range.start, "unknown component version: {num:#x}");
714                }
715                #[cfg(not(feature = "component-model"))]
716                bail!(
717                    range.start,
718                    "component model validation support disabled \
719                     at compile time"
720                );
721            }
722        };
723
724        Ok(())
725    }
726
727    /// Validates [`Payload::TypeSection`](crate::Payload).
728    pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
729        self.process_module_section(
730            section,
731            "type",
732            |state, _types, count, offset| {
733                check_max(
734                    state.module.types.len(),
735                    count,
736                    MAX_WASM_TYPES,
737                    "types",
738                    offset,
739                )?;
740                state.module.assert_mut().types.reserve(count as usize);
741                Ok(())
742            },
743            |state, types, rec_group, offset| {
744                state
745                    .module
746                    .assert_mut()
747                    .add_types(rec_group, types, offset, true)?;
748                Ok(())
749            },
750        )
751    }
752
753    /// Validates [`Payload::ImportSection`](crate::Payload).
754    ///
755    /// This method should only be called when parsing a module.
756    pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
757        self.process_module_section(
758            section,
759            "import",
760            |state, _, count, offset| {
761                check_max(
762                    state.module.imports.len(),
763                    count,
764                    MAX_WASM_IMPORTS,
765                    "imports",
766                    offset,
767                )?;
768                state.module.assert_mut().imports.reserve(count as usize);
769                Ok(())
770            },
771            |state, types, imports, _offset| {
772                let state = state.module.assert_mut();
773                for import_and_offset in imports {
774                    let (offset, import) = import_and_offset?;
775                    state.add_import(import, types, offset)?;
776                }
777                Ok(())
778            },
779        )
780    }
781
782    /// Validates [`Payload::FunctionSection`](crate::Payload).
783    ///
784    /// This method should only be called when parsing a module.
785    pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
786        self.process_module_section(
787            section,
788            "function",
789            |state, _, count, offset| {
790                check_max(
791                    state.module.functions.len(),
792                    count,
793                    MAX_WASM_FUNCTIONS,
794                    "functions",
795                    offset,
796                )?;
797                state.module.assert_mut().functions.reserve(count as usize);
798                Ok(())
799            },
800            |state, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
801        )
802    }
803
804    /// Validates [`Payload::TableSection`](crate::Payload).
805    ///
806    /// This method should only be called when parsing a module.
807    pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
808        self.process_module_section(
809            section,
810            "table",
811            |state, _, count, offset| {
812                check_max(
813                    state.module.tables.len(),
814                    count,
815                    state.module.max_tables(),
816                    "tables",
817                    offset,
818                )?;
819                state.module.assert_mut().tables.reserve(count as usize);
820                Ok(())
821            },
822            |state, types, table, offset| state.add_table(table, types, offset),
823        )
824    }
825
826    /// Validates [`Payload::MemorySection`](crate::Payload).
827    ///
828    /// This method should only be called when parsing a module.
829    pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
830        self.process_module_section(
831            section,
832            "memory",
833            |state, _, count, offset| {
834                check_max(
835                    state.module.memories.len(),
836                    count,
837                    state.module.max_memories(),
838                    "memories",
839                    offset,
840                )?;
841                state.module.assert_mut().memories.reserve(count as usize);
842                Ok(())
843            },
844            |state, _, ty, offset| state.module.assert_mut().add_memory(ty, offset),
845        )
846    }
847
848    /// Validates [`Payload::TagSection`](crate::Payload).
849    ///
850    /// This method should only be called when parsing a module.
851    pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
852        if !self.features.exceptions() {
853            return Err(BinaryReaderError::new(
854                "exceptions proposal not enabled",
855                section.range().start,
856            ));
857        }
858        self.process_module_section(
859            section,
860            "tag",
861            |state, _, count, offset| {
862                check_max(
863                    state.module.tags.len(),
864                    count,
865                    MAX_WASM_TAGS,
866                    "tags",
867                    offset,
868                )?;
869                state.module.assert_mut().tags.reserve(count as usize);
870                Ok(())
871            },
872            |state, types, ty, offset| state.module.assert_mut().add_tag(ty, types, offset),
873        )
874    }
875
876    /// Validates [`Payload::GlobalSection`](crate::Payload).
877    ///
878    /// This method should only be called when parsing a module.
879    pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
880        self.process_module_section(
881            section,
882            "global",
883            |state, _, count, offset| {
884                check_max(
885                    state.module.globals.len(),
886                    count,
887                    MAX_WASM_GLOBALS,
888                    "globals",
889                    offset,
890                )?;
891                state.module.assert_mut().globals.reserve(count as usize);
892                Ok(())
893            },
894            |state, types, global, offset| state.add_global(global, types, offset),
895        )
896    }
897
898    /// Validates [`Payload::ExportSection`](crate::Payload).
899    ///
900    /// This method should only be called when parsing a module.
901    pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
902        self.process_module_section(
903            section,
904            "export",
905            |state, _, count, offset| {
906                check_max(
907                    state.module.exports.len(),
908                    count,
909                    MAX_WASM_EXPORTS,
910                    "exports",
911                    offset,
912                )?;
913                state.module.assert_mut().exports.reserve(count as usize);
914                Ok(())
915            },
916            |state, types, e, offset| {
917                let state = state.module.assert_mut();
918                let ty = state.export_to_entity_type(&e, offset)?;
919                state.add_export(e.name, ty, offset, false /* checked above */, types)
920            },
921        )
922    }
923
924    /// Validates [`Payload::StartSection`](crate::Payload).
925    ///
926    /// This method should only be called when parsing a module.
927    pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
928        let offset = range.start;
929        self.state.ensure_module("start", offset)?;
930        let state = self.module.as_mut().unwrap();
931
932        let ty = state.module.get_func_type(func, &self.types, offset)?;
933        if !ty.params().is_empty() || !ty.results().is_empty() {
934            return Err(BinaryReaderError::new(
935                "invalid start function type",
936                offset,
937            ));
938        }
939
940        Ok(())
941    }
942
943    /// Validates [`Payload::ElementSection`](crate::Payload).
944    ///
945    /// This method should only be called when parsing a module.
946    pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
947        self.process_module_section(
948            section,
949            "element",
950            |state, _, count, offset| {
951                check_max(
952                    state.module.element_types.len(),
953                    count,
954                    MAX_WASM_ELEMENT_SEGMENTS,
955                    "element segments",
956                    offset,
957                )?;
958                state
959                    .module
960                    .assert_mut()
961                    .element_types
962                    .reserve(count as usize);
963                Ok(())
964            },
965            |state, types, e, offset| state.add_element_segment(e, types, offset),
966        )
967    }
968
969    /// Validates [`Payload::DataCountSection`](crate::Payload).
970    ///
971    /// This method should only be called when parsing a module.
972    pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
973        let offset = range.start;
974        self.state.ensure_module("data count", offset)?;
975
976        let state = self.module.as_mut().unwrap();
977
978        if count > MAX_WASM_DATA_SEGMENTS as u32 {
979            return Err(BinaryReaderError::new(
980                "data count section specifies too many data segments",
981                offset,
982            ));
983        }
984
985        state.module.assert_mut().data_count = Some(count);
986        Ok(())
987    }
988
989    /// Validates [`Payload::CodeSectionStart`](crate::Payload).
990    ///
991    /// This method should only be called when parsing a module.
992    pub fn code_section_start(&mut self, range: &Range<usize>) -> Result<()> {
993        let offset = range.start;
994        self.state.ensure_module("code", offset)?;
995
996        let state = self.module.as_mut().unwrap();
997
998        // Take a snapshot of the types when we start the code section.
999        state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
1000
1001        Ok(())
1002    }
1003
1004    /// Validates [`Payload::CodeSectionEntry`](crate::Payload).
1005    ///
1006    /// This function will prepare a [`FuncToValidate`] which can be used to
1007    /// create a [`FuncValidator`] to validate the function. The function body
1008    /// provided will not be parsed or validated by this function.
1009    ///
1010    /// Note that the returned [`FuncToValidate`] is "connected" to this
1011    /// [`Validator`] in that it uses the internal context of this validator for
1012    /// validating the function. The [`FuncToValidate`] can be sent to another
1013    /// thread, for example, to offload actual processing of functions
1014    /// elsewhere.
1015    ///
1016    /// This method should only be called when parsing a module.
1017    pub fn code_section_entry(
1018        &mut self,
1019        body: &crate::FunctionBody,
1020    ) -> Result<FuncToValidate<ValidatorResources>> {
1021        let offset = body.range().start;
1022        self.state.ensure_module("code", offset)?;
1023        check_max(
1024            0,
1025            u32::try_from(body.range().len())
1026                .expect("usize already validated to u32 during section-length decoding"),
1027            MAX_WASM_FUNCTION_SIZE,
1028            "function body size",
1029            offset,
1030        )?;
1031
1032        let state = self.module.as_mut().unwrap();
1033
1034        let (index, ty) = state.next_code_index_and_type();
1035        Ok(FuncToValidate {
1036            index,
1037            ty,
1038            resources: ValidatorResources(state.module.arc().clone()),
1039            features: self.features,
1040        })
1041    }
1042
1043    /// Validates [`Payload::DataSection`](crate::Payload).
1044    ///
1045    /// This method should only be called when parsing a module.
1046    pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1047        self.process_module_section(
1048            section,
1049            "data",
1050            |_, _, count, offset| {
1051                check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1052            },
1053            |state, types, d, offset| state.add_data_segment(d, types, offset),
1054        )
1055    }
1056
1057    /// Validates [`Payload::ModuleSection`](crate::Payload).
1058    ///
1059    /// This method should only be called when parsing a component.
1060    #[cfg(feature = "component-model")]
1061    pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1062        self.state.ensure_component("module", range.start)?;
1063
1064        let current = self.components.last_mut().unwrap();
1065        check_max(
1066            current.core_modules.len(),
1067            1,
1068            MAX_WASM_MODULES,
1069            "modules",
1070            range.start,
1071        )?;
1072
1073        match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1074            State::Component => {}
1075            _ => unreachable!(),
1076        }
1077
1078        Ok(())
1079    }
1080
1081    /// Validates [`Payload::InstanceSection`](crate::Payload).
1082    ///
1083    /// This method should only be called when parsing a component.
1084    #[cfg(feature = "component-model")]
1085    pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1086        self.process_component_section(
1087            section,
1088            "core instance",
1089            |components, _, count, offset| {
1090                let current = components.last_mut().unwrap();
1091                check_max(
1092                    current.instance_count(),
1093                    count,
1094                    MAX_WASM_INSTANCES,
1095                    "instances",
1096                    offset,
1097                )?;
1098                current.core_instances.reserve(count as usize);
1099                Ok(())
1100            },
1101            |components, types, _features, instance, offset| {
1102                components
1103                    .last_mut()
1104                    .unwrap()
1105                    .add_core_instance(instance, types, offset)
1106            },
1107        )
1108    }
1109
1110    /// Validates [`Payload::CoreTypeSection`](crate::Payload).
1111    ///
1112    /// This method should only be called when parsing a component.
1113    #[cfg(feature = "component-model")]
1114    pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1115        self.process_component_section(
1116            section,
1117            "core type",
1118            |components, _types, count, offset| {
1119                let current = components.last_mut().unwrap();
1120                check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1121                current.core_types.reserve(count as usize);
1122                Ok(())
1123            },
1124            |components, types, _features, ty, offset| {
1125                ComponentState::add_core_type(
1126                    components, ty, types, offset, false, /* checked above */
1127                )
1128            },
1129        )
1130    }
1131
1132    /// Validates [`Payload::ComponentSection`](crate::Payload).
1133    ///
1134    /// This method should only be called when parsing a component.
1135    #[cfg(feature = "component-model")]
1136    pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1137        self.state.ensure_component("component", range.start)?;
1138
1139        let current = self.components.last_mut().unwrap();
1140        check_max(
1141            current.components.len(),
1142            1,
1143            MAX_WASM_COMPONENTS,
1144            "components",
1145            range.start,
1146        )?;
1147
1148        match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1149            State::Component => {}
1150            _ => unreachable!(),
1151        }
1152
1153        Ok(())
1154    }
1155
1156    /// Validates [`Payload::ComponentInstanceSection`](crate::Payload).
1157    ///
1158    /// This method should only be called when parsing a component.
1159    #[cfg(feature = "component-model")]
1160    pub fn component_instance_section(
1161        &mut self,
1162        section: &crate::ComponentInstanceSectionReader,
1163    ) -> Result<()> {
1164        self.process_component_section(
1165            section,
1166            "instance",
1167            |components, _, count, offset| {
1168                let current = components.last_mut().unwrap();
1169                check_max(
1170                    current.instance_count(),
1171                    count,
1172                    MAX_WASM_INSTANCES,
1173                    "instances",
1174                    offset,
1175                )?;
1176                current.instances.reserve(count as usize);
1177                Ok(())
1178            },
1179            |components, types, _features, instance, offset| {
1180                components
1181                    .last_mut()
1182                    .unwrap()
1183                    .add_instance(instance, types, offset)
1184            },
1185        )
1186    }
1187
1188    /// Validates [`Payload::ComponentAliasSection`](crate::Payload).
1189    ///
1190    /// This method should only be called when parsing a component.
1191    #[cfg(feature = "component-model")]
1192    pub fn component_alias_section(
1193        &mut self,
1194        section: &crate::ComponentAliasSectionReader<'_>,
1195    ) -> Result<()> {
1196        self.process_component_section(
1197            section,
1198            "alias",
1199            |_, _, _, _| Ok(()), // maximums checked via `add_alias`
1200            |components, types, _features, alias, offset| -> Result<(), BinaryReaderError> {
1201                ComponentState::add_alias(components, alias, types, offset)
1202            },
1203        )
1204    }
1205
1206    /// Validates [`Payload::ComponentTypeSection`](crate::Payload).
1207    ///
1208    /// This method should only be called when parsing a component.
1209    #[cfg(feature = "component-model")]
1210    pub fn component_type_section(
1211        &mut self,
1212        section: &crate::ComponentTypeSectionReader,
1213    ) -> Result<()> {
1214        self.process_component_section(
1215            section,
1216            "type",
1217            |components, _types, count, offset| {
1218                let current = components.last_mut().unwrap();
1219                check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1220                current.types.reserve(count as usize);
1221                Ok(())
1222            },
1223            |components, types, _features, ty, offset| {
1224                ComponentState::add_type(
1225                    components, ty, types, offset, false, /* checked above */
1226                )
1227            },
1228        )
1229    }
1230
1231    /// Validates [`Payload::ComponentCanonicalSection`](crate::Payload).
1232    ///
1233    /// This method should only be called when parsing a component.
1234    #[cfg(feature = "component-model")]
1235    pub fn component_canonical_section(
1236        &mut self,
1237        section: &crate::ComponentCanonicalSectionReader,
1238    ) -> Result<()> {
1239        self.process_component_section(
1240            section,
1241            "function",
1242            |components, _, count, offset| {
1243                let current = components.last_mut().unwrap();
1244                check_max(
1245                    current.function_count(),
1246                    count,
1247                    MAX_WASM_FUNCTIONS,
1248                    "functions",
1249                    offset,
1250                )?;
1251                current.funcs.reserve(count as usize);
1252                Ok(())
1253            },
1254            |components, types, _features, func, offset| {
1255                let current = components.last_mut().unwrap();
1256                current.canonical_function(func, types, offset)
1257            },
1258        )
1259    }
1260
1261    /// Validates [`Payload::ComponentStartSection`](crate::Payload).
1262    ///
1263    /// This method should only be called when parsing a component.
1264    #[cfg(feature = "component-model")]
1265    pub fn component_start_section(
1266        &mut self,
1267        f: &crate::ComponentStartFunction,
1268        range: &Range<usize>,
1269    ) -> Result<()> {
1270        self.state.ensure_component("start", range.start)?;
1271
1272        self.components.last_mut().unwrap().add_start(
1273            f.func_index,
1274            &f.arguments,
1275            f.results,
1276            &mut self.types,
1277            range.start,
1278        )
1279    }
1280
1281    /// Validates [`Payload::ComponentImportSection`](crate::Payload).
1282    ///
1283    /// This method should only be called when parsing a component.
1284    #[cfg(feature = "component-model")]
1285    pub fn component_import_section(
1286        &mut self,
1287        section: &crate::ComponentImportSectionReader,
1288    ) -> Result<()> {
1289        self.process_component_section(
1290            section,
1291            "import",
1292            |_, _, _, _| Ok(()), // add_import will check limits
1293            |components, types, _features, import, offset| {
1294                components
1295                    .last_mut()
1296                    .unwrap()
1297                    .add_import(import, types, offset)
1298            },
1299        )
1300    }
1301
1302    /// Validates [`Payload::ComponentExportSection`](crate::Payload).
1303    ///
1304    /// This method should only be called when parsing a component.
1305    #[cfg(feature = "component-model")]
1306    pub fn component_export_section(
1307        &mut self,
1308        section: &crate::ComponentExportSectionReader,
1309    ) -> Result<()> {
1310        self.process_component_section(
1311            section,
1312            "export",
1313            |components, _, count, offset| {
1314                let current = components.last_mut().unwrap();
1315                check_max(
1316                    current.exports.len(),
1317                    count,
1318                    MAX_WASM_EXPORTS,
1319                    "exports",
1320                    offset,
1321                )?;
1322                current.exports.reserve(count as usize);
1323                Ok(())
1324            },
1325            |components, types, _features, export, offset| {
1326                let current = components.last_mut().unwrap();
1327                let ty = current.export_to_entity_type(&export, types, offset)?;
1328                current.add_export(
1329                    export.name,
1330                    ty,
1331                    types,
1332                    offset,
1333                    false, /* checked above */
1334                )
1335            },
1336        )
1337    }
1338
1339    /// Validates [`Payload::UnknownSection`](crate::Payload).
1340    ///
1341    /// Currently always returns an error.
1342    pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1343        Err(format_err!(range.start, "malformed section id: {id}"))
1344    }
1345
1346    /// Validates [`Payload::End`](crate::Payload).
1347    ///
1348    /// Returns the types known to the validator for the module or component.
1349    pub fn end(&mut self, offset: usize) -> Result<Types> {
1350        match mem::replace(&mut self.state, State::End) {
1351            State::Unparsed(_) => Err(BinaryReaderError::new(
1352                "cannot call `end` before a header has been parsed",
1353                offset,
1354            )),
1355            State::End => Err(BinaryReaderError::new(
1356                "cannot call `end` after parsing has completed",
1357                offset,
1358            )),
1359            State::Module => {
1360                let mut state = self.module.take().unwrap();
1361
1362                // If there's a parent component, we'll add a module to the parent state
1363                // and continue to validate the component
1364                #[cfg(feature = "component-model")]
1365                if let Some(parent) = self.components.last_mut() {
1366                    parent.add_core_module(&state.module, &mut self.types, offset)?;
1367                    self.state = State::Component;
1368                }
1369
1370                Ok(Types::from_module(
1371                    self.id,
1372                    self.types.commit(),
1373                    state.module.arc().clone(),
1374                ))
1375            }
1376            #[cfg(feature = "component-model")]
1377            State::Component => {
1378                let mut component = self.components.pop().unwrap();
1379
1380                // Validate that all values were used for the component
1381                if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1382                    bail!(
1383                        offset,
1384                        "value index {index} was not used as part of an \
1385                         instantiation, start function, or export"
1386                    );
1387                }
1388
1389                // If there's a parent component, pop the stack, add it to the parent,
1390                // and continue to validate the component
1391                let ty = component.finish(&self.types, offset)?;
1392                if let Some(parent) = self.components.last_mut() {
1393                    parent.add_component(ty, &mut self.types)?;
1394                    self.state = State::Component;
1395                }
1396
1397                Ok(Types::from_component(
1398                    self.id,
1399                    self.types.commit(),
1400                    component,
1401                ))
1402            }
1403        }
1404    }
1405
1406    fn process_module_section<'a, T>(
1407        &mut self,
1408        section: &SectionLimited<'a, T>,
1409        name: &str,
1410        validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>,
1411        mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>,
1412    ) -> Result<()>
1413    where
1414        T: FromReader<'a>,
1415    {
1416        let offset = section.range().start;
1417        self.state.ensure_module(name, offset)?;
1418
1419        let state = self.module.as_mut().unwrap();
1420
1421        validate_section(state, &mut self.types, section.count(), offset)?;
1422
1423        for item in section.clone().into_iter_with_offsets() {
1424            let (offset, item) = item?;
1425            validate_item(state, &mut self.types, item, offset)?;
1426        }
1427
1428        Ok(())
1429    }
1430
1431    #[cfg(feature = "component-model")]
1432    fn process_component_section<'a, T>(
1433        &mut self,
1434        section: &SectionLimited<'a, T>,
1435        name: &str,
1436        validate_section: impl FnOnce(
1437            &mut Vec<ComponentState>,
1438            &mut TypeAlloc,
1439            u32,
1440            usize,
1441        ) -> Result<()>,
1442        mut validate_item: impl FnMut(
1443            &mut Vec<ComponentState>,
1444            &mut TypeAlloc,
1445            &WasmFeatures,
1446            T,
1447            usize,
1448        ) -> Result<()>,
1449    ) -> Result<()>
1450    where
1451        T: FromReader<'a>,
1452    {
1453        let offset = section.range().start;
1454
1455        self.state.ensure_component(name, offset)?;
1456        validate_section(
1457            &mut self.components,
1458            &mut self.types,
1459            section.count(),
1460            offset,
1461        )?;
1462
1463        for item in section.clone().into_iter_with_offsets() {
1464            let (offset, item) = item?;
1465            validate_item(
1466                &mut self.components,
1467                &mut self.types,
1468                &self.features,
1469                item,
1470                offset,
1471            )?;
1472        }
1473
1474        Ok(())
1475    }
1476}
1477
1478#[cfg(test)]
1479mod tests {
1480    use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1481    use anyhow::Result;
1482
1483    #[test]
1484    fn test_module_type_information() -> Result<()> {
1485        let bytes = wat::parse_str(
1486            r#"
1487            (module
1488                (type (func (param i32 i64) (result i32)))
1489                (memory 1 5)
1490                (table 10 funcref)
1491                (global (mut i32) (i32.const 0))
1492                (func (type 0) (i32.const 0))
1493                (tag (param i64 i32))
1494                (elem funcref (ref.func 0))
1495            )
1496        "#,
1497        )?;
1498
1499        let mut validator =
1500            Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1501
1502        let types = validator.validate_all(&bytes)?;
1503        let types = types.as_ref();
1504
1505        assert_eq!(types.core_type_count_in_module(), 2);
1506        assert_eq!(types.memory_count(), 1);
1507        assert_eq!(types.table_count(), 1);
1508        assert_eq!(types.global_count(), 1);
1509        assert_eq!(types.function_count(), 1);
1510        assert_eq!(types.tag_count(), 1);
1511        assert_eq!(types.element_count(), 1);
1512        assert_eq!(types.module_count(), 0);
1513        assert_eq!(types.component_count(), 0);
1514        assert_eq!(types.core_instance_count(), 0);
1515        assert_eq!(types.value_count(), 0);
1516
1517        let id = types.core_type_at_in_module(0);
1518        let ty = types[id].unwrap_func();
1519        assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1520        assert_eq!(ty.results(), [ValType::I32]);
1521
1522        let id = types.core_type_at_in_module(1);
1523        let ty = types[id].unwrap_func();
1524        assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1525        assert_eq!(ty.results(), []);
1526
1527        assert_eq!(
1528            types.memory_at(0),
1529            MemoryType {
1530                memory64: false,
1531                shared: false,
1532                initial: 1,
1533                maximum: Some(5),
1534                page_size_log2: None,
1535            }
1536        );
1537
1538        assert_eq!(
1539            types.table_at(0),
1540            TableType {
1541                initial: 10,
1542                maximum: None,
1543                element_type: RefType::FUNCREF,
1544                table64: false,
1545                shared: false,
1546            }
1547        );
1548
1549        assert_eq!(
1550            types.global_at(0),
1551            GlobalType {
1552                content_type: ValType::I32,
1553                mutable: true,
1554                shared: false
1555            }
1556        );
1557
1558        let id = types.core_function_at(0);
1559        let ty = types[id].unwrap_func();
1560        assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1561        assert_eq!(ty.results(), [ValType::I32]);
1562
1563        let ty = types.tag_at(0);
1564        let ty = types[ty].unwrap_func();
1565        assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1566        assert_eq!(ty.results(), []);
1567
1568        assert_eq!(types.element_at(0), RefType::FUNCREF);
1569
1570        Ok(())
1571    }
1572
1573    #[test]
1574    fn test_type_id_aliasing() -> Result<()> {
1575        let bytes = wat::parse_str(
1576            r#"
1577            (component
1578              (type $T (list string))
1579              (alias outer 0 $T (type $A1))
1580              (alias outer 0 $T (type $A2))
1581            )
1582        "#,
1583        )?;
1584
1585        let mut validator =
1586            Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1587
1588        let types = validator.validate_all(&bytes)?;
1589        let types = types.as_ref();
1590
1591        let t_id = types.component_defined_type_at(0);
1592        let a1_id = types.component_defined_type_at(1);
1593        let a2_id = types.component_defined_type_at(2);
1594
1595        // The ids should all be the same
1596        assert!(t_id == a1_id);
1597        assert!(t_id == a2_id);
1598        assert!(a1_id == a2_id);
1599
1600        // However, they should all point to the same type
1601        assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1602        assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1603
1604        Ok(())
1605    }
1606
1607    #[test]
1608    fn test_type_id_exports() -> Result<()> {
1609        let bytes = wat::parse_str(
1610            r#"
1611            (component
1612              (type $T (list string))
1613              (export $A1 "A1" (type $T))
1614              (export $A2 "A2" (type $T))
1615            )
1616        "#,
1617        )?;
1618
1619        let mut validator =
1620            Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1621
1622        let types = validator.validate_all(&bytes)?;
1623        let types = types.as_ref();
1624
1625        let t_id = types.component_defined_type_at(0);
1626        let a1_id = types.component_defined_type_at(1);
1627        let a2_id = types.component_defined_type_at(2);
1628
1629        // The ids should all be the same
1630        assert!(t_id != a1_id);
1631        assert!(t_id != a2_id);
1632        assert!(a1_id != a2_id);
1633
1634        // However, they should all point to the same type
1635        assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1636        assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1637
1638        Ok(())
1639    }
1640
1641    #[test]
1642    fn reset_fresh_validator() {
1643        Validator::new().reset();
1644    }
1645}