1use crate::prelude::*;
17use crate::{
18 limits::*, AbstractHeapType, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType,
19 Parser, Payload, RefType, Result, SectionLimited, ValType, WasmFeatures,
20 WASM_COMPONENT_VERSION, WASM_MODULE_VERSION,
21};
22use ::core::mem;
23use ::core::ops::Range;
24use ::core::sync::atomic::{AtomicUsize, Ordering};
25use alloc::sync::Arc;
26
27pub fn validate(bytes: &[u8]) -> Result<Types> {
42 Validator::new().validate_all(bytes)
43}
44
45#[test]
46fn test_validate() {
47 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0]).is_ok());
48 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0]).is_err());
49}
50
51mod component;
52mod core;
53mod func;
54pub mod names;
55mod operators;
56pub mod types;
57
58use self::component::*;
59pub use self::core::ValidatorResources;
60use self::core::*;
61use self::types::{TypeAlloc, Types, TypesRef};
62pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
63pub use operators::{Frame, FrameKind};
64
65fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
66 if max
67 .checked_sub(cur_len)
68 .and_then(|amt| amt.checked_sub(amt_added as usize))
69 .is_none()
70 {
71 if max == 1 {
72 bail!(offset, "multiple {desc}");
73 }
74
75 bail!(offset, "{desc} count exceeds limit of {max}");
76 }
77
78 Ok(())
79}
80
81fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
82 match a.checked_add(b) {
83 Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
84 _ => Err(format_err!(
85 offset,
86 "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
87 )),
88 }
89}
90
91#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
98pub struct ValidatorId(usize);
99
100impl Default for ValidatorId {
101 #[inline]
102 fn default() -> Self {
103 static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
104 ValidatorId(ID_COUNTER.fetch_add(1, Ordering::AcqRel))
105 }
106}
107
108#[derive(Default)]
134pub struct Validator {
135 id: ValidatorId,
136
137 state: State,
139
140 types: TypeAlloc,
142
143 module: Option<ModuleState>,
145
146 components: Vec<ComponentState>,
149
150 features: WasmFeatures,
153}
154
155#[derive(Debug, Clone, Copy, Eq, PartialEq)]
156enum State {
157 Unparsed(Option<Encoding>),
161 Module,
165 Component,
170 End,
172}
173
174impl State {
175 fn ensure_parsable(&self, offset: usize) -> Result<()> {
176 match self {
177 Self::Module | Self::Component => Ok(()),
178 Self::Unparsed(_) => Err(BinaryReaderError::new(
179 "unexpected section before header was parsed",
180 offset,
181 )),
182 Self::End => Err(BinaryReaderError::new(
183 "unexpected section after parsing has completed",
184 offset,
185 )),
186 }
187 }
188
189 fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
190 self.ensure_parsable(offset)?;
191
192 match self {
193 Self::Module => Ok(()),
194 Self::Component => Err(format_err!(
195 offset,
196 "unexpected module {section} section while parsing a component",
197 )),
198 _ => unreachable!(),
199 }
200 }
201
202 fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
203 self.ensure_parsable(offset)?;
204
205 match self {
206 Self::Component => Ok(()),
207 Self::Module => Err(format_err!(
208 offset,
209 "unexpected component {section} section while parsing a module",
210 )),
211 _ => unreachable!(),
212 }
213 }
214}
215
216impl Default for State {
217 fn default() -> Self {
218 Self::Unparsed(None)
219 }
220}
221
222impl WasmFeatures {
223 pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
228 match ty {
229 ValType::I32 | ValType::I64 => Ok(()),
230 ValType::F32 | ValType::F64 => {
231 if self.floats() {
232 Ok(())
233 } else {
234 Err("floating-point support is disabled")
235 }
236 }
237 ValType::Ref(r) => self.check_ref_type(r),
238 ValType::V128 => {
239 if self.simd() {
240 Ok(())
241 } else {
242 Err("SIMD support is not enabled")
243 }
244 }
245 }
246 }
247
248 pub(crate) fn check_ref_type(&self, r: RefType) -> Result<(), &'static str> {
249 if !self.reference_types() {
250 return Err("reference types support is not enabled");
251 }
252 match r.heap_type() {
253 HeapType::Concrete(_) => {
254 if self.function_references() || self.gc() {
263 Ok(())
264 } else {
265 Err("function references required for index reference types")
266 }
267 }
268 HeapType::Abstract { shared, ty } => {
269 use AbstractHeapType::*;
270 if shared && !self.shared_everything_threads() {
271 return Err(
272 "shared reference types require the shared-everything-threads proposal",
273 );
274 }
275
276 if !self.gc_types() && ty != Func && ty != Exn {
279 return Err("gc types are disallowed but found type which requires gc");
280 }
281
282 match (ty, r.is_nullable()) {
283 (Func, true) | (Extern, true) => Ok(()),
285
286 (Func | Extern, false) => {
289 if self.function_references() {
290 Ok(())
291 } else {
292 Err("function references required for non-nullable types")
293 }
294 }
295
296 (Any | None | Eq | Struct | Array | I31 | NoExtern | NoFunc, _) => {
298 if self.gc() {
299 Ok(())
300 } else {
301 Err("heap types not supported without the gc feature")
302 }
303 }
304
305 (Exn | NoExn, _) => {
307 if self.exceptions() {
308 Ok(())
309 } else {
310 Err("exception refs not supported without the exception handling feature")
311 }
312 }
313 }
314 }
315 }
316 }
317}
318
319#[allow(clippy::large_enum_variant)]
321pub enum ValidPayload<'a> {
322 Ok,
324 Parser(Parser),
329 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
331 End(Types),
334}
335
336impl Validator {
337 pub fn new() -> Validator {
344 Validator::default()
345 }
346
347 pub fn new_with_features(features: WasmFeatures) -> Validator {
355 let mut ret = Validator::new();
356 ret.features = features;
357 ret
358 }
359
360 pub fn features(&self) -> &WasmFeatures {
362 &self.features
363 }
364
365 pub fn reset(&mut self) {
418 let Validator {
419 id: _,
422
423 types: _,
425
426 features: _,
433
434 state,
435 module,
436 components,
437 } = self;
438
439 assert!(
440 matches!(state, State::End),
441 "cannot reset a validator that did not successfully complete validation"
442 );
443 assert!(module.is_none());
444 assert!(components.is_empty());
445
446 *state = State::default();
447 }
448
449 pub fn id(&self) -> ValidatorId {
456 self.id
457 }
458
459 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
468 let mut functions_to_validate = Vec::new();
469 let mut last_types = None;
470 let mut parser = Parser::new(0);
471 let _ = &mut parser;
472 #[cfg(feature = "features")]
473 parser.set_features(self.features);
474 for payload in parser.parse_all(bytes) {
475 match self.payload(&payload?)? {
476 ValidPayload::Func(a, b) => {
477 functions_to_validate.push((a, b));
478 }
479 ValidPayload::End(types) => {
480 last_types = Some(types);
482 }
483 _ => {}
484 }
485 }
486
487 let mut allocs = FuncValidatorAllocations::default();
488 for (func, body) in functions_to_validate {
489 let mut validator = func.into_validator(allocs);
490 validator.validate(&body)?;
491 allocs = validator.into_allocations();
492 }
493
494 Ok(last_types.unwrap())
495 }
496
497 pub fn types(&self, mut level: usize) -> Option<TypesRef> {
507 if let Some(module) = &self.module {
508 if level == 0 {
509 return Some(TypesRef::from_module(self.id, &self.types, &module.module));
510 } else {
511 level -= 1;
512 }
513 }
514
515 self.components
516 .iter()
517 .nth_back(level)
518 .map(|component| TypesRef::from_component(self.id, &self.types, component))
519 }
520
521 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
535 use crate::Payload::*;
536 match payload {
537 Version {
538 num,
539 encoding,
540 range,
541 } => self.version(*num, *encoding, range)?,
542
543 TypeSection(s) => self.type_section(s)?,
545 ImportSection(s) => self.import_section(s)?,
546 FunctionSection(s) => self.function_section(s)?,
547 TableSection(s) => self.table_section(s)?,
548 MemorySection(s) => self.memory_section(s)?,
549 TagSection(s) => self.tag_section(s)?,
550 GlobalSection(s) => self.global_section(s)?,
551 ExportSection(s) => self.export_section(s)?,
552 StartSection { func, range } => self.start_section(*func, range)?,
553 ElementSection(s) => self.element_section(s)?,
554 DataCountSection { count, range } => self.data_count_section(*count, range)?,
555 CodeSectionStart {
556 count,
557 range,
558 size: _,
559 } => self.code_section_start(*count, range)?,
560 CodeSectionEntry(body) => {
561 let func_validator = self.code_section_entry(body)?;
562 return Ok(ValidPayload::Func(func_validator, body.clone()));
563 }
564 DataSection(s) => self.data_section(s)?,
565
566 ModuleSection {
568 parser,
569 unchecked_range: range,
570 ..
571 } => {
572 self.module_section(range)?;
573 return Ok(ValidPayload::Parser(parser.clone()));
574 }
575 InstanceSection(s) => self.instance_section(s)?,
576 CoreTypeSection(s) => self.core_type_section(s)?,
577 ComponentSection {
578 parser,
579 unchecked_range: range,
580 ..
581 } => {
582 self.component_section(range)?;
583 return Ok(ValidPayload::Parser(parser.clone()));
584 }
585 ComponentInstanceSection(s) => self.component_instance_section(s)?,
586 ComponentAliasSection(s) => self.component_alias_section(s)?,
587 ComponentTypeSection(s) => self.component_type_section(s)?,
588 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
589 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
590 ComponentImportSection(s) => self.component_import_section(s)?,
591 ComponentExportSection(s) => self.component_export_section(s)?,
592
593 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
594
595 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
597 }
598 Ok(ValidPayload::Ok)
599 }
600
601 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
603 match &self.state {
604 State::Unparsed(expected) => {
605 if let Some(expected) = expected {
606 if *expected != encoding {
607 bail!(
608 range.start,
609 "expected a version header for a {}",
610 match expected {
611 Encoding::Module => "module",
612 Encoding::Component => "component",
613 }
614 );
615 }
616 }
617 }
618 _ => {
619 return Err(BinaryReaderError::new(
620 "wasm version header out of order",
621 range.start,
622 ))
623 }
624 }
625
626 self.state = match encoding {
627 Encoding::Module => {
628 if num == WASM_MODULE_VERSION {
629 assert!(self.module.is_none());
630 self.module = Some(ModuleState::default());
631 State::Module
632 } else {
633 bail!(range.start, "unknown binary version: {num:#x}");
634 }
635 }
636 Encoding::Component => {
637 if !self.features.component_model() {
638 bail!(
639 range.start,
640 "unknown binary version and encoding combination: {num:#x} and 0x1, \
641 note: encoded as a component but the WebAssembly component model feature \
642 is not enabled - enable the feature to allow component validation",
643 );
644 }
645 if num == WASM_COMPONENT_VERSION {
646 self.components
647 .push(ComponentState::new(ComponentKind::Component));
648 State::Component
649 } else if num < WASM_COMPONENT_VERSION {
650 bail!(range.start, "unsupported component version: {num:#x}");
651 } else {
652 bail!(range.start, "unknown component version: {num:#x}");
653 }
654 }
655 };
656
657 Ok(())
658 }
659
660 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
662 self.process_module_section(
663 Order::Type,
664 section,
665 "type",
666 |state, _, _types, count, offset| {
667 check_max(
668 state.module.types.len(),
669 count,
670 MAX_WASM_TYPES,
671 "types",
672 offset,
673 )?;
674 state.module.assert_mut().types.reserve(count as usize);
675 Ok(())
676 },
677 |state, features, types, rec_group, offset| {
678 state
679 .module
680 .assert_mut()
681 .add_types(rec_group, features, types, offset, true)?;
682 Ok(())
683 },
684 )
685 }
686
687 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
691 self.process_module_section(
692 Order::Import,
693 section,
694 "import",
695 |state, _, _, count, offset| {
696 check_max(
697 state.module.imports.len(),
698 count,
699 MAX_WASM_IMPORTS,
700 "imports",
701 offset,
702 )?;
703 state.module.assert_mut().imports.reserve(count as usize);
704 Ok(())
705 },
706 |state, features, types, import, offset| {
707 state
708 .module
709 .assert_mut()
710 .add_import(import, features, types, offset)
711 },
712 )
713 }
714
715 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
719 self.process_module_section(
720 Order::Function,
721 section,
722 "function",
723 |state, _, _, count, offset| {
724 check_max(
725 state.module.functions.len(),
726 count,
727 MAX_WASM_FUNCTIONS,
728 "functions",
729 offset,
730 )?;
731 state.module.assert_mut().functions.reserve(count as usize);
732 debug_assert!(state.expected_code_bodies.is_none());
733 state.expected_code_bodies = Some(count);
734 Ok(())
735 },
736 |state, _, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
737 )
738 }
739
740 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
744 let features = self.features;
745 self.process_module_section(
746 Order::Table,
747 section,
748 "table",
749 |state, _, _, count, offset| {
750 check_max(
751 state.module.tables.len(),
752 count,
753 state.module.max_tables(&features),
754 "tables",
755 offset,
756 )?;
757 state.module.assert_mut().tables.reserve(count as usize);
758 Ok(())
759 },
760 |state, features, types, table, offset| state.add_table(table, features, types, offset),
761 )
762 }
763
764 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
768 self.process_module_section(
769 Order::Memory,
770 section,
771 "memory",
772 |state, features, _, count, offset| {
773 check_max(
774 state.module.memories.len(),
775 count,
776 state.module.max_memories(features),
777 "memories",
778 offset,
779 )?;
780 state.module.assert_mut().memories.reserve(count as usize);
781 Ok(())
782 },
783 |state, features, _, ty, offset| {
784 state.module.assert_mut().add_memory(ty, features, offset)
785 },
786 )
787 }
788
789 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
793 if !self.features.exceptions() {
794 return Err(BinaryReaderError::new(
795 "exceptions proposal not enabled",
796 section.range().start,
797 ));
798 }
799
800 self.process_module_section(
801 Order::Tag,
802 section,
803 "tag",
804 |state, _, _, count, offset| {
805 check_max(
806 state.module.tags.len(),
807 count,
808 MAX_WASM_TAGS,
809 "tags",
810 offset,
811 )?;
812 state.module.assert_mut().tags.reserve(count as usize);
813 Ok(())
814 },
815 |state, features, types, ty, offset| {
816 state
817 .module
818 .assert_mut()
819 .add_tag(ty, features, types, offset)
820 },
821 )
822 }
823
824 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
828 self.process_module_section(
829 Order::Global,
830 section,
831 "global",
832 |state, _, _, count, offset| {
833 check_max(
834 state.module.globals.len(),
835 count,
836 MAX_WASM_GLOBALS,
837 "globals",
838 offset,
839 )?;
840 state.module.assert_mut().globals.reserve(count as usize);
841 Ok(())
842 },
843 |state, features, types, global, offset| {
844 state.add_global(global, features, types, offset)
845 },
846 )
847 }
848
849 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
853 self.process_module_section(
854 Order::Export,
855 section,
856 "export",
857 |state, _, _, count, offset| {
858 check_max(
859 state.module.exports.len(),
860 count,
861 MAX_WASM_EXPORTS,
862 "exports",
863 offset,
864 )?;
865 state.module.assert_mut().exports.reserve(count as usize);
866 Ok(())
867 },
868 |state, features, types, e, offset| {
869 let state = state.module.assert_mut();
870 let ty = state.export_to_entity_type(&e, offset)?;
871 state.add_export(
872 e.name, ty, features, offset, false, types,
874 )
875 },
876 )
877 }
878
879 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
883 let offset = range.start;
884 self.state.ensure_module("start", offset)?;
885 let state = self.module.as_mut().unwrap();
886 state.update_order(Order::Start, offset)?;
887
888 let ty = state.module.get_func_type(func, &self.types, offset)?;
889 if !ty.params().is_empty() || !ty.results().is_empty() {
890 return Err(BinaryReaderError::new(
891 "invalid start function type",
892 offset,
893 ));
894 }
895
896 Ok(())
897 }
898
899 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
903 self.process_module_section(
904 Order::Element,
905 section,
906 "element",
907 |state, _, _, count, offset| {
908 check_max(
909 state.module.element_types.len(),
910 count,
911 MAX_WASM_ELEMENT_SEGMENTS,
912 "element segments",
913 offset,
914 )?;
915 state
916 .module
917 .assert_mut()
918 .element_types
919 .reserve(count as usize);
920 Ok(())
921 },
922 |state, features, types, e, offset| {
923 state.add_element_segment(e, features, types, offset)
924 },
925 )
926 }
927
928 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
932 let offset = range.start;
933 self.state.ensure_module("data count", offset)?;
934
935 let state = self.module.as_mut().unwrap();
936 state.update_order(Order::DataCount, offset)?;
937
938 if count > MAX_WASM_DATA_SEGMENTS as u32 {
939 return Err(BinaryReaderError::new(
940 "data count section specifies too many data segments",
941 offset,
942 ));
943 }
944
945 state.module.assert_mut().data_count = Some(count);
946 Ok(())
947 }
948
949 pub fn code_section_start(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
953 let offset = range.start;
954 self.state.ensure_module("code", offset)?;
955
956 let state = self.module.as_mut().unwrap();
957 state.update_order(Order::Code, offset)?;
958
959 match state.expected_code_bodies.take() {
960 Some(n) if n == count => {}
961 Some(_) => {
962 return Err(BinaryReaderError::new(
963 "function and code section have inconsistent lengths",
964 offset,
965 ));
966 }
967 None if count == 0 => {}
970 None => {
971 return Err(BinaryReaderError::new(
972 "code section without function section",
973 offset,
974 ))
975 }
976 }
977
978 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
980
981 Ok(())
982 }
983
984 pub fn code_section_entry(
998 &mut self,
999 body: &crate::FunctionBody,
1000 ) -> Result<FuncToValidate<ValidatorResources>> {
1001 let offset = body.range().start;
1002 self.state.ensure_module("code", offset)?;
1003
1004 let state = self.module.as_mut().unwrap();
1005
1006 let (index, ty) = state.next_code_index_and_type(offset)?;
1007 Ok(FuncToValidate {
1008 index,
1009 ty,
1010 resources: ValidatorResources(state.module.arc().clone()),
1011 features: self.features,
1012 })
1013 }
1014
1015 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1019 self.process_module_section(
1020 Order::Data,
1021 section,
1022 "data",
1023 |state, _, _, count, offset| {
1024 state.data_segment_count = count;
1025 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1026 },
1027 |state, features, types, d, offset| state.add_data_segment(d, features, types, offset),
1028 )
1029 }
1030
1031 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1035 self.state.ensure_component("module", range.start)?;
1036
1037 let current = self.components.last_mut().unwrap();
1038 check_max(
1039 current.core_modules.len(),
1040 1,
1041 MAX_WASM_MODULES,
1042 "modules",
1043 range.start,
1044 )?;
1045
1046 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1047 State::Component => {}
1048 _ => unreachable!(),
1049 }
1050
1051 Ok(())
1052 }
1053
1054 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1058 self.process_component_section(
1059 section,
1060 "core instance",
1061 |components, _, count, offset| {
1062 let current = components.last_mut().unwrap();
1063 check_max(
1064 current.instance_count(),
1065 count,
1066 MAX_WASM_INSTANCES,
1067 "instances",
1068 offset,
1069 )?;
1070 current.core_instances.reserve(count as usize);
1071 Ok(())
1072 },
1073 |components, types, _, instance, offset| {
1074 components
1075 .last_mut()
1076 .unwrap()
1077 .add_core_instance(instance, types, offset)
1078 },
1079 )
1080 }
1081
1082 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1086 self.process_component_section(
1087 section,
1088 "core type",
1089 |components, _types, count, offset| {
1090 let current = components.last_mut().unwrap();
1091 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1092 current.core_types.reserve(count as usize);
1093 Ok(())
1094 },
1095 |components, types, features, ty, offset| {
1096 ComponentState::add_core_type(
1097 components, ty, features, types, offset, false, )
1099 },
1100 )
1101 }
1102
1103 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1107 self.state.ensure_component("component", range.start)?;
1108
1109 let current = self.components.last_mut().unwrap();
1110 check_max(
1111 current.components.len(),
1112 1,
1113 MAX_WASM_COMPONENTS,
1114 "components",
1115 range.start,
1116 )?;
1117
1118 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1119 State::Component => {}
1120 _ => unreachable!(),
1121 }
1122
1123 Ok(())
1124 }
1125
1126 pub fn component_instance_section(
1130 &mut self,
1131 section: &crate::ComponentInstanceSectionReader,
1132 ) -> Result<()> {
1133 self.process_component_section(
1134 section,
1135 "instance",
1136 |components, _, count, offset| {
1137 let current = components.last_mut().unwrap();
1138 check_max(
1139 current.instance_count(),
1140 count,
1141 MAX_WASM_INSTANCES,
1142 "instances",
1143 offset,
1144 )?;
1145 current.instances.reserve(count as usize);
1146 Ok(())
1147 },
1148 |components, types, features, instance, offset| {
1149 components
1150 .last_mut()
1151 .unwrap()
1152 .add_instance(instance, features, types, offset)
1153 },
1154 )
1155 }
1156
1157 pub fn component_alias_section(
1161 &mut self,
1162 section: &crate::ComponentAliasSectionReader<'_>,
1163 ) -> Result<()> {
1164 self.process_component_section(
1165 section,
1166 "alias",
1167 |_, _, _, _| Ok(()), |components, types, features, alias, offset| -> Result<(), BinaryReaderError> {
1169 ComponentState::add_alias(components, alias, features, types, offset)
1170 },
1171 )
1172 }
1173
1174 pub fn component_type_section(
1178 &mut self,
1179 section: &crate::ComponentTypeSectionReader,
1180 ) -> Result<()> {
1181 self.process_component_section(
1182 section,
1183 "type",
1184 |components, _types, count, offset| {
1185 let current = components.last_mut().unwrap();
1186 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1187 current.types.reserve(count as usize);
1188 Ok(())
1189 },
1190 |components, types, features, ty, offset| {
1191 ComponentState::add_type(
1192 components, ty, features, types, offset, false, )
1194 },
1195 )
1196 }
1197
1198 pub fn component_canonical_section(
1202 &mut self,
1203 section: &crate::ComponentCanonicalSectionReader,
1204 ) -> Result<()> {
1205 self.process_component_section(
1206 section,
1207 "function",
1208 |components, _, count, offset| {
1209 let current = components.last_mut().unwrap();
1210 check_max(
1211 current.function_count(),
1212 count,
1213 MAX_WASM_FUNCTIONS,
1214 "functions",
1215 offset,
1216 )?;
1217 current.funcs.reserve(count as usize);
1218 Ok(())
1219 },
1220 |components, types, _, func, offset| {
1221 let current = components.last_mut().unwrap();
1222 match func {
1223 crate::CanonicalFunction::Lift {
1224 core_func_index,
1225 type_index,
1226 options,
1227 } => current.lift_function(
1228 core_func_index,
1229 type_index,
1230 options.into_vec(),
1231 types,
1232 offset,
1233 ),
1234 crate::CanonicalFunction::Lower {
1235 func_index,
1236 options,
1237 } => current.lower_function(func_index, options.into_vec(), types, offset),
1238 crate::CanonicalFunction::ResourceNew { resource } => {
1239 current.resource_new(resource, types, offset)
1240 }
1241 crate::CanonicalFunction::ResourceDrop { resource } => {
1242 current.resource_drop(resource, types, offset)
1243 }
1244 crate::CanonicalFunction::ResourceRep { resource } => {
1245 current.resource_rep(resource, types, offset)
1246 }
1247 }
1248 },
1249 )
1250 }
1251
1252 pub fn component_start_section(
1256 &mut self,
1257 f: &crate::ComponentStartFunction,
1258 range: &Range<usize>,
1259 ) -> Result<()> {
1260 self.state.ensure_component("start", range.start)?;
1261
1262 self.components.last_mut().unwrap().add_start(
1263 f.func_index,
1264 &f.arguments,
1265 f.results,
1266 &self.features,
1267 &mut self.types,
1268 range.start,
1269 )
1270 }
1271
1272 pub fn component_import_section(
1276 &mut self,
1277 section: &crate::ComponentImportSectionReader,
1278 ) -> Result<()> {
1279 self.process_component_section(
1280 section,
1281 "import",
1282 |_, _, _, _| Ok(()), |components, types, features, import, offset| {
1284 components
1285 .last_mut()
1286 .unwrap()
1287 .add_import(import, features, types, offset)
1288 },
1289 )
1290 }
1291
1292 pub fn component_export_section(
1296 &mut self,
1297 section: &crate::ComponentExportSectionReader,
1298 ) -> Result<()> {
1299 self.process_component_section(
1300 section,
1301 "export",
1302 |components, _, count, offset| {
1303 let current = components.last_mut().unwrap();
1304 check_max(
1305 current.exports.len(),
1306 count,
1307 MAX_WASM_EXPORTS,
1308 "exports",
1309 offset,
1310 )?;
1311 current.exports.reserve(count as usize);
1312 Ok(())
1313 },
1314 |components, types, features, export, offset| {
1315 let current = components.last_mut().unwrap();
1316 let ty = current.export_to_entity_type(&export, features, types, offset)?;
1317 current.add_export(
1318 export.name,
1319 ty,
1320 features,
1321 types,
1322 offset,
1323 false, )
1325 },
1326 )
1327 }
1328
1329 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1333 Err(format_err!(range.start, "malformed section id: {id}"))
1334 }
1335
1336 pub fn end(&mut self, offset: usize) -> Result<Types> {
1340 match mem::replace(&mut self.state, State::End) {
1341 State::Unparsed(_) => Err(BinaryReaderError::new(
1342 "cannot call `end` before a header has been parsed",
1343 offset,
1344 )),
1345 State::End => Err(BinaryReaderError::new(
1346 "cannot call `end` after parsing has completed",
1347 offset,
1348 )),
1349 State::Module => {
1350 let mut state = self.module.take().unwrap();
1351 state.validate_end(offset)?;
1352
1353 if let Some(parent) = self.components.last_mut() {
1356 parent.add_core_module(&state.module, &mut self.types, offset)?;
1357 self.state = State::Component;
1358 }
1359
1360 Ok(Types::from_module(
1361 self.id,
1362 self.types.commit(),
1363 state.module.arc().clone(),
1364 ))
1365 }
1366 State::Component => {
1367 let mut component = self.components.pop().unwrap();
1368
1369 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1371 bail!(
1372 offset,
1373 "value index {index} was not used as part of an \
1374 instantiation, start function, or export"
1375 );
1376 }
1377
1378 let ty = component.finish(&mut self.types, offset)?;
1381 if let Some(parent) = self.components.last_mut() {
1382 parent.add_component(ty, &mut self.types)?;
1383 self.state = State::Component;
1384 }
1385
1386 Ok(Types::from_component(
1387 self.id,
1388 self.types.commit(),
1389 component,
1390 ))
1391 }
1392 }
1393 }
1394
1395 fn process_module_section<'a, T>(
1396 &mut self,
1397 order: Order,
1398 section: &SectionLimited<'a, T>,
1399 name: &str,
1400 validate_section: impl FnOnce(
1401 &mut ModuleState,
1402 &WasmFeatures,
1403 &mut TypeAlloc,
1404 u32,
1405 usize,
1406 ) -> Result<()>,
1407 mut validate_item: impl FnMut(
1408 &mut ModuleState,
1409 &WasmFeatures,
1410 &mut TypeAlloc,
1411 T,
1412 usize,
1413 ) -> Result<()>,
1414 ) -> Result<()>
1415 where
1416 T: FromReader<'a>,
1417 {
1418 let offset = section.range().start;
1419 self.state.ensure_module(name, offset)?;
1420
1421 let state = self.module.as_mut().unwrap();
1422 state.update_order(order, offset)?;
1423
1424 validate_section(
1425 state,
1426 &self.features,
1427 &mut self.types,
1428 section.count(),
1429 offset,
1430 )?;
1431
1432 for item in section.clone().into_iter_with_offsets() {
1433 let (offset, item) = item?;
1434 validate_item(state, &self.features, &mut self.types, item, offset)?;
1435 }
1436
1437 Ok(())
1438 }
1439
1440 fn process_component_section<'a, T>(
1441 &mut self,
1442 section: &SectionLimited<'a, T>,
1443 name: &str,
1444 validate_section: impl FnOnce(
1445 &mut Vec<ComponentState>,
1446 &mut TypeAlloc,
1447 u32,
1448 usize,
1449 ) -> Result<()>,
1450 mut validate_item: impl FnMut(
1451 &mut Vec<ComponentState>,
1452 &mut TypeAlloc,
1453 &WasmFeatures,
1454 T,
1455 usize,
1456 ) -> Result<()>,
1457 ) -> Result<()>
1458 where
1459 T: FromReader<'a>,
1460 {
1461 let offset = section.range().start;
1462
1463 if !self.features.component_model() {
1464 return Err(BinaryReaderError::new(
1465 "component model feature is not enabled",
1466 offset,
1467 ));
1468 }
1469
1470 self.state.ensure_component(name, offset)?;
1471 validate_section(
1472 &mut self.components,
1473 &mut self.types,
1474 section.count(),
1475 offset,
1476 )?;
1477
1478 for item in section.clone().into_iter_with_offsets() {
1479 let (offset, item) = item?;
1480 validate_item(
1481 &mut self.components,
1482 &mut self.types,
1483 &self.features,
1484 item,
1485 offset,
1486 )?;
1487 }
1488
1489 Ok(())
1490 }
1491}
1492
1493#[cfg(test)]
1494mod tests {
1495 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1496 use anyhow::Result;
1497
1498 #[test]
1499 fn test_module_type_information() -> Result<()> {
1500 let bytes = wat::parse_str(
1501 r#"
1502 (module
1503 (type (func (param i32 i64) (result i32)))
1504 (memory 1 5)
1505 (table 10 funcref)
1506 (global (mut i32) (i32.const 0))
1507 (func (type 0) (i32.const 0))
1508 (tag (param i64 i32))
1509 (elem funcref (ref.func 0))
1510 )
1511 "#,
1512 )?;
1513
1514 let mut validator =
1515 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1516
1517 let types = validator.validate_all(&bytes)?;
1518
1519 assert_eq!(types.type_count(), 2);
1520 assert_eq!(types.memory_count(), 1);
1521 assert_eq!(types.table_count(), 1);
1522 assert_eq!(types.global_count(), 1);
1523 assert_eq!(types.core_function_count(), 1);
1524 assert_eq!(types.tag_count(), 1);
1525 assert_eq!(types.element_count(), 1);
1526 assert_eq!(types.module_count(), 0);
1527 assert_eq!(types.component_count(), 0);
1528 assert_eq!(types.core_instance_count(), 0);
1529 assert_eq!(types.value_count(), 0);
1530
1531 let id = match types.core_type_at(0) {
1532 crate::types::ComponentCoreTypeId::Sub(s) => s,
1533 crate::types::ComponentCoreTypeId::Module(_) => panic!(),
1534 };
1535 let ty = types[id].unwrap_func();
1536 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1537 assert_eq!(ty.results(), [ValType::I32]);
1538
1539 let id = match types.core_type_at(1) {
1540 crate::types::ComponentCoreTypeId::Sub(s) => s,
1541 crate::types::ComponentCoreTypeId::Module(_) => panic!(),
1542 };
1543 let ty = types[id].unwrap_func();
1544 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1545 assert_eq!(ty.results(), []);
1546
1547 assert_eq!(
1548 types.memory_at(0),
1549 MemoryType {
1550 memory64: false,
1551 shared: false,
1552 initial: 1,
1553 maximum: Some(5),
1554 page_size_log2: None,
1555 }
1556 );
1557
1558 assert_eq!(
1559 types.table_at(0),
1560 TableType {
1561 initial: 10,
1562 maximum: None,
1563 element_type: RefType::FUNCREF,
1564 table64: false,
1565 shared: false,
1566 }
1567 );
1568
1569 assert_eq!(
1570 types.global_at(0),
1571 GlobalType {
1572 content_type: ValType::I32,
1573 mutable: true,
1574 shared: false
1575 }
1576 );
1577
1578 let id = types.core_function_at(0);
1579 let ty = types[id].unwrap_func();
1580 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1581 assert_eq!(ty.results(), [ValType::I32]);
1582
1583 let ty = types.tag_at(0);
1584 let ty = types[ty].unwrap_func();
1585 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1586 assert_eq!(ty.results(), []);
1587
1588 assert_eq!(types.element_at(0), RefType::FUNCREF);
1589
1590 Ok(())
1591 }
1592
1593 #[test]
1594 fn test_type_id_aliasing() -> Result<()> {
1595 let bytes = wat::parse_str(
1596 r#"
1597 (component
1598 (type $T (list string))
1599 (alias outer 0 $T (type $A1))
1600 (alias outer 0 $T (type $A2))
1601 )
1602 "#,
1603 )?;
1604
1605 let mut validator =
1606 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1607
1608 let types = validator.validate_all(&bytes)?;
1609
1610 let t_id = types.component_defined_type_at(0);
1611 let a1_id = types.component_defined_type_at(1);
1612 let a2_id = types.component_defined_type_at(2);
1613
1614 assert!(t_id == a1_id);
1616 assert!(t_id == a2_id);
1617 assert!(a1_id == a2_id);
1618
1619 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1621 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1622
1623 Ok(())
1624 }
1625
1626 #[test]
1627 fn test_type_id_exports() -> Result<()> {
1628 let bytes = wat::parse_str(
1629 r#"
1630 (component
1631 (type $T (list string))
1632 (export $A1 "A1" (type $T))
1633 (export $A2 "A2" (type $T))
1634 )
1635 "#,
1636 )?;
1637
1638 let mut validator =
1639 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1640
1641 let types = validator.validate_all(&bytes)?;
1642
1643 let t_id = types.component_defined_type_at(0);
1644 let a1_id = types.component_defined_type_at(1);
1645 let a2_id = types.component_defined_type_at(2);
1646
1647 assert!(t_id != a1_id);
1649 assert!(t_id != a2_id);
1650 assert!(a1_id != a2_id);
1651
1652 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1654 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1655
1656 Ok(())
1657 }
1658}