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