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