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