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::Abstract { shared, ty } => {
281                use AbstractHeapType::*;
282                if shared && !self.shared_everything_threads() {
283                    return Err(
284                        "shared reference types require the shared-everything-threads proposal",
285                    );
286                }
287
288                // Apply the "gc-types" feature which disallows all heap types
289                // except exnref/funcref.
290                if !self.gc_types() && ty != Func && ty != Exn {
291                    return Err("gc types are disallowed but found type which requires gc");
292                }
293
294                match (ty, r.is_nullable()) {
295                    // funcref/externref only require `reference-types`.
296                    (Func, true) | (Extern, true) => Ok(()),
297
298                    // Non-nullable func/extern references requires the
299                    // `function-references` proposal.
300                    (Func | Extern, false) => {
301                        if self.function_references() {
302                            Ok(())
303                        } else {
304                            Err("function references required for non-nullable types")
305                        }
306                    }
307
308                    // These types were added in the gc proposal.
309                    (Any | None | Eq | Struct | Array | I31 | NoExtern | NoFunc, _) => {
310                        if self.gc() {
311                            Ok(())
312                        } else {
313                            Err("heap types not supported without the gc feature")
314                        }
315                    }
316
317                    // These types were added in the exception-handling proposal.
318                    (Exn | NoExn, _) => {
319                        if self.exceptions() {
320                            Ok(())
321                        } else {
322                            Err(
323                                "exception refs not supported without the exception handling feature",
324                            )
325                        }
326                    }
327
328                    // These types were added in the stack switching proposal.
329                    (Cont | NoCont, _) => {
330                        if self.stack_switching() {
331                            Ok(())
332                        } else {
333                            Err(
334                                "continuation refs not supported without the stack switching feature",
335                            )
336                        }
337                    }
338                }
339            }
340        }
341    }
342}
343
344/// Possible return values from [`Validator::payload`].
345#[allow(clippy::large_enum_variant)]
346pub enum ValidPayload<'a> {
347    /// The payload validated, no further action need be taken.
348    Ok,
349    /// The payload validated, but it started a nested module or component.
350    ///
351    /// This result indicates that the specified parser should be used instead
352    /// of the currently-used parser until this returned one ends.
353    Parser(Parser),
354    /// A function was found to be validated.
355    Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
356    /// The end payload was validated and the types known to the validator
357    /// are provided.
358    End(Types),
359}
360
361impl Validator {
362    /// Creates a new [`Validator`] ready to validate a WebAssembly module
363    /// or component.
364    ///
365    /// The new validator will receive payloads parsed from
366    /// [`Parser`], and expects the first payload received to be
367    /// the version header from the parser.
368    pub fn new() -> Validator {
369        Validator::default()
370    }
371
372    /// Creates a new [`Validator`] which has the specified set of wasm
373    /// features activated for validation.
374    ///
375    /// This function is the same as [`Validator::new`] except it also allows
376    /// you to customize the active wasm features in use for validation. This
377    /// can allow enabling experimental proposals or also turning off
378    /// on-by-default wasm proposals.
379    pub fn new_with_features(features: WasmFeatures) -> Validator {
380        let mut ret = Validator::new();
381        ret.features = features;
382        ret
383    }
384
385    /// Returns the wasm features used for this validator.
386    pub fn features(&self) -> &WasmFeatures {
387        &self.features
388    }
389
390    /// Reset this validator's state such that it is ready to validate a new
391    /// Wasm module or component.
392    ///
393    /// This does *not* clear or reset the internal state keeping track of
394    /// validated (and deduplicated and canonicalized) types, allowing you to
395    /// use the same type identifiers (such as
396    /// [`CoreTypeId`][crate::types::CoreTypeId]) for the same types that are
397    /// defined multiple times across different modules and components.
398    ///
399    /// # Panics
400    ///
401    /// This function will panic if the validator was mid-way through
402    /// validating a binary. Validation must complete entirely or not have
403    /// started at all for this method to be called.
404    ///
405    /// # Examples
406    ///
407    /// ```
408    /// fn foo() -> anyhow::Result<()> {
409    /// use wasmparser::Validator;
410    ///
411    /// let mut validator = Validator::default();
412    ///
413    /// // Two wasm modules, both of which define the same type, but at
414    /// // different indices in their respective types index spaces.
415    /// let wasm1 = wat::parse_str("
416    ///     (module
417    ///         (type $same_type (func (param i32) (result f64)))
418    ///     )
419    /// ")?;
420    /// let wasm2 = wat::parse_str("
421    ///     (module
422    ///         (type $different_type (func))
423    ///         (type $same_type (func (param i32) (result f64)))
424    ///     )
425    /// ")?;
426    ///
427    /// // Validate the first Wasm module and get the ID of its type.
428    /// let types = validator.validate_all(&wasm1)?;
429    /// let id1 = types.as_ref().core_type_at_in_module(0);
430    ///
431    /// // Reset the validator so we can parse the second wasm module inside
432    /// // this validator's same context.
433    /// validator.reset();
434    ///
435    /// // Validate the second Wasm module and get the ID of its second type,
436    /// // which is the same type as the first Wasm module's only type.
437    /// let types = validator.validate_all(&wasm2)?;
438    /// let id2 = types.as_ref().core_type_at_in_module(1);
439    ///
440    /// // Because both modules were processed in the same `Validator`, they
441    /// // share the same types context and therefore the same type defined
442    /// // multiple times across different modules will be deduplicated and
443    /// // assigned the same identifier!
444    /// assert_eq!(id1, id2);
445    /// assert_eq!(types[id1], types[id2]);
446    /// # Ok(())
447    /// # }
448    /// # foo().unwrap()
449    /// ```
450    pub fn reset(&mut self) {
451        let Validator {
452            // Not changing the identifier; users should be able to observe that
453            // they are using the same validation context, even after resetting.
454            id: _,
455
456            // Don't mess with `types`, we specifically want to reuse canonicalization.
457            types: _,
458
459            // Also leave features as they are. While this is perhaps not
460            // strictly necessary, it helps us avoid weird bugs where we have
461            // different views of what is or is not a valid type at different
462            // times, despite using the same `TypeList` and hash consing
463            // context, and therefore there could be moments in time where we
464            // have "invalid" types inside our current types list.
465            features: _,
466
467            state,
468            module,
469            #[cfg(feature = "component-model")]
470            components,
471        } = self;
472
473        assert!(
474            matches!(state, State::End) || matches!(state, State::Unparsed(None)),
475            "cannot reset a validator that did not successfully complete validation"
476        );
477        assert!(module.is_none());
478        #[cfg(feature = "component-model")]
479        assert!(components.is_empty());
480
481        *state = State::default();
482    }
483
484    /// Get this validator's unique identifier.
485    ///
486    /// Allows you to assert that you are always working with the same
487    /// `Validator` instance, when you can't otherwise statically ensure that
488    /// property by e.g. storing a reference to the validator inside your
489    /// structure.
490    pub fn id(&self) -> ValidatorId {
491        self.id
492    }
493
494    /// Validates an entire in-memory module or component with this validator.
495    ///
496    /// This function will internally create a [`Parser`] to parse the `bytes`
497    /// provided. The entire module or component specified by `bytes` will be
498    /// parsed and validated.
499    ///
500    /// Upon success, the type information for the top-level module or component
501    /// will be returned.
502    pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
503        let mut functions_to_validate = Vec::new();
504        let mut last_types = None;
505        let mut parser = Parser::new(0);
506        let _ = &mut parser;
507        #[cfg(feature = "features")]
508        parser.set_features(self.features);
509        for payload in parser.parse_all(bytes) {
510            match self.payload(&payload?)? {
511                ValidPayload::Func(a, b) => {
512                    functions_to_validate.push((a, b));
513                }
514                ValidPayload::End(types) => {
515                    // Only the last (top-level) type information will be returned
516                    last_types = Some(types);
517                }
518                _ => {}
519            }
520        }
521
522        let mut allocs = FuncValidatorAllocations::default();
523        for (func, body) in functions_to_validate {
524            let mut validator = func.into_validator(allocs);
525            validator.validate(&body)?;
526            allocs = validator.into_allocations();
527        }
528
529        Ok(last_types.unwrap())
530    }
531
532    /// Gets the types known by the validator so far within the
533    /// module/component `level` modules/components up from the
534    /// module/component currently being parsed.
535    ///
536    /// For instance, calling `validator.types(0)` will get the types of the
537    /// module/component currently being parsed, and `validator.types(1)` will
538    /// get the types of the component containing that module/component.
539    ///
540    /// Returns `None` if there is no module/component that many levels up.
541    pub fn types(&self, mut level: usize) -> Option<TypesRef<'_>> {
542        if let Some(module) = &self.module {
543            if level == 0 {
544                return Some(TypesRef::from_module(self.id, &self.types, &module.module));
545            } else {
546                level -= 1;
547                let _ = level;
548            }
549        }
550
551        #[cfg(feature = "component-model")]
552        return self
553            .components
554            .iter()
555            .nth_back(level)
556            .map(|component| TypesRef::from_component(self.id, &self.types, component));
557        #[cfg(not(feature = "component-model"))]
558        return None;
559    }
560
561    /// Convenience function to validate a single [`Payload`].
562    ///
563    /// This function is intended to be used as a convenience. It will
564    /// internally perform any validation necessary to validate the [`Payload`]
565    /// provided. The convenience part is that you're likely already going to
566    /// be matching on [`Payload`] in your application, at which point it's more
567    /// appropriate to call the individual methods on [`Validator`] per-variant
568    /// in [`Payload`], such as [`Validator::type_section`].
569    ///
570    /// This function returns a [`ValidPayload`] variant on success, indicating
571    /// one of a few possible actions that need to be taken after a payload is
572    /// validated. For example function contents are not validated here, they're
573    /// returned through [`ValidPayload`] for validation by the caller.
574    pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
575        use crate::Payload::*;
576        match payload {
577            Version {
578                num,
579                encoding,
580                range,
581            } => self.version(*num, *encoding, range)?,
582
583            // Module sections
584            TypeSection(s) => self.type_section(s)?,
585            ImportSection(s) => self.import_section(s)?,
586            FunctionSection(s) => self.function_section(s)?,
587            TableSection(s) => self.table_section(s)?,
588            MemorySection(s) => self.memory_section(s)?,
589            TagSection(s) => self.tag_section(s)?,
590            GlobalSection(s) => self.global_section(s)?,
591            ExportSection(s) => self.export_section(s)?,
592            StartSection { func, range } => self.start_section(*func, range)?,
593            ElementSection(s) => self.element_section(s)?,
594            DataCountSection { count, range } => self.data_count_section(*count, range)?,
595            CodeSectionStart {
596                count: _,
597                range,
598                size: _,
599            } => self.code_section_start(range)?,
600            CodeSectionEntry(body) => {
601                let func_validator = self.code_section_entry(body)?;
602                return Ok(ValidPayload::Func(func_validator, body.clone()));
603            }
604            DataSection(s) => self.data_section(s)?,
605
606            // Component sections
607            #[cfg(feature = "component-model")]
608            ModuleSection {
609                parser,
610                unchecked_range: range,
611                ..
612            } => {
613                self.module_section(range)?;
614                return Ok(ValidPayload::Parser(parser.clone()));
615            }
616            #[cfg(feature = "component-model")]
617            InstanceSection(s) => self.instance_section(s)?,
618            #[cfg(feature = "component-model")]
619            CoreTypeSection(s) => self.core_type_section(s)?,
620            #[cfg(feature = "component-model")]
621            ComponentSection {
622                parser,
623                unchecked_range: range,
624                ..
625            } => {
626                self.component_section(range)?;
627                return Ok(ValidPayload::Parser(parser.clone()));
628            }
629            #[cfg(feature = "component-model")]
630            ComponentInstanceSection(s) => self.component_instance_section(s)?,
631            #[cfg(feature = "component-model")]
632            ComponentAliasSection(s) => self.component_alias_section(s)?,
633            #[cfg(feature = "component-model")]
634            ComponentTypeSection(s) => self.component_type_section(s)?,
635            #[cfg(feature = "component-model")]
636            ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
637            #[cfg(feature = "component-model")]
638            ComponentStartSection { start, range } => self.component_start_section(start, range)?,
639            #[cfg(feature = "component-model")]
640            ComponentImportSection(s) => self.component_import_section(s)?,
641            #[cfg(feature = "component-model")]
642            ComponentExportSection(s) => self.component_export_section(s)?,
643
644            End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
645
646            CustomSection { .. } => {} // no validation for custom sections
647            UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
648        }
649        Ok(ValidPayload::Ok)
650    }
651
652    /// Validates [`Payload::Version`](crate::Payload).
653    pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
654        match &self.state {
655            State::Unparsed(expected) => {
656                if let Some(expected) = expected {
657                    if *expected != encoding {
658                        bail!(
659                            range.start,
660                            "expected a version header for a {}",
661                            match expected {
662                                Encoding::Module => "module",
663                                Encoding::Component => "component",
664                            }
665                        );
666                    }
667                }
668            }
669            _ => {
670                return Err(BinaryReaderError::new(
671                    "wasm version header out of order",
672                    range.start,
673                ));
674            }
675        }
676
677        self.state = match encoding {
678            Encoding::Module => {
679                if num == WASM_MODULE_VERSION {
680                    assert!(self.module.is_none());
681                    self.module = Some(ModuleState::new(self.features));
682                    State::Module
683                } else {
684                    bail!(range.start, "unknown binary version: {num:#x}");
685                }
686            }
687            Encoding::Component => {
688                if !self.features.component_model() {
689                    bail!(
690                        range.start,
691                        "unknown binary version and encoding combination: {num:#x} and 0x1, \
692                        note: encoded as a component but the WebAssembly component model feature \
693                        is not enabled - enable the feature to allow component validation",
694                    );
695                }
696                #[cfg(feature = "component-model")]
697                if num == crate::WASM_COMPONENT_VERSION {
698                    self.components
699                        .push(ComponentState::new(ComponentKind::Component, self.features));
700                    State::Component
701                } else if num < crate::WASM_COMPONENT_VERSION {
702                    bail!(range.start, "unsupported component version: {num:#x}");
703                } else {
704                    bail!(range.start, "unknown component version: {num:#x}");
705                }
706                #[cfg(not(feature = "component-model"))]
707                bail!(
708                    range.start,
709                    "component model validation support disabled \
710                     at compile time"
711                );
712            }
713        };
714
715        Ok(())
716    }
717
718    /// Validates [`Payload::TypeSection`](crate::Payload).
719    pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
720        self.process_module_section(
721            section,
722            "type",
723            |state, _types, count, offset| {
724                check_max(
725                    state.module.types.len(),
726                    count,
727                    MAX_WASM_TYPES,
728                    "types",
729                    offset,
730                )?;
731                state.module.assert_mut().types.reserve(count as usize);
732                Ok(())
733            },
734            |state, types, rec_group, offset| {
735                state
736                    .module
737                    .assert_mut()
738                    .add_types(rec_group, types, offset, true)?;
739                Ok(())
740            },
741        )
742    }
743
744    /// Validates [`Payload::ImportSection`](crate::Payload).
745    ///
746    /// This method should only be called when parsing a module.
747    pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
748        self.process_module_section(
749            section,
750            "import",
751            |state, _, count, offset| {
752                check_max(
753                    state.module.imports.len(),
754                    count,
755                    MAX_WASM_IMPORTS,
756                    "imports",
757                    offset,
758                )?;
759                state.module.assert_mut().imports.reserve(count as usize);
760                Ok(())
761            },
762            |state, types, import, offset| {
763                state.module.assert_mut().add_import(import, types, offset)
764            },
765        )
766    }
767
768    /// Validates [`Payload::FunctionSection`](crate::Payload).
769    ///
770    /// This method should only be called when parsing a module.
771    pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
772        self.process_module_section(
773            section,
774            "function",
775            |state, _, count, offset| {
776                check_max(
777                    state.module.functions.len(),
778                    count,
779                    MAX_WASM_FUNCTIONS,
780                    "functions",
781                    offset,
782                )?;
783                state.module.assert_mut().functions.reserve(count as usize);
784                Ok(())
785            },
786            |state, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
787        )
788    }
789
790    /// Validates [`Payload::TableSection`](crate::Payload).
791    ///
792    /// This method should only be called when parsing a module.
793    pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
794        self.process_module_section(
795            section,
796            "table",
797            |state, _, count, offset| {
798                check_max(
799                    state.module.tables.len(),
800                    count,
801                    state.module.max_tables(),
802                    "tables",
803                    offset,
804                )?;
805                state.module.assert_mut().tables.reserve(count as usize);
806                Ok(())
807            },
808            |state, types, table, offset| state.add_table(table, types, offset),
809        )
810    }
811
812    /// Validates [`Payload::MemorySection`](crate::Payload).
813    ///
814    /// This method should only be called when parsing a module.
815    pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
816        self.process_module_section(
817            section,
818            "memory",
819            |state, _, count, offset| {
820                check_max(
821                    state.module.memories.len(),
822                    count,
823                    state.module.max_memories(),
824                    "memories",
825                    offset,
826                )?;
827                state.module.assert_mut().memories.reserve(count as usize);
828                Ok(())
829            },
830            |state, _, ty, offset| state.module.assert_mut().add_memory(ty, offset),
831        )
832    }
833
834    /// Validates [`Payload::TagSection`](crate::Payload).
835    ///
836    /// This method should only be called when parsing a module.
837    pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
838        if !self.features.exceptions() {
839            return Err(BinaryReaderError::new(
840                "exceptions proposal not enabled",
841                section.range().start,
842            ));
843        }
844        self.process_module_section(
845            section,
846            "tag",
847            |state, _, count, offset| {
848                check_max(
849                    state.module.tags.len(),
850                    count,
851                    MAX_WASM_TAGS,
852                    "tags",
853                    offset,
854                )?;
855                state.module.assert_mut().tags.reserve(count as usize);
856                Ok(())
857            },
858            |state, types, ty, offset| state.module.assert_mut().add_tag(ty, types, offset),
859        )
860    }
861
862    /// Validates [`Payload::GlobalSection`](crate::Payload).
863    ///
864    /// This method should only be called when parsing a module.
865    pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
866        self.process_module_section(
867            section,
868            "global",
869            |state, _, count, offset| {
870                check_max(
871                    state.module.globals.len(),
872                    count,
873                    MAX_WASM_GLOBALS,
874                    "globals",
875                    offset,
876                )?;
877                state.module.assert_mut().globals.reserve(count as usize);
878                Ok(())
879            },
880            |state, types, global, offset| state.add_global(global, types, offset),
881        )
882    }
883
884    /// Validates [`Payload::ExportSection`](crate::Payload).
885    ///
886    /// This method should only be called when parsing a module.
887    pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
888        self.process_module_section(
889            section,
890            "export",
891            |state, _, count, offset| {
892                check_max(
893                    state.module.exports.len(),
894                    count,
895                    MAX_WASM_EXPORTS,
896                    "exports",
897                    offset,
898                )?;
899                state.module.assert_mut().exports.reserve(count as usize);
900                Ok(())
901            },
902            |state, types, e, offset| {
903                let state = state.module.assert_mut();
904                let ty = state.export_to_entity_type(&e, offset)?;
905                state.add_export(e.name, ty, offset, false /* checked above */, types)
906            },
907        )
908    }
909
910    /// Validates [`Payload::StartSection`](crate::Payload).
911    ///
912    /// This method should only be called when parsing a module.
913    pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
914        let offset = range.start;
915        self.state.ensure_module("start", offset)?;
916        let state = self.module.as_mut().unwrap();
917
918        let ty = state.module.get_func_type(func, &self.types, offset)?;
919        if !ty.params().is_empty() || !ty.results().is_empty() {
920            return Err(BinaryReaderError::new(
921                "invalid start function type",
922                offset,
923            ));
924        }
925
926        Ok(())
927    }
928
929    /// Validates [`Payload::ElementSection`](crate::Payload).
930    ///
931    /// This method should only be called when parsing a module.
932    pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
933        self.process_module_section(
934            section,
935            "element",
936            |state, _, count, offset| {
937                check_max(
938                    state.module.element_types.len(),
939                    count,
940                    MAX_WASM_ELEMENT_SEGMENTS,
941                    "element segments",
942                    offset,
943                )?;
944                state
945                    .module
946                    .assert_mut()
947                    .element_types
948                    .reserve(count as usize);
949                Ok(())
950            },
951            |state, types, e, offset| state.add_element_segment(e, types, offset),
952        )
953    }
954
955    /// Validates [`Payload::DataCountSection`](crate::Payload).
956    ///
957    /// This method should only be called when parsing a module.
958    pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
959        let offset = range.start;
960        self.state.ensure_module("data count", offset)?;
961
962        let state = self.module.as_mut().unwrap();
963
964        if count > MAX_WASM_DATA_SEGMENTS as u32 {
965            return Err(BinaryReaderError::new(
966                "data count section specifies too many data segments",
967                offset,
968            ));
969        }
970
971        state.module.assert_mut().data_count = Some(count);
972        Ok(())
973    }
974
975    /// Validates [`Payload::CodeSectionStart`](crate::Payload).
976    ///
977    /// This method should only be called when parsing a module.
978    pub fn code_section_start(&mut self, range: &Range<usize>) -> Result<()> {
979        let offset = range.start;
980        self.state.ensure_module("code", offset)?;
981
982        let state = self.module.as_mut().unwrap();
983
984        // Take a snapshot of the types when we start the code section.
985        state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
986
987        Ok(())
988    }
989
990    /// Validates [`Payload::CodeSectionEntry`](crate::Payload).
991    ///
992    /// This function will prepare a [`FuncToValidate`] which can be used to
993    /// create a [`FuncValidator`] to validate the function. The function body
994    /// provided will not be parsed or validated by this function.
995    ///
996    /// Note that the returned [`FuncToValidate`] is "connected" to this
997    /// [`Validator`] in that it uses the internal context of this validator for
998    /// validating the function. The [`FuncToValidate`] can be sent to another
999    /// thread, for example, to offload actual processing of functions
1000    /// elsewhere.
1001    ///
1002    /// This method should only be called when parsing a module.
1003    pub fn code_section_entry(
1004        &mut self,
1005        body: &crate::FunctionBody,
1006    ) -> Result<FuncToValidate<ValidatorResources>> {
1007        let offset = body.range().start;
1008        self.state.ensure_module("code", offset)?;
1009
1010        let state = self.module.as_mut().unwrap();
1011
1012        let (index, ty) = state.next_code_index_and_type();
1013        Ok(FuncToValidate {
1014            index,
1015            ty,
1016            resources: ValidatorResources(state.module.arc().clone()),
1017            features: self.features,
1018        })
1019    }
1020
1021    /// Validates [`Payload::DataSection`](crate::Payload).
1022    ///
1023    /// This method should only be called when parsing a module.
1024    pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1025        self.process_module_section(
1026            section,
1027            "data",
1028            |_, _, count, offset| {
1029                check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1030            },
1031            |state, types, d, offset| state.add_data_segment(d, types, offset),
1032        )
1033    }
1034
1035    /// Validates [`Payload::ModuleSection`](crate::Payload).
1036    ///
1037    /// This method should only be called when parsing a component.
1038    #[cfg(feature = "component-model")]
1039    pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1040        self.state.ensure_component("module", range.start)?;
1041
1042        let current = self.components.last_mut().unwrap();
1043        check_max(
1044            current.core_modules.len(),
1045            1,
1046            MAX_WASM_MODULES,
1047            "modules",
1048            range.start,
1049        )?;
1050
1051        match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1052            State::Component => {}
1053            _ => unreachable!(),
1054        }
1055
1056        Ok(())
1057    }
1058
1059    /// Validates [`Payload::InstanceSection`](crate::Payload).
1060    ///
1061    /// This method should only be called when parsing a component.
1062    #[cfg(feature = "component-model")]
1063    pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1064        self.process_component_section(
1065            section,
1066            "core instance",
1067            |components, _, count, offset| {
1068                let current = components.last_mut().unwrap();
1069                check_max(
1070                    current.instance_count(),
1071                    count,
1072                    MAX_WASM_INSTANCES,
1073                    "instances",
1074                    offset,
1075                )?;
1076                current.core_instances.reserve(count as usize);
1077                Ok(())
1078            },
1079            |components, types, _features, instance, offset| {
1080                components
1081                    .last_mut()
1082                    .unwrap()
1083                    .add_core_instance(instance, types, offset)
1084            },
1085        )
1086    }
1087
1088    /// Validates [`Payload::CoreTypeSection`](crate::Payload).
1089    ///
1090    /// This method should only be called when parsing a component.
1091    #[cfg(feature = "component-model")]
1092    pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1093        self.process_component_section(
1094            section,
1095            "core type",
1096            |components, _types, count, offset| {
1097                let current = components.last_mut().unwrap();
1098                check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1099                current.core_types.reserve(count as usize);
1100                Ok(())
1101            },
1102            |components, types, _features, ty, offset| {
1103                ComponentState::add_core_type(
1104                    components, ty, types, offset, false, /* checked above */
1105                )
1106            },
1107        )
1108    }
1109
1110    /// Validates [`Payload::ComponentSection`](crate::Payload).
1111    ///
1112    /// This method should only be called when parsing a component.
1113    #[cfg(feature = "component-model")]
1114    pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1115        self.state.ensure_component("component", range.start)?;
1116
1117        let current = self.components.last_mut().unwrap();
1118        check_max(
1119            current.components.len(),
1120            1,
1121            MAX_WASM_COMPONENTS,
1122            "components",
1123            range.start,
1124        )?;
1125
1126        match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1127            State::Component => {}
1128            _ => unreachable!(),
1129        }
1130
1131        Ok(())
1132    }
1133
1134    /// Validates [`Payload::ComponentInstanceSection`](crate::Payload).
1135    ///
1136    /// This method should only be called when parsing a component.
1137    #[cfg(feature = "component-model")]
1138    pub fn component_instance_section(
1139        &mut self,
1140        section: &crate::ComponentInstanceSectionReader,
1141    ) -> Result<()> {
1142        self.process_component_section(
1143            section,
1144            "instance",
1145            |components, _, count, offset| {
1146                let current = components.last_mut().unwrap();
1147                check_max(
1148                    current.instance_count(),
1149                    count,
1150                    MAX_WASM_INSTANCES,
1151                    "instances",
1152                    offset,
1153                )?;
1154                current.instances.reserve(count as usize);
1155                Ok(())
1156            },
1157            |components, types, _features, instance, offset| {
1158                components
1159                    .last_mut()
1160                    .unwrap()
1161                    .add_instance(instance, types, offset)
1162            },
1163        )
1164    }
1165
1166    /// Validates [`Payload::ComponentAliasSection`](crate::Payload).
1167    ///
1168    /// This method should only be called when parsing a component.
1169    #[cfg(feature = "component-model")]
1170    pub fn component_alias_section(
1171        &mut self,
1172        section: &crate::ComponentAliasSectionReader<'_>,
1173    ) -> Result<()> {
1174        self.process_component_section(
1175            section,
1176            "alias",
1177            |_, _, _, _| Ok(()), // maximums checked via `add_alias`
1178            |components, types, _features, alias, offset| -> Result<(), BinaryReaderError> {
1179                ComponentState::add_alias(components, alias, types, offset)
1180            },
1181        )
1182    }
1183
1184    /// Validates [`Payload::ComponentTypeSection`](crate::Payload).
1185    ///
1186    /// This method should only be called when parsing a component.
1187    #[cfg(feature = "component-model")]
1188    pub fn component_type_section(
1189        &mut self,
1190        section: &crate::ComponentTypeSectionReader,
1191    ) -> Result<()> {
1192        self.process_component_section(
1193            section,
1194            "type",
1195            |components, _types, count, offset| {
1196                let current = components.last_mut().unwrap();
1197                check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1198                current.types.reserve(count as usize);
1199                Ok(())
1200            },
1201            |components, types, _features, ty, offset| {
1202                ComponentState::add_type(
1203                    components, ty, types, offset, false, /* checked above */
1204                )
1205            },
1206        )
1207    }
1208
1209    /// Validates [`Payload::ComponentCanonicalSection`](crate::Payload).
1210    ///
1211    /// This method should only be called when parsing a component.
1212    #[cfg(feature = "component-model")]
1213    pub fn component_canonical_section(
1214        &mut self,
1215        section: &crate::ComponentCanonicalSectionReader,
1216    ) -> Result<()> {
1217        self.process_component_section(
1218            section,
1219            "function",
1220            |components, _, count, offset| {
1221                let current = components.last_mut().unwrap();
1222                check_max(
1223                    current.function_count(),
1224                    count,
1225                    MAX_WASM_FUNCTIONS,
1226                    "functions",
1227                    offset,
1228                )?;
1229                current.funcs.reserve(count as usize);
1230                Ok(())
1231            },
1232            |components, types, _features, func, offset| {
1233                let current = components.last_mut().unwrap();
1234                current.canonical_function(func, types, offset)
1235            },
1236        )
1237    }
1238
1239    /// Validates [`Payload::ComponentStartSection`](crate::Payload).
1240    ///
1241    /// This method should only be called when parsing a component.
1242    #[cfg(feature = "component-model")]
1243    pub fn component_start_section(
1244        &mut self,
1245        f: &crate::ComponentStartFunction,
1246        range: &Range<usize>,
1247    ) -> Result<()> {
1248        self.state.ensure_component("start", range.start)?;
1249
1250        self.components.last_mut().unwrap().add_start(
1251            f.func_index,
1252            &f.arguments,
1253            f.results,
1254            &mut self.types,
1255            range.start,
1256        )
1257    }
1258
1259    /// Validates [`Payload::ComponentImportSection`](crate::Payload).
1260    ///
1261    /// This method should only be called when parsing a component.
1262    #[cfg(feature = "component-model")]
1263    pub fn component_import_section(
1264        &mut self,
1265        section: &crate::ComponentImportSectionReader,
1266    ) -> Result<()> {
1267        self.process_component_section(
1268            section,
1269            "import",
1270            |_, _, _, _| Ok(()), // add_import will check limits
1271            |components, types, _features, import, offset| {
1272                components
1273                    .last_mut()
1274                    .unwrap()
1275                    .add_import(import, types, offset)
1276            },
1277        )
1278    }
1279
1280    /// Validates [`Payload::ComponentExportSection`](crate::Payload).
1281    ///
1282    /// This method should only be called when parsing a component.
1283    #[cfg(feature = "component-model")]
1284    pub fn component_export_section(
1285        &mut self,
1286        section: &crate::ComponentExportSectionReader,
1287    ) -> Result<()> {
1288        self.process_component_section(
1289            section,
1290            "export",
1291            |components, _, count, offset| {
1292                let current = components.last_mut().unwrap();
1293                check_max(
1294                    current.exports.len(),
1295                    count,
1296                    MAX_WASM_EXPORTS,
1297                    "exports",
1298                    offset,
1299                )?;
1300                current.exports.reserve(count as usize);
1301                Ok(())
1302            },
1303            |components, types, _features, export, offset| {
1304                let current = components.last_mut().unwrap();
1305                let ty = current.export_to_entity_type(&export, types, offset)?;
1306                current.add_export(
1307                    export.name,
1308                    ty,
1309                    types,
1310                    offset,
1311                    false, /* checked above */
1312                )
1313            },
1314        )
1315    }
1316
1317    /// Validates [`Payload::UnknownSection`](crate::Payload).
1318    ///
1319    /// Currently always returns an error.
1320    pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1321        Err(format_err!(range.start, "malformed section id: {id}"))
1322    }
1323
1324    /// Validates [`Payload::End`](crate::Payload).
1325    ///
1326    /// Returns the types known to the validator for the module or component.
1327    pub fn end(&mut self, offset: usize) -> Result<Types> {
1328        match mem::replace(&mut self.state, State::End) {
1329            State::Unparsed(_) => Err(BinaryReaderError::new(
1330                "cannot call `end` before a header has been parsed",
1331                offset,
1332            )),
1333            State::End => Err(BinaryReaderError::new(
1334                "cannot call `end` after parsing has completed",
1335                offset,
1336            )),
1337            State::Module => {
1338                let mut state = self.module.take().unwrap();
1339
1340                // If there's a parent component, we'll add a module to the parent state
1341                // and continue to validate the component
1342                #[cfg(feature = "component-model")]
1343                if let Some(parent) = self.components.last_mut() {
1344                    parent.add_core_module(&state.module, &mut self.types, offset)?;
1345                    self.state = State::Component;
1346                }
1347
1348                Ok(Types::from_module(
1349                    self.id,
1350                    self.types.commit(),
1351                    state.module.arc().clone(),
1352                ))
1353            }
1354            #[cfg(feature = "component-model")]
1355            State::Component => {
1356                let mut component = self.components.pop().unwrap();
1357
1358                // Validate that all values were used for the component
1359                if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1360                    bail!(
1361                        offset,
1362                        "value index {index} was not used as part of an \
1363                         instantiation, start function, or export"
1364                    );
1365                }
1366
1367                // If there's a parent component, pop the stack, add it to the parent,
1368                // and continue to validate the component
1369                let ty = component.finish(&self.types, offset)?;
1370                if let Some(parent) = self.components.last_mut() {
1371                    parent.add_component(ty, &mut self.types)?;
1372                    self.state = State::Component;
1373                }
1374
1375                Ok(Types::from_component(
1376                    self.id,
1377                    self.types.commit(),
1378                    component,
1379                ))
1380            }
1381        }
1382    }
1383
1384    fn process_module_section<'a, T>(
1385        &mut self,
1386        section: &SectionLimited<'a, T>,
1387        name: &str,
1388        validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>,
1389        mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>,
1390    ) -> Result<()>
1391    where
1392        T: FromReader<'a>,
1393    {
1394        let offset = section.range().start;
1395        self.state.ensure_module(name, offset)?;
1396
1397        let state = self.module.as_mut().unwrap();
1398
1399        validate_section(state, &mut self.types, section.count(), offset)?;
1400
1401        for item in section.clone().into_iter_with_offsets() {
1402            let (offset, item) = item?;
1403            validate_item(state, &mut self.types, item, offset)?;
1404        }
1405
1406        Ok(())
1407    }
1408
1409    #[cfg(feature = "component-model")]
1410    fn process_component_section<'a, T>(
1411        &mut self,
1412        section: &SectionLimited<'a, T>,
1413        name: &str,
1414        validate_section: impl FnOnce(
1415            &mut Vec<ComponentState>,
1416            &mut TypeAlloc,
1417            u32,
1418            usize,
1419        ) -> Result<()>,
1420        mut validate_item: impl FnMut(
1421            &mut Vec<ComponentState>,
1422            &mut TypeAlloc,
1423            &WasmFeatures,
1424            T,
1425            usize,
1426        ) -> Result<()>,
1427    ) -> Result<()>
1428    where
1429        T: FromReader<'a>,
1430    {
1431        let offset = section.range().start;
1432
1433        self.state.ensure_component(name, offset)?;
1434        validate_section(
1435            &mut self.components,
1436            &mut self.types,
1437            section.count(),
1438            offset,
1439        )?;
1440
1441        for item in section.clone().into_iter_with_offsets() {
1442            let (offset, item) = item?;
1443            validate_item(
1444                &mut self.components,
1445                &mut self.types,
1446                &self.features,
1447                item,
1448                offset,
1449            )?;
1450        }
1451
1452        Ok(())
1453    }
1454}
1455
1456#[cfg(test)]
1457mod tests {
1458    use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1459    use anyhow::Result;
1460
1461    #[test]
1462    fn test_module_type_information() -> Result<()> {
1463        let bytes = wat::parse_str(
1464            r#"
1465            (module
1466                (type (func (param i32 i64) (result i32)))
1467                (memory 1 5)
1468                (table 10 funcref)
1469                (global (mut i32) (i32.const 0))
1470                (func (type 0) (i32.const 0))
1471                (tag (param i64 i32))
1472                (elem funcref (ref.func 0))
1473            )
1474        "#,
1475        )?;
1476
1477        let mut validator =
1478            Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1479
1480        let types = validator.validate_all(&bytes)?;
1481        let types = types.as_ref();
1482
1483        assert_eq!(types.core_type_count_in_module(), 2);
1484        assert_eq!(types.memory_count(), 1);
1485        assert_eq!(types.table_count(), 1);
1486        assert_eq!(types.global_count(), 1);
1487        assert_eq!(types.function_count(), 1);
1488        assert_eq!(types.tag_count(), 1);
1489        assert_eq!(types.element_count(), 1);
1490        assert_eq!(types.module_count(), 0);
1491        assert_eq!(types.component_count(), 0);
1492        assert_eq!(types.core_instance_count(), 0);
1493        assert_eq!(types.value_count(), 0);
1494
1495        let id = types.core_type_at_in_module(0);
1496        let ty = types[id].unwrap_func();
1497        assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1498        assert_eq!(ty.results(), [ValType::I32]);
1499
1500        let id = types.core_type_at_in_module(1);
1501        let ty = types[id].unwrap_func();
1502        assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1503        assert_eq!(ty.results(), []);
1504
1505        assert_eq!(
1506            types.memory_at(0),
1507            MemoryType {
1508                memory64: false,
1509                shared: false,
1510                initial: 1,
1511                maximum: Some(5),
1512                page_size_log2: None,
1513            }
1514        );
1515
1516        assert_eq!(
1517            types.table_at(0),
1518            TableType {
1519                initial: 10,
1520                maximum: None,
1521                element_type: RefType::FUNCREF,
1522                table64: false,
1523                shared: false,
1524            }
1525        );
1526
1527        assert_eq!(
1528            types.global_at(0),
1529            GlobalType {
1530                content_type: ValType::I32,
1531                mutable: true,
1532                shared: false
1533            }
1534        );
1535
1536        let id = types.core_function_at(0);
1537        let ty = types[id].unwrap_func();
1538        assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1539        assert_eq!(ty.results(), [ValType::I32]);
1540
1541        let ty = types.tag_at(0);
1542        let ty = types[ty].unwrap_func();
1543        assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1544        assert_eq!(ty.results(), []);
1545
1546        assert_eq!(types.element_at(0), RefType::FUNCREF);
1547
1548        Ok(())
1549    }
1550
1551    #[test]
1552    fn test_type_id_aliasing() -> Result<()> {
1553        let bytes = wat::parse_str(
1554            r#"
1555            (component
1556              (type $T (list string))
1557              (alias outer 0 $T (type $A1))
1558              (alias outer 0 $T (type $A2))
1559            )
1560        "#,
1561        )?;
1562
1563        let mut validator =
1564            Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1565
1566        let types = validator.validate_all(&bytes)?;
1567        let types = types.as_ref();
1568
1569        let t_id = types.component_defined_type_at(0);
1570        let a1_id = types.component_defined_type_at(1);
1571        let a2_id = types.component_defined_type_at(2);
1572
1573        // The ids should all be the same
1574        assert!(t_id == a1_id);
1575        assert!(t_id == a2_id);
1576        assert!(a1_id == a2_id);
1577
1578        // However, they should all point to the same type
1579        assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1580        assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1581
1582        Ok(())
1583    }
1584
1585    #[test]
1586    fn test_type_id_exports() -> Result<()> {
1587        let bytes = wat::parse_str(
1588            r#"
1589            (component
1590              (type $T (list string))
1591              (export $A1 "A1" (type $T))
1592              (export $A2 "A2" (type $T))
1593            )
1594        "#,
1595        )?;
1596
1597        let mut validator =
1598            Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1599
1600        let types = validator.validate_all(&bytes)?;
1601        let types = types.as_ref();
1602
1603        let t_id = types.component_defined_type_at(0);
1604        let a1_id = types.component_defined_type_at(1);
1605        let a2_id = types.component_defined_type_at(2);
1606
1607        // The ids should all be the same
1608        assert!(t_id != a1_id);
1609        assert!(t_id != a2_id);
1610        assert!(a1_id != a2_id);
1611
1612        // However, they should all point to the same type
1613        assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1614        assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1615
1616        Ok(())
1617    }
1618
1619    #[test]
1620    fn reset_fresh_validator() {
1621        Validator::new().reset();
1622    }
1623}