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