/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 | | } |