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 maxOption
71 .checked_sub(cur_len)
72 .and_then(|amt: usize| 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: u32) 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(val:1, order: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 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, _, instance, offset| {
1121 components
1122 .last_mut()
1123 .unwrap()
1124 .add_core_instance(instance, 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 match func {
1276 crate::CanonicalFunction::Lift {
1277 core_func_index,
1278 type_index,
1279 options,
1280 } => current.lift_function(
1281 core_func_index,
1282 type_index,
1283 options.into_vec(),
1284 types,
1285 offset,
1286 features,
1287 ),
1288 crate::CanonicalFunction::Lower {
1289 func_index,
1290 options,
1291 } => current.lower_function(
1292 func_index,
1293 options.into_vec(),
1294 types,
1295 offset,
1296 features,
1297 ),
1298 crate::CanonicalFunction::ResourceNew { resource } => {
1299 current.resource_new(resource, types, offset)
1300 }
1301 crate::CanonicalFunction::ResourceDrop { resource } => {
1302 current.resource_drop(resource, types, offset)
1303 }
1304 crate::CanonicalFunction::ResourceRep { resource } => {
1305 current.resource_rep(resource, types, offset)
1306 }
1307 crate::CanonicalFunction::ThreadSpawn { func_ty_index } => {
1308 current.thread_spawn(func_ty_index, types, offset, features)
1309 }
1310 crate::CanonicalFunction::ThreadHwConcurrency => {
1311 current.thread_hw_concurrency(types, offset, features)
1312 }
1313 crate::CanonicalFunction::TaskBackpressure => {
1314 current.task_backpressure(types, offset, features)
1315 }
1316 crate::CanonicalFunction::TaskReturn { type_index } => {
1317 current.task_return(type_index, types, offset, features)
1318 }
1319 crate::CanonicalFunction::TaskWait { async_, memory } => {
1320 current.task_wait(async_, memory, types, offset, features)
1321 }
1322 crate::CanonicalFunction::TaskPoll { async_, memory } => {
1323 current.task_poll(async_, memory, types, offset, features)
1324 }
1325 crate::CanonicalFunction::TaskYield { async_ } => {
1326 current.task_yield(async_, types, offset, features)
1327 }
1328 crate::CanonicalFunction::SubtaskDrop => {
1329 current.subtask_drop(types, offset, features)
1330 }
1331 crate::CanonicalFunction::StreamNew { ty } => {
1332 current.stream_new(ty, types, offset, features)
1333 }
1334 crate::CanonicalFunction::StreamRead { ty, options } => {
1335 current.stream_read(ty, options.into_vec(), types, offset, features)
1336 }
1337 crate::CanonicalFunction::StreamWrite { ty, options } => {
1338 current.stream_write(ty, options.into_vec(), types, offset, features)
1339 }
1340 crate::CanonicalFunction::StreamCancelRead { ty, async_ } => {
1341 current.stream_cancel_read(ty, async_, types, offset, features)
1342 }
1343 crate::CanonicalFunction::StreamCancelWrite { ty, async_ } => {
1344 current.stream_cancel_write(ty, async_, types, offset, features)
1345 }
1346 crate::CanonicalFunction::StreamCloseReadable { ty } => {
1347 current.stream_close_readable(ty, types, offset, features)
1348 }
1349 crate::CanonicalFunction::StreamCloseWritable { ty } => {
1350 current.stream_close_writable(ty, types, offset, features)
1351 }
1352 crate::CanonicalFunction::FutureNew { ty } => {
1353 current.future_new(ty, types, offset, features)
1354 }
1355 crate::CanonicalFunction::FutureRead { ty, options } => {
1356 current.future_read(ty, options.into_vec(), types, offset, features)
1357 }
1358 crate::CanonicalFunction::FutureWrite { ty, options } => {
1359 current.future_write(ty, options.into_vec(), types, offset, features)
1360 }
1361 crate::CanonicalFunction::FutureCancelRead { ty, async_ } => {
1362 current.future_cancel_read(ty, async_, types, offset, features)
1363 }
1364 crate::CanonicalFunction::FutureCancelWrite { ty, async_ } => {
1365 current.future_cancel_write(ty, async_, types, offset, features)
1366 }
1367 crate::CanonicalFunction::FutureCloseReadable { ty } => {
1368 current.future_close_readable(ty, types, offset, features)
1369 }
1370 crate::CanonicalFunction::FutureCloseWritable { ty } => {
1371 current.future_close_writable(ty, types, offset, features)
1372 }
1373 crate::CanonicalFunction::ErrorContextNew { options } => {
1374 current.error_context_new(options.into_vec(), types, offset, features)
1375 }
1376 crate::CanonicalFunction::ErrorContextDebugMessage { options } => current
1377 .error_context_debug_message(options.into_vec(), types, offset, features),
1378 crate::CanonicalFunction::ErrorContextDrop => {
1379 current.error_context_drop(types, offset, features)
1380 }
1381 }
1382 },
1383 )
1384 }
1385
1386 /// Validates [`Payload::ComponentStartSection`](crate::Payload).
1387 ///
1388 /// This method should only be called when parsing a component.
1389 #[cfg(feature = "component-model")]
1390 pub fn component_start_section(
1391 &mut self,
1392 f: &crate::ComponentStartFunction,
1393 range: &Range<usize>,
1394 ) -> Result<()> {
1395 self.state.ensure_component("start", range.start)?;
1396
1397 self.components.last_mut().unwrap().add_start(
1398 f.func_index,
1399 &f.arguments,
1400 f.results,
1401 &self.features,
1402 &mut self.types,
1403 range.start,
1404 )
1405 }
1406
1407 /// Validates [`Payload::ComponentImportSection`](crate::Payload).
1408 ///
1409 /// This method should only be called when parsing a component.
1410 #[cfg(feature = "component-model")]
1411 pub fn component_import_section(
1412 &mut self,
1413 section: &crate::ComponentImportSectionReader,
1414 ) -> Result<()> {
1415 self.process_component_section(
1416 section,
1417 "import",
1418 |_, _, _, _| Ok(()), // add_import will check limits
1419 |components, types, features, import, offset| {
1420 components
1421 .last_mut()
1422 .unwrap()
1423 .add_import(import, features, types, offset)
1424 },
1425 )
1426 }
1427
1428 /// Validates [`Payload::ComponentExportSection`](crate::Payload).
1429 ///
1430 /// This method should only be called when parsing a component.
1431 #[cfg(feature = "component-model")]
1432 pub fn component_export_section(
1433 &mut self,
1434 section: &crate::ComponentExportSectionReader,
1435 ) -> Result<()> {
1436 self.process_component_section(
1437 section,
1438 "export",
1439 |components, _, count, offset| {
1440 let current = components.last_mut().unwrap();
1441 check_max(
1442 current.exports.len(),
1443 count,
1444 MAX_WASM_EXPORTS,
1445 "exports",
1446 offset,
1447 )?;
1448 current.exports.reserve(count as usize);
1449 Ok(())
1450 },
1451 |components, types, features, export, offset| {
1452 let current = components.last_mut().unwrap();
1453 let ty = current.export_to_entity_type(&export, features, types, offset)?;
1454 current.add_export(
1455 export.name,
1456 ty,
1457 features,
1458 types,
1459 offset,
1460 false, /* checked above */
1461 )
1462 },
1463 )
1464 }
1465
1466 /// Validates [`Payload::UnknownSection`](crate::Payload).
1467 ///
1468 /// Currently always returns an error.
1469 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1470 Err(format_err!(range.start, "malformed section id: {id}"))
1471 }
1472
1473 /// Validates [`Payload::End`](crate::Payload).
1474 ///
1475 /// Returns the types known to the validator for the module or component.
1476 pub fn end(&mut self, offset: usize) -> Result<Types> {
1477 match mem::replace(&mut self.state, State::End) {
1478 State::Unparsed(_) => Err(BinaryReaderError::new(
1479 "cannot call `end` before a header has been parsed",
1480 offset,
1481 )),
1482 State::End => Err(BinaryReaderError::new(
1483 "cannot call `end` after parsing has completed",
1484 offset,
1485 )),
1486 State::Module => {
1487 let mut state = self.module.take().unwrap();
1488 state.validate_end(offset)?;
1489
1490 // If there's a parent component, we'll add a module to the parent state
1491 // and continue to validate the component
1492 #[cfg(feature = "component-model")]
1493 if let Some(parent) = self.components.last_mut() {
1494 parent.add_core_module(&state.module, &mut self.types, offset)?;
1495 self.state = State::Component;
1496 }
1497
1498 Ok(Types::from_module(
1499 self.id,
1500 self.types.commit(),
1501 state.module.arc().clone(),
1502 ))
1503 }
1504 #[cfg(feature = "component-model")]
1505 State::Component => {
1506 let mut component = self.components.pop().unwrap();
1507
1508 // Validate that all values were used for the component
1509 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1510 bail!(
1511 offset,
1512 "value index {index} was not used as part of an \
1513 instantiation, start function, or export"
1514 );
1515 }
1516
1517 // If there's a parent component, pop the stack, add it to the parent,
1518 // and continue to validate the component
1519 let ty = component.finish(&mut self.types, offset)?;
1520 if let Some(parent) = self.components.last_mut() {
1521 parent.add_component(ty, &mut self.types)?;
1522 self.state = State::Component;
1523 }
1524
1525 Ok(Types::from_component(
1526 self.id,
1527 self.types.commit(),
1528 component,
1529 ))
1530 }
1531 }
1532 }
1533
1534 fn process_module_section<'a, T>(
1535 &mut self,
1536 order: Order,
1537 section: &SectionLimited<'a, T>,
1538 name: &str,
1539 validate_section: impl FnOnce(
1540 &mut ModuleState,
1541 &WasmFeatures,
1542 &mut TypeAlloc,
1543 u32,
1544 usize,
1545 ) -> Result<()>,
1546 mut validate_item: impl FnMut(
1547 &mut ModuleState,
1548 &WasmFeatures,
1549 &mut TypeAlloc,
1550 T,
1551 usize,
1552 ) -> Result<()>,
1553 ) -> Result<()>
1554 where
1555 T: FromReader<'a>,
1556 {
1557 let offset = section.range().start;
1558 self.state.ensure_module(name, offset)?;
1559
1560 let state = self.module.as_mut().unwrap();
1561 state.update_order(order, offset)?;
1562
1563 validate_section(
1564 state,
1565 &self.features,
1566 &mut self.types,
1567 section.count(),
1568 offset,
1569 )?;
1570
1571 for item in section.clone().into_iter_with_offsets() {
1572 let (offset, item) = item?;
1573 validate_item(state, &self.features, &mut self.types, item, offset)?;
1574 }
1575
1576 Ok(())
1577 }
1578
1579 #[cfg(feature = "component-model")]
1580 fn process_component_section<'a, T>(
1581 &mut self,
1582 section: &SectionLimited<'a, T>,
1583 name: &str,
1584 validate_section: impl FnOnce(
1585 &mut Vec<ComponentState>,
1586 &mut TypeAlloc,
1587 u32,
1588 usize,
1589 ) -> Result<()>,
1590 mut validate_item: impl FnMut(
1591 &mut Vec<ComponentState>,
1592 &mut TypeAlloc,
1593 &WasmFeatures,
1594 T,
1595 usize,
1596 ) -> Result<()>,
1597 ) -> Result<()>
1598 where
1599 T: FromReader<'a>,
1600 {
1601 let offset = section.range().start;
1602
1603 if !self.features.component_model() {
1604 return Err(BinaryReaderError::new(
1605 "component model feature is not enabled",
1606 offset,
1607 ));
1608 }
1609
1610 self.state.ensure_component(name, offset)?;
1611 validate_section(
1612 &mut self.components,
1613 &mut self.types,
1614 section.count(),
1615 offset,
1616 )?;
1617
1618 for item in section.clone().into_iter_with_offsets() {
1619 let (offset, item) = item?;
1620 validate_item(
1621 &mut self.components,
1622 &mut self.types,
1623 &self.features,
1624 item,
1625 offset,
1626 )?;
1627 }
1628
1629 Ok(())
1630 }
1631}
1632
1633#[cfg(test)]
1634mod tests {
1635 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1636 use anyhow::Result;
1637
1638 #[test]
1639 fn test_module_type_information() -> Result<()> {
1640 let bytes = wat::parse_str(
1641 r#"
1642 (module
1643 (type (func (param i32 i64) (result i32)))
1644 (memory 1 5)
1645 (table 10 funcref)
1646 (global (mut i32) (i32.const 0))
1647 (func (type 0) (i32.const 0))
1648 (tag (param i64 i32))
1649 (elem funcref (ref.func 0))
1650 )
1651 "#,
1652 )?;
1653
1654 let mut validator =
1655 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1656
1657 let types = validator.validate_all(&bytes)?;
1658 let types = types.as_ref();
1659
1660 assert_eq!(types.core_type_count_in_module(), 2);
1661 assert_eq!(types.memory_count(), 1);
1662 assert_eq!(types.table_count(), 1);
1663 assert_eq!(types.global_count(), 1);
1664 assert_eq!(types.function_count(), 1);
1665 assert_eq!(types.tag_count(), 1);
1666 assert_eq!(types.element_count(), 1);
1667 assert_eq!(types.module_count(), 0);
1668 assert_eq!(types.component_count(), 0);
1669 assert_eq!(types.core_instance_count(), 0);
1670 assert_eq!(types.value_count(), 0);
1671
1672 let id = types.core_type_at_in_module(0);
1673 let ty = types[id].unwrap_func();
1674 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1675 assert_eq!(ty.results(), [ValType::I32]);
1676
1677 let id = types.core_type_at_in_module(1);
1678 let ty = types[id].unwrap_func();
1679 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1680 assert_eq!(ty.results(), []);
1681
1682 assert_eq!(
1683 types.memory_at(0),
1684 MemoryType {
1685 memory64: false,
1686 shared: false,
1687 initial: 1,
1688 maximum: Some(5),
1689 page_size_log2: None,
1690 }
1691 );
1692
1693 assert_eq!(
1694 types.table_at(0),
1695 TableType {
1696 initial: 10,
1697 maximum: None,
1698 element_type: RefType::FUNCREF,
1699 table64: false,
1700 shared: false,
1701 }
1702 );
1703
1704 assert_eq!(
1705 types.global_at(0),
1706 GlobalType {
1707 content_type: ValType::I32,
1708 mutable: true,
1709 shared: false
1710 }
1711 );
1712
1713 let id = types.core_function_at(0);
1714 let ty = types[id].unwrap_func();
1715 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1716 assert_eq!(ty.results(), [ValType::I32]);
1717
1718 let ty = types.tag_at(0);
1719 let ty = types[ty].unwrap_func();
1720 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1721 assert_eq!(ty.results(), []);
1722
1723 assert_eq!(types.element_at(0), RefType::FUNCREF);
1724
1725 Ok(())
1726 }
1727
1728 #[test]
1729 fn test_type_id_aliasing() -> Result<()> {
1730 let bytes = wat::parse_str(
1731 r#"
1732 (component
1733 (type $T (list string))
1734 (alias outer 0 $T (type $A1))
1735 (alias outer 0 $T (type $A2))
1736 )
1737 "#,
1738 )?;
1739
1740 let mut validator =
1741 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1742
1743 let types = validator.validate_all(&bytes)?;
1744 let types = types.as_ref();
1745
1746 let t_id = types.component_defined_type_at(0);
1747 let a1_id = types.component_defined_type_at(1);
1748 let a2_id = types.component_defined_type_at(2);
1749
1750 // The ids should all be the same
1751 assert!(t_id == a1_id);
1752 assert!(t_id == a2_id);
1753 assert!(a1_id == a2_id);
1754
1755 // However, they should all point to the same type
1756 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1757 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1758
1759 Ok(())
1760 }
1761
1762 #[test]
1763 fn test_type_id_exports() -> Result<()> {
1764 let bytes = wat::parse_str(
1765 r#"
1766 (component
1767 (type $T (list string))
1768 (export $A1 "A1" (type $T))
1769 (export $A2 "A2" (type $T))
1770 )
1771 "#,
1772 )?;
1773
1774 let mut validator =
1775 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1776
1777 let types = validator.validate_all(&bytes)?;
1778 let types = types.as_ref();
1779
1780 let t_id = types.component_defined_type_at(0);
1781 let a1_id = types.component_defined_type_at(1);
1782 let a2_id = types.component_defined_type_at(2);
1783
1784 // The ids should all be the same
1785 assert!(t_id != a1_id);
1786 assert!(t_id != a2_id);
1787 assert!(a1_id != a2_id);
1788
1789 // However, they should all point to the same type
1790 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1791 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1792
1793 Ok(())
1794 }
1795}
1796