1mod canonical;
5pub(crate) use canonical::InternRecGroup;
6
7use self::arc::MaybeOwned;
8use super::{
9 check_max, combine_type_sizes,
10 operators::{OperatorValidator, OperatorValidatorAllocations, ty_to_str},
11 types::{CoreTypeId, EntityType, RecGroupId, TypeAlloc, TypeList},
12};
13#[cfg(feature = "simd")]
14use crate::VisitSimdOperator;
15use crate::{
16 BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, FuncType,
17 Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, SubType, Table, TableInit,
18 TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, WasmFeatures,
19 WasmModuleResources, limits::*,
20};
21use crate::{CompositeInnerType, prelude::*};
22use alloc::sync::Arc;
23use core::mem;
24
25pub(crate) struct ModuleState {
26 pub module: arc::MaybeOwned<Module>,
32
33 const_expr_allocs: OperatorValidatorAllocations,
34
35 code_section_index: Option<usize>,
37}
38
39impl ModuleState {
40 pub fn new(features: WasmFeatures) -> ModuleState {
41 ModuleState {
42 module: arc::MaybeOwned::new(Module::new(features)),
43 const_expr_allocs: OperatorValidatorAllocations::default(),
44 code_section_index: None,
45 }
46 }
47
48 pub fn next_code_index_and_type(&mut self) -> (u32, u32) {
49 let index = self
50 .code_section_index
51 .get_or_insert(self.module.num_imported_functions as usize);
52
53 assert!(*index < self.module.functions.len());
54
55 let ty = self.module.functions[*index];
56 *index += 1;
57
58 ((*index - 1) as u32, ty)
59 }
60
61 pub fn add_global(
62 &mut self,
63 mut global: Global,
64 types: &TypeList,
65 offset: usize,
66 ) -> Result<()> {
67 self.module
68 .check_global_type(&mut global.ty, types, offset)?;
69 self.check_const_expr(&global.init_expr, global.ty.content_type, types)?;
70 self.module.assert_mut().globals.push(global.ty);
71 Ok(())
72 }
73
74 pub fn add_table(
75 &mut self,
76 mut table: Table<'_>,
77 types: &TypeList,
78 offset: usize,
79 ) -> Result<()> {
80 self.module.check_table_type(&mut table.ty, types, offset)?;
81
82 match &table.init {
83 TableInit::RefNull => {
84 if !table.ty.element_type.is_nullable() {
85 bail!(offset, "type mismatch: non-defaultable element type");
86 }
87 }
88 TableInit::Expr(expr) => {
89 if !self.module.features.function_references() {
90 bail!(
91 offset,
92 "tables with expression initializers require \
93 the function-references proposal"
94 );
95 }
96 self.check_const_expr(expr, table.ty.element_type.into(), types)?;
97 }
98 }
99 self.module.assert_mut().tables.push(table.ty);
100 Ok(())
101 }
102
103 pub fn add_data_segment(&mut self, data: Data, types: &TypeList, offset: usize) -> Result<()> {
104 match data.kind {
105 DataKind::Passive => {
106 if !self.module.features.bulk_memory() {
107 bail!(
108 offset,
109 "passive data segments require the bulk-memory proposal"
110 );
111 }
112 Ok(())
113 }
114 DataKind::Active {
115 memory_index,
116 offset_expr,
117 } => {
118 let ty = self.module.memory_at(memory_index, offset)?.index_type();
119 self.check_const_expr(&offset_expr, ty, types)
120 }
121 }
122 }
123
124 pub fn add_element_segment(
125 &mut self,
126 mut e: Element,
127 types: &TypeList,
128 offset: usize,
129 ) -> Result<()> {
130 let element_ty = match &mut e.items {
133 crate::ElementItems::Functions(_) => RefType::FUNC,
134 crate::ElementItems::Expressions(ty, _) => {
135 self.module.check_ref_type(ty, offset)?;
136 *ty
137 }
138 };
139
140 match e.kind {
141 ElementKind::Active {
142 table_index,
143 offset_expr,
144 } => {
145 let table = self.module.table_at(table_index.unwrap_or(0), offset)?;
146 if !types.reftype_is_subtype(element_ty, table.element_type) {
147 return Err(BinaryReaderError::new(
148 format!(
149 "type mismatch: invalid element type `{}` for table type `{}`",
150 ty_to_str(element_ty.into()),
151 ty_to_str(table.element_type.into()),
152 ),
153 offset,
154 ));
155 }
156
157 self.check_const_expr(&offset_expr, table.index_type(), types)?;
158 }
159 ElementKind::Passive | ElementKind::Declared => {
160 if !self.module.features.bulk_memory() {
161 return Err(BinaryReaderError::new(
162 "bulk memory must be enabled",
163 offset,
164 ));
165 }
166 }
167 }
168
169 let validate_count = |count: u32| -> Result<(), BinaryReaderError> {
170 if count > MAX_WASM_TABLE_ENTRIES as u32 {
171 Err(BinaryReaderError::new(
172 "number of elements is out of bounds",
173 offset,
174 ))
175 } else {
176 Ok(())
177 }
178 };
179 match e.items {
180 crate::ElementItems::Functions(reader) => {
181 let count = reader.count();
182 validate_count(count)?;
183 for f in reader.into_iter_with_offsets() {
184 let (offset, f) = f?;
185 self.module.get_func_type(f, types, offset)?;
186 self.module.assert_mut().function_references.insert(f);
187 }
188 }
189 crate::ElementItems::Expressions(ty, reader) => {
190 validate_count(reader.count())?;
191 for expr in reader {
192 self.check_const_expr(&expr?, ValType::Ref(ty), types)?;
193 }
194 }
195 }
196 self.module.assert_mut().element_types.push(element_ty);
197 Ok(())
198 }
199
200 fn check_const_expr(
201 &mut self,
202 expr: &ConstExpr<'_>,
203 expected_ty: ValType,
204 types: &TypeList,
205 ) -> Result<()> {
206 let mut validator = VisitConstOperator {
207 offset: 0,
208 uninserted_funcref: false,
209 ops: OperatorValidator::new_const_expr(
210 &self.module.features,
211 expected_ty,
212 mem::take(&mut self.const_expr_allocs),
213 ),
214 resources: OperatorValidatorResources {
215 types,
216 module: &mut self.module,
217 },
218 };
219
220 let mut ops = expr.get_operators_reader();
221 while !ops.eof() {
222 validator.offset = ops.original_position();
223 ops.visit_operator(&mut validator)??;
224 }
225
226 assert!(!validator.uninserted_funcref);
228
229 self.const_expr_allocs = validator.ops.into_allocations();
230
231 return Ok(());
232
233 struct VisitConstOperator<'a> {
234 offset: usize,
235 uninserted_funcref: bool,
236 ops: OperatorValidator,
237 resources: OperatorValidatorResources<'a>,
238 }
239
240 impl VisitConstOperator<'_> {
241 fn validator(&mut self) -> impl VisitOperator<'_, Output = Result<()>> {
242 self.ops.with_resources(&self.resources, self.offset)
243 }
244
245 fn validate_extended_const(&mut self, op: &str) -> Result<()> {
246 if self.ops.features.extended_const() {
247 Ok(())
248 } else {
249 Err(BinaryReaderError::new(
250 format!("constant expression required: non-constant operator: {op}"),
251 self.offset,
252 ))
253 }
254 }
255
256 fn validate_gc(&mut self, op: &str) -> Result<()> {
257 if self.ops.features.gc() {
258 Ok(())
259 } else {
260 Err(BinaryReaderError::new(
261 format!("constant expression required: non-constant operator: {op}"),
262 self.offset,
263 ))
264 }
265 }
266
267 fn validate_shared_everything_threads(&mut self, op: &str) -> Result<()> {
268 if self.ops.features.shared_everything_threads() {
269 Ok(())
270 } else {
271 Err(BinaryReaderError::new(
272 format!("constant expression required: non-constant operator: {op}"),
273 self.offset,
274 ))
275 }
276 }
277
278 fn validate_global(&mut self, index: u32) -> Result<()> {
279 let module = &self.resources.module;
280 let global = module.global_at(index, self.offset)?;
281
282 if index >= module.num_imported_globals && !self.ops.features.gc() {
283 return Err(BinaryReaderError::new(
284 "constant expression required: global.get of locally defined global",
285 self.offset,
286 ));
287 }
288 if global.mutable {
289 return Err(BinaryReaderError::new(
290 "constant expression required: global.get of mutable global",
291 self.offset,
292 ));
293 }
294 Ok(())
295 }
296
297 fn insert_ref_func(&mut self, index: u32) {
315 if self.resources.module.as_mut().is_none() {
316 self.uninserted_funcref = true;
317 } else {
318 self.resources
319 .module
320 .assert_mut()
321 .function_references
322 .insert(index);
323 }
324 }
325
326 fn not_const(&self, instr: &str) -> BinaryReaderError {
327 BinaryReaderError::new(
328 format!("constant expression required: non-constant operator: {instr}"),
329 self.offset,
330 )
331 }
332 }
333
334 #[cfg_attr(not(feature = "simd"), allow(unused_macro_rules))]
335 macro_rules! define_visit_operator {
336 ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
337 $(
338 #[allow(unused_variables)]
339 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
340 define_visit_operator!(@visit self $visit $($($arg)*)?)
341 }
342 )*
343 };
344
345 (@visit $self:ident visit_i32_const $val:ident) => {{
347 $self.validator().visit_i32_const($val)
348 }};
349 (@visit $self:ident visit_i64_const $val:ident) => {{
350 $self.validator().visit_i64_const($val)
351 }};
352 (@visit $self:ident visit_f32_const $val:ident) => {{
353 $self.validator().visit_f32_const($val)
354 }};
355 (@visit $self:ident visit_f64_const $val:ident) => {{
356 $self.validator().visit_f64_const($val)
357 }};
358 (@visit $self:ident visit_v128_const $val:ident) => {{
359 $self.validator().simd_visitor().unwrap().visit_v128_const($val)
360 }};
361 (@visit $self:ident visit_ref_null $val:ident) => {{
362 $self.validator().visit_ref_null($val)
363 }};
364 (@visit $self:ident visit_end) => {{
365 $self.validator().visit_end()
366 }};
367
368
369 (@visit $self:ident visit_i32_add) => {{
371 $self.validate_extended_const("i32.add")?;
372 $self.validator().visit_i32_add()
373 }};
374 (@visit $self:ident visit_i32_sub) => {{
375 $self.validate_extended_const("i32.sub")?;
376 $self.validator().visit_i32_sub()
377 }};
378 (@visit $self:ident visit_i32_mul) => {{
379 $self.validate_extended_const("i32.mul")?;
380 $self.validator().visit_i32_mul()
381 }};
382 (@visit $self:ident visit_i64_add) => {{
383 $self.validate_extended_const("i64.add")?;
384 $self.validator().visit_i64_add()
385 }};
386 (@visit $self:ident visit_i64_sub) => {{
387 $self.validate_extended_const("i64.sub")?;
388 $self.validator().visit_i64_sub()
389 }};
390 (@visit $self:ident visit_i64_mul) => {{
391 $self.validate_extended_const("i64.mul")?;
392 $self.validator().visit_i64_mul()
393 }};
394
395 (@visit $self:ident visit_struct_new $type_index:ident) => {{
398 $self.validate_gc("struct.new")?;
399 $self.validator().visit_struct_new($type_index)
400 }};
401 (@visit $self:ident visit_struct_new_default $type_index:ident) => {{
402 $self.validate_gc("struct.new_default")?;
403 $self.validator().visit_struct_new_default($type_index)
404 }};
405 (@visit $self:ident visit_array_new $type_index:ident) => {{
406 $self.validate_gc("array.new")?;
407 $self.validator().visit_array_new($type_index)
408 }};
409 (@visit $self:ident visit_array_new_default $type_index:ident) => {{
410 $self.validate_gc("array.new_default")?;
411 $self.validator().visit_array_new_default($type_index)
412 }};
413 (@visit $self:ident visit_array_new_fixed $type_index:ident $n:ident) => {{
414 $self.validate_gc("array.new_fixed")?;
415 $self.validator().visit_array_new_fixed($type_index, $n)
416 }};
417 (@visit $self:ident visit_ref_i31) => {{
418 $self.validate_gc("ref.i31")?;
419 $self.validator().visit_ref_i31()
420 }};
421 (@visit $self:ident visit_extern_convert_any) => {{
422 $self.validate_gc("extern.convert_any")?;
423 $self.validator().visit_extern_convert_any()
424 }};
425 (@visit $self:ident visit_any_convert_extern) => {{
426 $self.validate_gc("any.convert_extern")?;
427 $self.validator().visit_any_convert_extern()
428 }};
429 (@visit $self:ident visit_ref_i31_shared) => {{
430 $self.validate_shared_everything_threads("ref.i31_shared")?;
431 $self.validator().visit_ref_i31_shared()
432 }};
433
434 (@visit $self:ident visit_global_get $idx:ident) => {{
437 $self.validate_global($idx)?;
438 $self.validator().visit_global_get($idx)
439 }};
440 (@visit $self:ident visit_ref_func $idx:ident) => {{
443 $self.insert_ref_func($idx);
444 $self.validator().visit_ref_func($idx)
445 }};
446
447 (@visit $self:ident $op:ident $($args:tt)*) => {{
448 Err($self.not_const(stringify!($op)))
449 }}
450 }
451
452 impl<'a> VisitOperator<'a> for VisitConstOperator<'a> {
453 type Output = Result<()>;
454
455 #[cfg(feature = "simd")]
456 fn simd_visitor(
457 &mut self,
458 ) -> Option<&mut dyn crate::VisitSimdOperator<'a, Output = Self::Output>> {
459 Some(self)
460 }
461
462 crate::for_each_visit_operator!(define_visit_operator);
463 }
464
465 #[cfg(feature = "simd")]
466 impl<'a> VisitSimdOperator<'a> for VisitConstOperator<'a> {
467 crate::for_each_visit_simd_operator!(define_visit_operator);
468 }
469 }
470}
471
472#[derive(Debug)]
473pub(crate) struct Module {
474 pub snapshot: Option<Arc<TypeList>>,
478 pub types: Vec<CoreTypeId>,
480 pub tables: Vec<TableType>,
481 pub memories: Vec<MemoryType>,
482 pub globals: Vec<GlobalType>,
483 pub element_types: Vec<RefType>,
484 pub data_count: Option<u32>,
485 pub functions: Vec<u32>,
487 pub tags: Vec<CoreTypeId>,
488 pub function_references: Set<u32>,
489 pub imports: IndexMap<(String, String), Vec<EntityType>>,
490 pub exports: IndexMap<String, EntityType>,
491 pub type_size: u32,
492 num_imported_globals: u32,
493 num_imported_functions: u32,
494 features: WasmFeatures,
495}
496
497impl Module {
498 pub fn new(features: WasmFeatures) -> Self {
499 Self {
500 snapshot: Default::default(),
501 types: Default::default(),
502 tables: Default::default(),
503 memories: Default::default(),
504 globals: Default::default(),
505 element_types: Default::default(),
506 data_count: Default::default(),
507 functions: Default::default(),
508 tags: Default::default(),
509 function_references: Default::default(),
510 imports: Default::default(),
511 exports: Default::default(),
512 type_size: 1,
513 num_imported_globals: Default::default(),
514 num_imported_functions: Default::default(),
515 features,
516 }
517 }
518
519 pub(crate) fn add_types(
520 &mut self,
521 rec_group: RecGroup,
522 types: &mut TypeAlloc,
523 offset: usize,
524 check_limit: bool,
525 ) -> Result<()> {
526 if check_limit {
527 check_max(
528 self.types.len(),
529 rec_group.types().len() as u32,
530 MAX_WASM_TYPES,
531 "types",
532 offset,
533 )?;
534 }
535 self.canonicalize_and_intern_rec_group(types, rec_group, offset)
536 }
537
538 pub fn add_import(
539 &mut self,
540 mut import: crate::Import,
541 types: &TypeList,
542 offset: usize,
543 ) -> Result<()> {
544 let entity = self.check_type_ref(&mut import.ty, types, offset)?;
545
546 let (len, max, desc) = match import.ty {
547 TypeRef::Func(type_index) => {
548 self.functions.push(type_index);
549 self.num_imported_functions += 1;
550 (self.functions.len(), MAX_WASM_FUNCTIONS, "functions")
551 }
552 TypeRef::Table(ty) => {
553 self.tables.push(ty);
554 (self.tables.len(), self.max_tables(), "tables")
555 }
556 TypeRef::Memory(ty) => {
557 self.memories.push(ty);
558 (self.memories.len(), self.max_memories(), "memories")
559 }
560 TypeRef::Tag(ty) => {
561 self.tags.push(self.types[ty.func_type_idx as usize]);
562 (self.tags.len(), MAX_WASM_TAGS, "tags")
563 }
564 TypeRef::Global(ty) => {
565 if !self.features.mutable_global() && ty.mutable {
566 return Err(BinaryReaderError::new(
567 "mutable global support is not enabled",
568 offset,
569 ));
570 }
571 self.globals.push(ty);
572 self.num_imported_globals += 1;
573 (self.globals.len(), MAX_WASM_GLOBALS, "globals")
574 }
575 };
576
577 check_max(len, 0, max, desc, offset)?;
578
579 self.type_size = combine_type_sizes(self.type_size, entity.info(types).size(), offset)?;
580
581 self.imports
582 .entry((import.module.to_string(), import.name.to_string()))
583 .or_default()
584 .push(entity);
585
586 Ok(())
587 }
588
589 pub fn add_export(
590 &mut self,
591 name: &str,
592 ty: EntityType,
593 offset: usize,
594 check_limit: bool,
595 types: &TypeList,
596 ) -> Result<()> {
597 if !self.features.mutable_global() {
598 if let EntityType::Global(global_type) = ty {
599 if global_type.mutable {
600 return Err(BinaryReaderError::new(
601 "mutable global support is not enabled",
602 offset,
603 ));
604 }
605 }
606 }
607
608 if check_limit {
609 check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
610 }
611
612 self.type_size = combine_type_sizes(self.type_size, ty.info(types).size(), offset)?;
613
614 match self.exports.insert(name.to_string(), ty) {
615 Some(_) => Err(format_err!(
616 offset,
617 "duplicate export name `{name}` already defined"
618 )),
619 None => Ok(()),
620 }
621 }
622
623 pub fn add_function(&mut self, type_index: u32, types: &TypeList, offset: usize) -> Result<()> {
624 self.func_type_at(type_index, types, offset)?;
625 self.functions.push(type_index);
626 Ok(())
627 }
628
629 pub fn add_memory(&mut self, ty: MemoryType, offset: usize) -> Result<()> {
630 self.check_memory_type(&ty, offset)?;
631 self.memories.push(ty);
632 Ok(())
633 }
634
635 pub fn add_tag(&mut self, ty: TagType, types: &TypeList, offset: usize) -> Result<()> {
636 self.check_tag_type(&ty, types, offset)?;
637 self.tags.push(self.types[ty.func_type_idx as usize]);
638 Ok(())
639 }
640
641 fn sub_type_at<'a>(&self, types: &'a TypeList, idx: u32, offset: usize) -> Result<&'a SubType> {
642 let id = self.type_id_at(idx, offset)?;
643 Ok(&types[id])
644 }
645
646 fn func_type_at<'a>(
647 &self,
648 type_index: u32,
649 types: &'a TypeList,
650 offset: usize,
651 ) -> Result<&'a FuncType> {
652 match &self
653 .sub_type_at(types, type_index, offset)?
654 .composite_type
655 .inner
656 {
657 CompositeInnerType::Func(f) => Ok(f),
658 _ => bail!(offset, "type index {type_index} is not a function type"),
659 }
660 }
661
662 pub fn check_type_ref(
663 &self,
664 type_ref: &mut TypeRef,
665 types: &TypeList,
666 offset: usize,
667 ) -> Result<EntityType> {
668 Ok(match type_ref {
669 TypeRef::Func(type_index) => {
670 self.func_type_at(*type_index, types, offset)?;
671 EntityType::Func(self.types[*type_index as usize])
672 }
673 TypeRef::Table(t) => {
674 self.check_table_type(t, types, offset)?;
675 EntityType::Table(*t)
676 }
677 TypeRef::Memory(t) => {
678 self.check_memory_type(t, offset)?;
679 EntityType::Memory(*t)
680 }
681 TypeRef::Tag(t) => {
682 self.check_tag_type(t, types, offset)?;
683 EntityType::Tag(self.types[t.func_type_idx as usize])
684 }
685 TypeRef::Global(t) => {
686 self.check_global_type(t, types, offset)?;
687 EntityType::Global(*t)
688 }
689 })
690 }
691
692 fn check_table_type(&self, ty: &mut TableType, types: &TypeList, offset: usize) -> Result<()> {
693 if ty.element_type != RefType::FUNCREF {
696 self.check_ref_type(&mut ty.element_type, offset)?
697 }
698
699 self.check_limits(ty.initial, ty.maximum, offset)?;
700 if ty.table64 && !self.features().memory64() {
701 bail!(offset, "memory64 must be enabled for 64-bit tables");
702 }
703 if ty.shared && !self.features().shared_everything_threads() {
704 bail!(
705 offset,
706 "shared tables require the shared-everything-threads proposal"
707 );
708 }
709
710 let true_maximum = if ty.table64 {
711 u64::MAX
712 } else {
713 u32::MAX as u64
714 };
715 let err = format!("table size must be at most {true_maximum:#x} entries");
716 if ty.initial > true_maximum {
717 return Err(BinaryReaderError::new(err, offset));
718 }
719 if let Some(maximum) = ty.maximum {
720 if maximum > true_maximum {
721 return Err(BinaryReaderError::new(err, offset));
722 }
723 }
724 if ty.shared && !types.reftype_is_shared(ty.element_type) {
725 return Err(BinaryReaderError::new(
726 "shared tables must have a shared element type",
727 offset,
728 ));
729 }
730 Ok(())
731 }
732
733 fn check_memory_type(&self, ty: &MemoryType, offset: usize) -> Result<()> {
734 self.check_limits(ty.initial, ty.maximum, offset)?;
735
736 if ty.memory64 && !self.features().memory64() {
737 bail!(offset, "memory64 must be enabled for 64-bit memories");
738 }
739 if ty.shared && !self.features().threads() {
740 bail!(offset, "threads must be enabled for shared memories");
741 }
742
743 let page_size = if let Some(page_size_log2) = ty.page_size_log2 {
744 if !self.features().custom_page_sizes() {
745 return Err(BinaryReaderError::new(
746 "the custom page sizes proposal must be enabled to customize a memory's page size",
747 offset,
748 ));
749 }
750 if page_size_log2 != 0 && page_size_log2 != 16 {
753 return Err(BinaryReaderError::new("invalid custom page size", offset));
754 }
755 let page_size = 1_u64 << page_size_log2;
756 debug_assert!(page_size.is_power_of_two());
757 debug_assert!(page_size == DEFAULT_WASM_PAGE_SIZE || page_size == 1);
758 page_size
759 } else {
760 let page_size_log2 = 16;
761 debug_assert_eq!(DEFAULT_WASM_PAGE_SIZE, 1 << page_size_log2);
762 DEFAULT_WASM_PAGE_SIZE
763 };
764 let true_maximum = if ty.memory64 {
765 max_wasm_memory64_pages(page_size)
766 } else {
767 max_wasm_memory32_pages(page_size)
768 };
769 let err = format!("memory size must be at most {true_maximum:#x} {page_size}-byte pages");
770 if ty.initial > true_maximum {
771 return Err(BinaryReaderError::new(err, offset));
772 }
773 if let Some(maximum) = ty.maximum {
774 if maximum > true_maximum {
775 return Err(BinaryReaderError::new(err, offset));
776 }
777 }
778 if ty.shared && ty.maximum.is_none() {
779 return Err(BinaryReaderError::new(
780 "shared memory must have maximum size",
781 offset,
782 ));
783 }
784 Ok(())
785 }
786
787 #[cfg(feature = "component-model")]
788 pub(crate) fn imports_for_module_type(
789 &self,
790 offset: usize,
791 ) -> Result<IndexMap<(String, String), EntityType>> {
792 self.imports
795 .iter()
796 .map(|((module, name), types)| {
797 if types.len() != 1 {
798 bail!(
799 offset,
800 "module has a duplicate import name `{module}:{name}` \
801 that is not allowed in components",
802 );
803 }
804 Ok(((module.clone(), name.clone()), types[0]))
805 })
806 .collect::<Result<_>>()
807 }
808
809 fn check_value_type(&self, ty: &mut ValType, offset: usize) -> Result<()> {
810 match ty {
813 ValType::Ref(rt) => self.check_ref_type(rt, offset),
814 _ => self
815 .features
816 .check_value_type(*ty)
817 .map_err(|e| BinaryReaderError::new(e, offset)),
818 }
819 }
820
821 fn check_ref_type(&self, ty: &mut RefType, offset: usize) -> Result<()> {
822 self.features
823 .check_ref_type(*ty)
824 .map_err(|e| BinaryReaderError::new(e, offset))?;
825 let mut hty = ty.heap_type();
826 self.check_heap_type(&mut hty, offset)?;
827 *ty = RefType::new(ty.is_nullable(), hty).unwrap();
828 Ok(())
829 }
830
831 fn check_heap_type(&self, ty: &mut HeapType, offset: usize) -> Result<()> {
832 let type_index = match ty {
834 HeapType::Abstract { .. } => return Ok(()),
835 HeapType::Concrete(type_index) => type_index,
836 };
837 match type_index {
838 UnpackedIndex::Module(idx) => {
839 let id = self.type_id_at(*idx, offset)?;
840 *type_index = UnpackedIndex::Id(id);
841 Ok(())
842 }
843 UnpackedIndex::RecGroup(_) | UnpackedIndex::Id(_) => unreachable!(),
847 }
848 }
849
850 fn check_tag_type(&self, ty: &TagType, types: &TypeList, offset: usize) -> Result<()> {
851 if !self.features().exceptions() {
852 bail!(offset, "exceptions proposal not enabled");
853 }
854 let ty = self.func_type_at(ty.func_type_idx, types, offset)?;
855 if !ty.results().is_empty() && !self.features.stack_switching() {
856 return Err(BinaryReaderError::new(
857 "invalid exception type: non-empty tag result type",
858 offset,
859 ));
860 }
861 Ok(())
862 }
863
864 fn check_global_type(
865 &self,
866 ty: &mut GlobalType,
867 types: &TypeList,
868 offset: usize,
869 ) -> Result<()> {
870 self.check_value_type(&mut ty.content_type, offset)?;
871 if ty.shared && !self.features.shared_everything_threads() {
872 bail!(
873 offset,
874 "shared globals require the shared-everything-threads proposal"
875 );
876 }
877 if ty.shared && !types.valtype_is_shared(ty.content_type) {
878 return Err(BinaryReaderError::new(
879 "shared globals must have a shared value type",
880 offset,
881 ));
882 }
883 Ok(())
884 }
885
886 fn check_limits<T>(&self, initial: T, maximum: Option<T>, offset: usize) -> Result<()>
887 where
888 T: Into<u64>,
889 {
890 if let Some(max) = maximum {
891 if initial.into() > max.into() {
892 return Err(BinaryReaderError::new(
893 "size minimum must not be greater than maximum",
894 offset,
895 ));
896 }
897 }
898 Ok(())
899 }
900
901 pub fn max_tables(&self) -> usize {
902 if self.features.reference_types() {
903 MAX_WASM_TABLES
904 } else {
905 1
906 }
907 }
908
909 pub fn max_memories(&self) -> usize {
910 if self.features.multi_memory() {
911 MAX_WASM_MEMORIES
912 } else {
913 1
914 }
915 }
916
917 pub fn export_to_entity_type(
918 &mut self,
919 export: &crate::Export,
920 offset: usize,
921 ) -> Result<EntityType> {
922 let check = |ty: &str, index: u32, total: usize| {
923 if index as usize >= total {
924 Err(format_err!(
925 offset,
926 "unknown {ty} {index}: exported {ty} index out of bounds",
927 ))
928 } else {
929 Ok(())
930 }
931 };
932
933 Ok(match export.kind {
934 ExternalKind::Func => {
935 check("function", export.index, self.functions.len())?;
936 self.function_references.insert(export.index);
937 EntityType::Func(self.types[self.functions[export.index as usize] as usize])
938 }
939 ExternalKind::Table => {
940 check("table", export.index, self.tables.len())?;
941 EntityType::Table(self.tables[export.index as usize])
942 }
943 ExternalKind::Memory => {
944 check("memory", export.index, self.memories.len())?;
945 EntityType::Memory(self.memories[export.index as usize])
946 }
947 ExternalKind::Global => {
948 check("global", export.index, self.globals.len())?;
949 EntityType::Global(self.globals[export.index as usize])
950 }
951 ExternalKind::Tag => {
952 check("tag", export.index, self.tags.len())?;
953 EntityType::Tag(self.tags[export.index as usize])
954 }
955 })
956 }
957
958 pub fn get_func_type<'a>(
959 &self,
960 func_idx: u32,
961 types: &'a TypeList,
962 offset: usize,
963 ) -> Result<&'a FuncType> {
964 match self.functions.get(func_idx as usize) {
965 Some(idx) => self.func_type_at(*idx, types, offset),
966 None => Err(format_err!(
967 offset,
968 "unknown function {func_idx}: func index out of bounds",
969 )),
970 }
971 }
972
973 fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> {
974 match self.globals.get(idx as usize) {
975 Some(t) => Ok(t),
976 None => Err(format_err!(
977 offset,
978 "unknown global {idx}: global index out of bounds"
979 )),
980 }
981 }
982
983 fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> {
984 match self.tables.get(idx as usize) {
985 Some(t) => Ok(t),
986 None => Err(format_err!(
987 offset,
988 "unknown table {idx}: table index out of bounds"
989 )),
990 }
991 }
992
993 fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> {
994 match self.memories.get(idx as usize) {
995 Some(t) => Ok(t),
996 None => Err(format_err!(
997 offset,
998 "unknown memory {idx}: memory index out of bounds"
999 )),
1000 }
1001 }
1002}
1003
1004impl InternRecGroup for Module {
1005 fn features(&self) -> &WasmFeatures {
1006 &self.features
1007 }
1008
1009 fn add_type_id(&mut self, id: CoreTypeId) {
1010 self.types.push(id);
1011 }
1012
1013 fn type_id_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
1014 self.types
1015 .get(idx as usize)
1016 .copied()
1017 .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
1018 }
1019
1020 fn types_len(&self) -> u32 {
1021 u32::try_from(self.types.len()).unwrap()
1022 }
1023}
1024
1025struct OperatorValidatorResources<'a> {
1026 module: &'a mut MaybeOwned<Module>,
1027 types: &'a TypeList,
1028}
1029
1030impl WasmModuleResources for OperatorValidatorResources<'_> {
1031 fn table_at(&self, at: u32) -> Option<TableType> {
1032 self.module.tables.get(at as usize).cloned()
1033 }
1034
1035 fn memory_at(&self, at: u32) -> Option<MemoryType> {
1036 self.module.memories.get(at as usize).cloned()
1037 }
1038
1039 fn tag_at(&self, at: u32) -> Option<&FuncType> {
1040 let type_id = *self.module.tags.get(at as usize)?;
1041 Some(self.types[type_id].unwrap_func())
1042 }
1043
1044 fn global_at(&self, at: u32) -> Option<GlobalType> {
1045 self.module.globals.get(at as usize).cloned()
1046 }
1047
1048 fn sub_type_at(&self, at: u32) -> Option<&SubType> {
1049 let id = *self.module.types.get(at as usize)?;
1050 Some(&self.types[id])
1051 }
1052
1053 fn sub_type_at_id(&self, at: CoreTypeId) -> &SubType {
1054 &self.types[at]
1055 }
1056
1057 fn type_id_of_function(&self, at: u32) -> Option<CoreTypeId> {
1058 let type_index = self.module.functions.get(at as usize)?;
1059 self.module.types.get(*type_index as usize).copied()
1060 }
1061
1062 fn type_index_of_function(&self, at: u32) -> Option<u32> {
1063 self.module.functions.get(at as usize).copied()
1064 }
1065
1066 fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> {
1067 self.module.check_heap_type(t, offset)
1068 }
1069
1070 fn top_type(&self, heap_type: &HeapType) -> HeapType {
1071 self.types.top_type(heap_type)
1072 }
1073
1074 fn element_type_at(&self, at: u32) -> Option<RefType> {
1075 self.module.element_types.get(at as usize).cloned()
1076 }
1077
1078 fn is_subtype(&self, a: ValType, b: ValType) -> bool {
1079 self.types.valtype_is_subtype(a, b)
1080 }
1081
1082 fn is_shared(&self, ty: RefType) -> bool {
1083 self.types.reftype_is_shared(ty)
1084 }
1085
1086 fn element_count(&self) -> u32 {
1087 self.module.element_types.len() as u32
1088 }
1089
1090 fn data_count(&self) -> Option<u32> {
1091 self.module.data_count
1092 }
1093
1094 fn is_function_referenced(&self, idx: u32) -> bool {
1095 self.module.function_references.contains(&idx)
1096 }
1097}
1098
1099#[derive(Debug)]
1102pub struct ValidatorResources(pub(crate) Arc<Module>);
1103
1104impl WasmModuleResources for ValidatorResources {
1105 fn table_at(&self, at: u32) -> Option<TableType> {
1106 self.0.tables.get(at as usize).cloned()
1107 }
1108
1109 fn memory_at(&self, at: u32) -> Option<MemoryType> {
1110 self.0.memories.get(at as usize).cloned()
1111 }
1112
1113 fn tag_at(&self, at: u32) -> Option<&FuncType> {
1114 let id = *self.0.tags.get(at as usize)?;
1115 let types = self.0.snapshot.as_ref().unwrap();
1116 match &types[id].composite_type.inner {
1117 CompositeInnerType::Func(f) => Some(f),
1118 _ => None,
1119 }
1120 }
1121
1122 fn global_at(&self, at: u32) -> Option<GlobalType> {
1123 self.0.globals.get(at as usize).cloned()
1124 }
1125
1126 fn sub_type_at(&self, at: u32) -> Option<&SubType> {
1127 let id = *self.0.types.get(at as usize)?;
1128 let types = self.0.snapshot.as_ref().unwrap();
1129 Some(&types[id])
1130 }
1131
1132 fn sub_type_at_id(&self, at: CoreTypeId) -> &SubType {
1133 let types = self.0.snapshot.as_ref().unwrap();
1134 &types[at]
1135 }
1136
1137 fn type_id_of_function(&self, at: u32) -> Option<CoreTypeId> {
1138 let type_index = *self.0.functions.get(at as usize)?;
1139 self.0.types.get(type_index as usize).copied()
1140 }
1141
1142 fn type_index_of_function(&self, at: u32) -> Option<u32> {
1143 self.0.functions.get(at as usize).copied()
1144 }
1145
1146 fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> {
1147 self.0.check_heap_type(t, offset)
1148 }
1149
1150 fn top_type(&self, heap_type: &HeapType) -> HeapType {
1151 self.0.snapshot.as_ref().unwrap().top_type(heap_type)
1152 }
1153
1154 fn element_type_at(&self, at: u32) -> Option<RefType> {
1155 self.0.element_types.get(at as usize).cloned()
1156 }
1157
1158 fn is_subtype(&self, a: ValType, b: ValType) -> bool {
1159 self.0.snapshot.as_ref().unwrap().valtype_is_subtype(a, b)
1160 }
1161
1162 fn is_shared(&self, ty: RefType) -> bool {
1163 self.0.snapshot.as_ref().unwrap().reftype_is_shared(ty)
1164 }
1165
1166 fn element_count(&self) -> u32 {
1167 self.0.element_types.len() as u32
1168 }
1169
1170 fn data_count(&self) -> Option<u32> {
1171 self.0.data_count
1172 }
1173
1174 fn is_function_referenced(&self, idx: u32) -> bool {
1175 self.0.function_references.contains(&idx)
1176 }
1177}
1178
1179const _: () = {
1180 const fn assert_send<T: Send>() {}
1181
1182 assert_send::<ValidatorResources>();
1185};
1186
1187mod arc {
1188 use alloc::sync::Arc;
1189 use core::ops::Deref;
1190
1191 enum Inner<T> {
1192 Owned(T),
1193 Shared(Arc<T>),
1194
1195 Empty, }
1197
1198 pub struct MaybeOwned<T> {
1199 inner: Inner<T>,
1200 }
1201
1202 impl<T> MaybeOwned<T> {
1203 pub fn new(val: T) -> MaybeOwned<T> {
1204 MaybeOwned {
1205 inner: Inner::Owned(val),
1206 }
1207 }
1208
1209 #[inline]
1210 pub(crate) fn as_mut(&mut self) -> Option<&mut T> {
1211 match &mut self.inner {
1212 Inner::Owned(x) => Some(x),
1213 Inner::Shared(_) => None,
1214 Inner::Empty => Self::unreachable(),
1215 }
1216 }
1217
1218 #[inline]
1219 pub fn assert_mut(&mut self) -> &mut T {
1220 self.as_mut().unwrap()
1221 }
1222
1223 pub fn arc(&mut self) -> &Arc<T> {
1224 self.make_shared();
1225 match &self.inner {
1226 Inner::Shared(x) => x,
1227 _ => Self::unreachable(),
1228 }
1229 }
1230
1231 #[inline]
1232 fn make_shared(&mut self) {
1233 if let Inner::Shared(_) = self.inner {
1234 return;
1235 }
1236
1237 let inner = core::mem::replace(&mut self.inner, Inner::Empty);
1238 let x = match inner {
1239 Inner::Owned(x) => x,
1240 _ => Self::unreachable(),
1241 };
1242 let x = Arc::new(x);
1243 self.inner = Inner::Shared(x);
1244 }
1245
1246 #[cold]
1247 #[inline(never)]
1248 fn unreachable() -> ! {
1249 unreachable!()
1250 }
1251 }
1252
1253 impl<T: Default> Default for MaybeOwned<T> {
1254 fn default() -> MaybeOwned<T> {
1255 MaybeOwned::new(T::default())
1256 }
1257 }
1258
1259 impl<T> Deref for MaybeOwned<T> {
1260 type Target = T;
1261
1262 fn deref(&self) -> &T {
1263 match &self.inner {
1264 Inner::Owned(x) => x,
1265 Inner::Shared(x) => x,
1266 Inner::Empty => Self::unreachable(),
1267 }
1268 }
1269 }
1270}