Coverage Report

Created: 2026-02-14 07:33

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