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