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