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