1use crate::prelude::*;
17use crate::{
18 AbstractHeapType, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser,
19 Payload, RefType, Result, SectionLimited, ValType, WASM_MODULE_VERSION, WasmFeatures,
20 limits::*,
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
51#[cfg(feature = "component-model")]
52mod component;
53#[cfg(feature = "component-model")]
54pub mod component_types;
55mod core;
56mod func;
57#[cfg(feature = "component-model")]
58pub mod names;
59mod operators;
60pub mod types;
61
62#[cfg(feature = "component-model")]
63use self::component::*;
64pub use self::core::ValidatorResources;
65use self::core::*;
66use self::types::{TypeAlloc, Types, TypesRef};
67pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
68pub use operators::Frame;
69
70fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
71 if max
72 .checked_sub(cur_len)
73 .and_then(|amt| amt.checked_sub(amt_added as usize))
74 .is_none()
75 {
76 if max == 1 {
77 bail!(offset, "multiple {desc}");
78 }
79
80 bail!(offset, "{desc} count exceeds limit of {max}");
81 }
82
83 Ok(())
84}
85
86fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
87 match a.checked_add(b) {
88 Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
89 _ => Err(format_err!(
90 offset,
91 "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
92 )),
93 }
94}
95
96#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
103pub struct ValidatorId(usize);
104
105impl Default for ValidatorId {
106 #[inline]
107 fn default() -> Self {
108 static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
109 ValidatorId(ID_COUNTER.fetch_add(1, Ordering::AcqRel))
110 }
111}
112
113#[derive(Default)]
139pub struct Validator {
140 id: ValidatorId,
141
142 state: State,
144
145 types: TypeAlloc,
147
148 module: Option<ModuleState>,
150
151 #[cfg(feature = "component-model")]
154 components: Vec<ComponentState>,
155
156 features: WasmFeatures,
159}
160
161#[derive(Debug, Clone, Copy, Eq, PartialEq)]
162enum State {
163 Unparsed(Option<Encoding>),
167 Module,
171 #[cfg(feature = "component-model")]
176 Component,
177 End,
179}
180
181impl State {
182 fn ensure_parsable(&self, offset: usize) -> Result<()> {
183 match self {
184 Self::Module => Ok(()),
185 #[cfg(feature = "component-model")]
186 Self::Component => Ok(()),
187 Self::Unparsed(_) => Err(BinaryReaderError::new(
188 "unexpected section before header was parsed",
189 offset,
190 )),
191 Self::End => Err(BinaryReaderError::new(
192 "unexpected section after parsing has completed",
193 offset,
194 )),
195 }
196 }
197
198 fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
199 self.ensure_parsable(offset)?;
200 let _ = section;
201
202 match self {
203 Self::Module => Ok(()),
204 #[cfg(feature = "component-model")]
205 Self::Component => Err(format_err!(
206 offset,
207 "unexpected module {section} section while parsing a component",
208 )),
209 _ => unreachable!(),
210 }
211 }
212
213 #[cfg(feature = "component-model")]
214 fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
215 self.ensure_parsable(offset)?;
216
217 match self {
218 Self::Component => Ok(()),
219 Self::Module => Err(format_err!(
220 offset,
221 "unexpected component {section} section while parsing a module",
222 )),
223 _ => unreachable!(),
224 }
225 }
226}
227
228impl Default for State {
229 fn default() -> Self {
230 Self::Unparsed(None)
231 }
232}
233
234impl WasmFeatures {
235 pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
240 match ty {
241 ValType::I32 | ValType::I64 => Ok(()),
242 ValType::F32 | ValType::F64 => {
243 if self.floats() {
244 Ok(())
245 } else {
246 Err("floating-point support is disabled")
247 }
248 }
249 ValType::Ref(r) => self.check_ref_type(r),
250 ValType::V128 => {
251 if self.simd() {
252 Ok(())
253 } else {
254 Err("SIMD support is not enabled")
255 }
256 }
257 }
258 }
259
260 pub(crate) fn check_ref_type(&self, r: RefType) -> Result<(), &'static str> {
261 if !self.reference_types() {
262 return Err("reference types support is not enabled");
263 }
264 match r.heap_type() {
265 HeapType::Concrete(_) => {
266 if self.function_references() || self.gc() {
275 Ok(())
276 } else {
277 Err("function references required for index reference types")
278 }
279 }
280 HeapType::Abstract { shared, ty } => {
281 use AbstractHeapType::*;
282 if shared && !self.shared_everything_threads() {
283 return Err(
284 "shared reference types require the shared-everything-threads proposal",
285 );
286 }
287
288 if !self.gc_types() && ty != Func && ty != Exn {
291 return Err("gc types are disallowed but found type which requires gc");
292 }
293
294 match (ty, r.is_nullable()) {
295 (Func, true) | (Extern, true) => Ok(()),
297
298 (Func | Extern, false) => {
301 if self.function_references() {
302 Ok(())
303 } else {
304 Err("function references required for non-nullable types")
305 }
306 }
307
308 (Any | None | Eq | Struct | Array | I31 | NoExtern | NoFunc, _) => {
310 if self.gc() {
311 Ok(())
312 } else {
313 Err("heap types not supported without the gc feature")
314 }
315 }
316
317 (Exn | NoExn, _) => {
319 if self.exceptions() {
320 Ok(())
321 } else {
322 Err(
323 "exception refs not supported without the exception handling feature",
324 )
325 }
326 }
327
328 (Cont | NoCont, _) => {
330 if self.stack_switching() {
331 Ok(())
332 } else {
333 Err(
334 "continuation refs not supported without the stack switching feature",
335 )
336 }
337 }
338 }
339 }
340 }
341 }
342}
343
344#[allow(clippy::large_enum_variant)]
346pub enum ValidPayload<'a> {
347 Ok,
349 Parser(Parser),
354 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
356 End(Types),
359}
360
361impl Validator {
362 pub fn new() -> Validator {
369 Validator::default()
370 }
371
372 pub fn new_with_features(features: WasmFeatures) -> Validator {
380 let mut ret = Validator::new();
381 ret.features = features;
382 ret
383 }
384
385 pub fn features(&self) -> &WasmFeatures {
387 &self.features
388 }
389
390 pub fn reset(&mut self) {
451 let Validator {
452 id: _,
455
456 types: _,
458
459 features: _,
466
467 state,
468 module,
469 #[cfg(feature = "component-model")]
470 components,
471 } = self;
472
473 assert!(
474 matches!(state, State::End) || matches!(state, State::Unparsed(None)),
475 "cannot reset a validator that did not successfully complete validation"
476 );
477 assert!(module.is_none());
478 #[cfg(feature = "component-model")]
479 assert!(components.is_empty());
480
481 *state = State::default();
482 }
483
484 pub fn id(&self) -> ValidatorId {
491 self.id
492 }
493
494 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
503 let mut functions_to_validate = Vec::new();
504 let mut last_types = None;
505 let mut parser = Parser::new(0);
506 let _ = &mut parser;
507 #[cfg(feature = "features")]
508 parser.set_features(self.features);
509 for payload in parser.parse_all(bytes) {
510 match self.payload(&payload?)? {
511 ValidPayload::Func(a, b) => {
512 functions_to_validate.push((a, b));
513 }
514 ValidPayload::End(types) => {
515 last_types = Some(types);
517 }
518 _ => {}
519 }
520 }
521
522 let mut allocs = FuncValidatorAllocations::default();
523 for (func, body) in functions_to_validate {
524 let mut validator = func.into_validator(allocs);
525 validator.validate(&body)?;
526 allocs = validator.into_allocations();
527 }
528
529 Ok(last_types.unwrap())
530 }
531
532 pub fn types(&self, mut level: usize) -> Option<TypesRef<'_>> {
542 if let Some(module) = &self.module {
543 if level == 0 {
544 return Some(TypesRef::from_module(self.id, &self.types, &module.module));
545 } else {
546 level -= 1;
547 let _ = level;
548 }
549 }
550
551 #[cfg(feature = "component-model")]
552 return self
553 .components
554 .iter()
555 .nth_back(level)
556 .map(|component| TypesRef::from_component(self.id, &self.types, component));
557 #[cfg(not(feature = "component-model"))]
558 return None;
559 }
560
561 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
575 use crate::Payload::*;
576 match payload {
577 Version {
578 num,
579 encoding,
580 range,
581 } => self.version(*num, *encoding, range)?,
582
583 TypeSection(s) => self.type_section(s)?,
585 ImportSection(s) => self.import_section(s)?,
586 FunctionSection(s) => self.function_section(s)?,
587 TableSection(s) => self.table_section(s)?,
588 MemorySection(s) => self.memory_section(s)?,
589 TagSection(s) => self.tag_section(s)?,
590 GlobalSection(s) => self.global_section(s)?,
591 ExportSection(s) => self.export_section(s)?,
592 StartSection { func, range } => self.start_section(*func, range)?,
593 ElementSection(s) => self.element_section(s)?,
594 DataCountSection { count, range } => self.data_count_section(*count, range)?,
595 CodeSectionStart {
596 count: _,
597 range,
598 size: _,
599 } => self.code_section_start(range)?,
600 CodeSectionEntry(body) => {
601 let func_validator = self.code_section_entry(body)?;
602 return Ok(ValidPayload::Func(func_validator, body.clone()));
603 }
604 DataSection(s) => self.data_section(s)?,
605
606 #[cfg(feature = "component-model")]
608 ModuleSection {
609 parser,
610 unchecked_range: range,
611 ..
612 } => {
613 self.module_section(range)?;
614 return Ok(ValidPayload::Parser(parser.clone()));
615 }
616 #[cfg(feature = "component-model")]
617 InstanceSection(s) => self.instance_section(s)?,
618 #[cfg(feature = "component-model")]
619 CoreTypeSection(s) => self.core_type_section(s)?,
620 #[cfg(feature = "component-model")]
621 ComponentSection {
622 parser,
623 unchecked_range: range,
624 ..
625 } => {
626 self.component_section(range)?;
627 return Ok(ValidPayload::Parser(parser.clone()));
628 }
629 #[cfg(feature = "component-model")]
630 ComponentInstanceSection(s) => self.component_instance_section(s)?,
631 #[cfg(feature = "component-model")]
632 ComponentAliasSection(s) => self.component_alias_section(s)?,
633 #[cfg(feature = "component-model")]
634 ComponentTypeSection(s) => self.component_type_section(s)?,
635 #[cfg(feature = "component-model")]
636 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
637 #[cfg(feature = "component-model")]
638 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
639 #[cfg(feature = "component-model")]
640 ComponentImportSection(s) => self.component_import_section(s)?,
641 #[cfg(feature = "component-model")]
642 ComponentExportSection(s) => self.component_export_section(s)?,
643
644 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
645
646 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
648 }
649 Ok(ValidPayload::Ok)
650 }
651
652 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
654 match &self.state {
655 State::Unparsed(expected) => {
656 if let Some(expected) = expected {
657 if *expected != encoding {
658 bail!(
659 range.start,
660 "expected a version header for a {}",
661 match expected {
662 Encoding::Module => "module",
663 Encoding::Component => "component",
664 }
665 );
666 }
667 }
668 }
669 _ => {
670 return Err(BinaryReaderError::new(
671 "wasm version header out of order",
672 range.start,
673 ));
674 }
675 }
676
677 self.state = match encoding {
678 Encoding::Module => {
679 if num == WASM_MODULE_VERSION {
680 assert!(self.module.is_none());
681 self.module = Some(ModuleState::new(self.features));
682 State::Module
683 } else {
684 bail!(range.start, "unknown binary version: {num:#x}");
685 }
686 }
687 Encoding::Component => {
688 if !self.features.component_model() {
689 bail!(
690 range.start,
691 "unknown binary version and encoding combination: {num:#x} and 0x1, \
692 note: encoded as a component but the WebAssembly component model feature \
693 is not enabled - enable the feature to allow component validation",
694 );
695 }
696 #[cfg(feature = "component-model")]
697 if num == crate::WASM_COMPONENT_VERSION {
698 self.components
699 .push(ComponentState::new(ComponentKind::Component, self.features));
700 State::Component
701 } else if num < crate::WASM_COMPONENT_VERSION {
702 bail!(range.start, "unsupported component version: {num:#x}");
703 } else {
704 bail!(range.start, "unknown component version: {num:#x}");
705 }
706 #[cfg(not(feature = "component-model"))]
707 bail!(
708 range.start,
709 "component model validation support disabled \
710 at compile time"
711 );
712 }
713 };
714
715 Ok(())
716 }
717
718 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
720 self.process_module_section(
721 section,
722 "type",
723 |state, _types, count, offset| {
724 check_max(
725 state.module.types.len(),
726 count,
727 MAX_WASM_TYPES,
728 "types",
729 offset,
730 )?;
731 state.module.assert_mut().types.reserve(count as usize);
732 Ok(())
733 },
734 |state, types, rec_group, offset| {
735 state
736 .module
737 .assert_mut()
738 .add_types(rec_group, types, offset, true)?;
739 Ok(())
740 },
741 )
742 }
743
744 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
748 self.process_module_section(
749 section,
750 "import",
751 |state, _, count, offset| {
752 check_max(
753 state.module.imports.len(),
754 count,
755 MAX_WASM_IMPORTS,
756 "imports",
757 offset,
758 )?;
759 state.module.assert_mut().imports.reserve(count as usize);
760 Ok(())
761 },
762 |state, types, import, offset| {
763 state.module.assert_mut().add_import(import, types, offset)
764 },
765 )
766 }
767
768 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
772 self.process_module_section(
773 section,
774 "function",
775 |state, _, count, offset| {
776 check_max(
777 state.module.functions.len(),
778 count,
779 MAX_WASM_FUNCTIONS,
780 "functions",
781 offset,
782 )?;
783 state.module.assert_mut().functions.reserve(count as usize);
784 Ok(())
785 },
786 |state, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
787 )
788 }
789
790 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
794 self.process_module_section(
795 section,
796 "table",
797 |state, _, count, offset| {
798 check_max(
799 state.module.tables.len(),
800 count,
801 state.module.max_tables(),
802 "tables",
803 offset,
804 )?;
805 state.module.assert_mut().tables.reserve(count as usize);
806 Ok(())
807 },
808 |state, types, table, offset| state.add_table(table, types, offset),
809 )
810 }
811
812 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
816 self.process_module_section(
817 section,
818 "memory",
819 |state, _, count, offset| {
820 check_max(
821 state.module.memories.len(),
822 count,
823 state.module.max_memories(),
824 "memories",
825 offset,
826 )?;
827 state.module.assert_mut().memories.reserve(count as usize);
828 Ok(())
829 },
830 |state, _, ty, offset| state.module.assert_mut().add_memory(ty, offset),
831 )
832 }
833
834 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
838 if !self.features.exceptions() {
839 return Err(BinaryReaderError::new(
840 "exceptions proposal not enabled",
841 section.range().start,
842 ));
843 }
844 self.process_module_section(
845 section,
846 "tag",
847 |state, _, count, offset| {
848 check_max(
849 state.module.tags.len(),
850 count,
851 MAX_WASM_TAGS,
852 "tags",
853 offset,
854 )?;
855 state.module.assert_mut().tags.reserve(count as usize);
856 Ok(())
857 },
858 |state, types, ty, offset| state.module.assert_mut().add_tag(ty, types, offset),
859 )
860 }
861
862 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
866 self.process_module_section(
867 section,
868 "global",
869 |state, _, count, offset| {
870 check_max(
871 state.module.globals.len(),
872 count,
873 MAX_WASM_GLOBALS,
874 "globals",
875 offset,
876 )?;
877 state.module.assert_mut().globals.reserve(count as usize);
878 Ok(())
879 },
880 |state, types, global, offset| state.add_global(global, types, offset),
881 )
882 }
883
884 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
888 self.process_module_section(
889 section,
890 "export",
891 |state, _, count, offset| {
892 check_max(
893 state.module.exports.len(),
894 count,
895 MAX_WASM_EXPORTS,
896 "exports",
897 offset,
898 )?;
899 state.module.assert_mut().exports.reserve(count as usize);
900 Ok(())
901 },
902 |state, types, e, offset| {
903 let state = state.module.assert_mut();
904 let ty = state.export_to_entity_type(&e, offset)?;
905 state.add_export(e.name, ty, offset, false , types)
906 },
907 )
908 }
909
910 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
914 let offset = range.start;
915 self.state.ensure_module("start", offset)?;
916 let state = self.module.as_mut().unwrap();
917
918 let ty = state.module.get_func_type(func, &self.types, offset)?;
919 if !ty.params().is_empty() || !ty.results().is_empty() {
920 return Err(BinaryReaderError::new(
921 "invalid start function type",
922 offset,
923 ));
924 }
925
926 Ok(())
927 }
928
929 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
933 self.process_module_section(
934 section,
935 "element",
936 |state, _, count, offset| {
937 check_max(
938 state.module.element_types.len(),
939 count,
940 MAX_WASM_ELEMENT_SEGMENTS,
941 "element segments",
942 offset,
943 )?;
944 state
945 .module
946 .assert_mut()
947 .element_types
948 .reserve(count as usize);
949 Ok(())
950 },
951 |state, types, e, offset| state.add_element_segment(e, types, offset),
952 )
953 }
954
955 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
959 let offset = range.start;
960 self.state.ensure_module("data count", offset)?;
961
962 let state = self.module.as_mut().unwrap();
963
964 if count > MAX_WASM_DATA_SEGMENTS as u32 {
965 return Err(BinaryReaderError::new(
966 "data count section specifies too many data segments",
967 offset,
968 ));
969 }
970
971 state.module.assert_mut().data_count = Some(count);
972 Ok(())
973 }
974
975 pub fn code_section_start(&mut self, range: &Range<usize>) -> Result<()> {
979 let offset = range.start;
980 self.state.ensure_module("code", offset)?;
981
982 let state = self.module.as_mut().unwrap();
983
984 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
986
987 Ok(())
988 }
989
990 pub fn code_section_entry(
1004 &mut self,
1005 body: &crate::FunctionBody,
1006 ) -> Result<FuncToValidate<ValidatorResources>> {
1007 let offset = body.range().start;
1008 self.state.ensure_module("code", offset)?;
1009
1010 let state = self.module.as_mut().unwrap();
1011
1012 let (index, ty) = state.next_code_index_and_type();
1013 Ok(FuncToValidate {
1014 index,
1015 ty,
1016 resources: ValidatorResources(state.module.arc().clone()),
1017 features: self.features,
1018 })
1019 }
1020
1021 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1025 self.process_module_section(
1026 section,
1027 "data",
1028 |_, _, count, offset| {
1029 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1030 },
1031 |state, types, d, offset| state.add_data_segment(d, types, offset),
1032 )
1033 }
1034
1035 #[cfg(feature = "component-model")]
1039 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1040 self.state.ensure_component("module", range.start)?;
1041
1042 let current = self.components.last_mut().unwrap();
1043 check_max(
1044 current.core_modules.len(),
1045 1,
1046 MAX_WASM_MODULES,
1047 "modules",
1048 range.start,
1049 )?;
1050
1051 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1052 State::Component => {}
1053 _ => unreachable!(),
1054 }
1055
1056 Ok(())
1057 }
1058
1059 #[cfg(feature = "component-model")]
1063 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1064 self.process_component_section(
1065 section,
1066 "core instance",
1067 |components, _, count, offset| {
1068 let current = components.last_mut().unwrap();
1069 check_max(
1070 current.instance_count(),
1071 count,
1072 MAX_WASM_INSTANCES,
1073 "instances",
1074 offset,
1075 )?;
1076 current.core_instances.reserve(count as usize);
1077 Ok(())
1078 },
1079 |components, types, _features, instance, offset| {
1080 components
1081 .last_mut()
1082 .unwrap()
1083 .add_core_instance(instance, types, offset)
1084 },
1085 )
1086 }
1087
1088 #[cfg(feature = "component-model")]
1092 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1093 self.process_component_section(
1094 section,
1095 "core type",
1096 |components, _types, count, offset| {
1097 let current = components.last_mut().unwrap();
1098 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1099 current.core_types.reserve(count as usize);
1100 Ok(())
1101 },
1102 |components, types, _features, ty, offset| {
1103 ComponentState::add_core_type(
1104 components, ty, types, offset, false, )
1106 },
1107 )
1108 }
1109
1110 #[cfg(feature = "component-model")]
1114 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1115 self.state.ensure_component("component", range.start)?;
1116
1117 let current = self.components.last_mut().unwrap();
1118 check_max(
1119 current.components.len(),
1120 1,
1121 MAX_WASM_COMPONENTS,
1122 "components",
1123 range.start,
1124 )?;
1125
1126 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1127 State::Component => {}
1128 _ => unreachable!(),
1129 }
1130
1131 Ok(())
1132 }
1133
1134 #[cfg(feature = "component-model")]
1138 pub fn component_instance_section(
1139 &mut self,
1140 section: &crate::ComponentInstanceSectionReader,
1141 ) -> Result<()> {
1142 self.process_component_section(
1143 section,
1144 "instance",
1145 |components, _, count, offset| {
1146 let current = components.last_mut().unwrap();
1147 check_max(
1148 current.instance_count(),
1149 count,
1150 MAX_WASM_INSTANCES,
1151 "instances",
1152 offset,
1153 )?;
1154 current.instances.reserve(count as usize);
1155 Ok(())
1156 },
1157 |components, types, _features, instance, offset| {
1158 components
1159 .last_mut()
1160 .unwrap()
1161 .add_instance(instance, types, offset)
1162 },
1163 )
1164 }
1165
1166 #[cfg(feature = "component-model")]
1170 pub fn component_alias_section(
1171 &mut self,
1172 section: &crate::ComponentAliasSectionReader<'_>,
1173 ) -> Result<()> {
1174 self.process_component_section(
1175 section,
1176 "alias",
1177 |_, _, _, _| Ok(()), |components, types, _features, alias, offset| -> Result<(), BinaryReaderError> {
1179 ComponentState::add_alias(components, alias, types, offset)
1180 },
1181 )
1182 }
1183
1184 #[cfg(feature = "component-model")]
1188 pub fn component_type_section(
1189 &mut self,
1190 section: &crate::ComponentTypeSectionReader,
1191 ) -> Result<()> {
1192 self.process_component_section(
1193 section,
1194 "type",
1195 |components, _types, count, offset| {
1196 let current = components.last_mut().unwrap();
1197 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1198 current.types.reserve(count as usize);
1199 Ok(())
1200 },
1201 |components, types, _features, ty, offset| {
1202 ComponentState::add_type(
1203 components, ty, types, offset, false, )
1205 },
1206 )
1207 }
1208
1209 #[cfg(feature = "component-model")]
1213 pub fn component_canonical_section(
1214 &mut self,
1215 section: &crate::ComponentCanonicalSectionReader,
1216 ) -> Result<()> {
1217 self.process_component_section(
1218 section,
1219 "function",
1220 |components, _, count, offset| {
1221 let current = components.last_mut().unwrap();
1222 check_max(
1223 current.function_count(),
1224 count,
1225 MAX_WASM_FUNCTIONS,
1226 "functions",
1227 offset,
1228 )?;
1229 current.funcs.reserve(count as usize);
1230 Ok(())
1231 },
1232 |components, types, _features, func, offset| {
1233 let current = components.last_mut().unwrap();
1234 current.canonical_function(func, types, offset)
1235 },
1236 )
1237 }
1238
1239 #[cfg(feature = "component-model")]
1243 pub fn component_start_section(
1244 &mut self,
1245 f: &crate::ComponentStartFunction,
1246 range: &Range<usize>,
1247 ) -> Result<()> {
1248 self.state.ensure_component("start", range.start)?;
1249
1250 self.components.last_mut().unwrap().add_start(
1251 f.func_index,
1252 &f.arguments,
1253 f.results,
1254 &mut self.types,
1255 range.start,
1256 )
1257 }
1258
1259 #[cfg(feature = "component-model")]
1263 pub fn component_import_section(
1264 &mut self,
1265 section: &crate::ComponentImportSectionReader,
1266 ) -> Result<()> {
1267 self.process_component_section(
1268 section,
1269 "import",
1270 |_, _, _, _| Ok(()), |components, types, _features, import, offset| {
1272 components
1273 .last_mut()
1274 .unwrap()
1275 .add_import(import, types, offset)
1276 },
1277 )
1278 }
1279
1280 #[cfg(feature = "component-model")]
1284 pub fn component_export_section(
1285 &mut self,
1286 section: &crate::ComponentExportSectionReader,
1287 ) -> Result<()> {
1288 self.process_component_section(
1289 section,
1290 "export",
1291 |components, _, count, offset| {
1292 let current = components.last_mut().unwrap();
1293 check_max(
1294 current.exports.len(),
1295 count,
1296 MAX_WASM_EXPORTS,
1297 "exports",
1298 offset,
1299 )?;
1300 current.exports.reserve(count as usize);
1301 Ok(())
1302 },
1303 |components, types, _features, export, offset| {
1304 let current = components.last_mut().unwrap();
1305 let ty = current.export_to_entity_type(&export, types, offset)?;
1306 current.add_export(
1307 export.name,
1308 ty,
1309 types,
1310 offset,
1311 false, )
1313 },
1314 )
1315 }
1316
1317 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1321 Err(format_err!(range.start, "malformed section id: {id}"))
1322 }
1323
1324 pub fn end(&mut self, offset: usize) -> Result<Types> {
1328 match mem::replace(&mut self.state, State::End) {
1329 State::Unparsed(_) => Err(BinaryReaderError::new(
1330 "cannot call `end` before a header has been parsed",
1331 offset,
1332 )),
1333 State::End => Err(BinaryReaderError::new(
1334 "cannot call `end` after parsing has completed",
1335 offset,
1336 )),
1337 State::Module => {
1338 let mut state = self.module.take().unwrap();
1339
1340 #[cfg(feature = "component-model")]
1343 if let Some(parent) = self.components.last_mut() {
1344 parent.add_core_module(&state.module, &mut self.types, offset)?;
1345 self.state = State::Component;
1346 }
1347
1348 Ok(Types::from_module(
1349 self.id,
1350 self.types.commit(),
1351 state.module.arc().clone(),
1352 ))
1353 }
1354 #[cfg(feature = "component-model")]
1355 State::Component => {
1356 let mut component = self.components.pop().unwrap();
1357
1358 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1360 bail!(
1361 offset,
1362 "value index {index} was not used as part of an \
1363 instantiation, start function, or export"
1364 );
1365 }
1366
1367 let ty = component.finish(&self.types, offset)?;
1370 if let Some(parent) = self.components.last_mut() {
1371 parent.add_component(ty, &mut self.types)?;
1372 self.state = State::Component;
1373 }
1374
1375 Ok(Types::from_component(
1376 self.id,
1377 self.types.commit(),
1378 component,
1379 ))
1380 }
1381 }
1382 }
1383
1384 fn process_module_section<'a, T>(
1385 &mut self,
1386 section: &SectionLimited<'a, T>,
1387 name: &str,
1388 validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>,
1389 mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>,
1390 ) -> Result<()>
1391 where
1392 T: FromReader<'a>,
1393 {
1394 let offset = section.range().start;
1395 self.state.ensure_module(name, offset)?;
1396
1397 let state = self.module.as_mut().unwrap();
1398
1399 validate_section(state, &mut self.types, section.count(), offset)?;
1400
1401 for item in section.clone().into_iter_with_offsets() {
1402 let (offset, item) = item?;
1403 validate_item(state, &mut self.types, item, offset)?;
1404 }
1405
1406 Ok(())
1407 }
1408
1409 #[cfg(feature = "component-model")]
1410 fn process_component_section<'a, T>(
1411 &mut self,
1412 section: &SectionLimited<'a, T>,
1413 name: &str,
1414 validate_section: impl FnOnce(
1415 &mut Vec<ComponentState>,
1416 &mut TypeAlloc,
1417 u32,
1418 usize,
1419 ) -> Result<()>,
1420 mut validate_item: impl FnMut(
1421 &mut Vec<ComponentState>,
1422 &mut TypeAlloc,
1423 &WasmFeatures,
1424 T,
1425 usize,
1426 ) -> Result<()>,
1427 ) -> Result<()>
1428 where
1429 T: FromReader<'a>,
1430 {
1431 let offset = section.range().start;
1432
1433 self.state.ensure_component(name, offset)?;
1434 validate_section(
1435 &mut self.components,
1436 &mut self.types,
1437 section.count(),
1438 offset,
1439 )?;
1440
1441 for item in section.clone().into_iter_with_offsets() {
1442 let (offset, item) = item?;
1443 validate_item(
1444 &mut self.components,
1445 &mut self.types,
1446 &self.features,
1447 item,
1448 offset,
1449 )?;
1450 }
1451
1452 Ok(())
1453 }
1454}
1455
1456#[cfg(test)]
1457mod tests {
1458 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1459 use anyhow::Result;
1460
1461 #[test]
1462 fn test_module_type_information() -> Result<()> {
1463 let bytes = wat::parse_str(
1464 r#"
1465 (module
1466 (type (func (param i32 i64) (result i32)))
1467 (memory 1 5)
1468 (table 10 funcref)
1469 (global (mut i32) (i32.const 0))
1470 (func (type 0) (i32.const 0))
1471 (tag (param i64 i32))
1472 (elem funcref (ref.func 0))
1473 )
1474 "#,
1475 )?;
1476
1477 let mut validator =
1478 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1479
1480 let types = validator.validate_all(&bytes)?;
1481 let types = types.as_ref();
1482
1483 assert_eq!(types.core_type_count_in_module(), 2);
1484 assert_eq!(types.memory_count(), 1);
1485 assert_eq!(types.table_count(), 1);
1486 assert_eq!(types.global_count(), 1);
1487 assert_eq!(types.function_count(), 1);
1488 assert_eq!(types.tag_count(), 1);
1489 assert_eq!(types.element_count(), 1);
1490 assert_eq!(types.module_count(), 0);
1491 assert_eq!(types.component_count(), 0);
1492 assert_eq!(types.core_instance_count(), 0);
1493 assert_eq!(types.value_count(), 0);
1494
1495 let id = types.core_type_at_in_module(0);
1496 let ty = types[id].unwrap_func();
1497 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1498 assert_eq!(ty.results(), [ValType::I32]);
1499
1500 let id = types.core_type_at_in_module(1);
1501 let ty = types[id].unwrap_func();
1502 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1503 assert_eq!(ty.results(), []);
1504
1505 assert_eq!(
1506 types.memory_at(0),
1507 MemoryType {
1508 memory64: false,
1509 shared: false,
1510 initial: 1,
1511 maximum: Some(5),
1512 page_size_log2: None,
1513 }
1514 );
1515
1516 assert_eq!(
1517 types.table_at(0),
1518 TableType {
1519 initial: 10,
1520 maximum: None,
1521 element_type: RefType::FUNCREF,
1522 table64: false,
1523 shared: false,
1524 }
1525 );
1526
1527 assert_eq!(
1528 types.global_at(0),
1529 GlobalType {
1530 content_type: ValType::I32,
1531 mutable: true,
1532 shared: false
1533 }
1534 );
1535
1536 let id = types.core_function_at(0);
1537 let ty = types[id].unwrap_func();
1538 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1539 assert_eq!(ty.results(), [ValType::I32]);
1540
1541 let ty = types.tag_at(0);
1542 let ty = types[ty].unwrap_func();
1543 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1544 assert_eq!(ty.results(), []);
1545
1546 assert_eq!(types.element_at(0), RefType::FUNCREF);
1547
1548 Ok(())
1549 }
1550
1551 #[test]
1552 fn test_type_id_aliasing() -> Result<()> {
1553 let bytes = wat::parse_str(
1554 r#"
1555 (component
1556 (type $T (list string))
1557 (alias outer 0 $T (type $A1))
1558 (alias outer 0 $T (type $A2))
1559 )
1560 "#,
1561 )?;
1562
1563 let mut validator =
1564 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1565
1566 let types = validator.validate_all(&bytes)?;
1567 let types = types.as_ref();
1568
1569 let t_id = types.component_defined_type_at(0);
1570 let a1_id = types.component_defined_type_at(1);
1571 let a2_id = types.component_defined_type_at(2);
1572
1573 assert!(t_id == a1_id);
1575 assert!(t_id == a2_id);
1576 assert!(a1_id == a2_id);
1577
1578 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1580 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1581
1582 Ok(())
1583 }
1584
1585 #[test]
1586 fn test_type_id_exports() -> Result<()> {
1587 let bytes = wat::parse_str(
1588 r#"
1589 (component
1590 (type $T (list string))
1591 (export $A1 "A1" (type $T))
1592 (export $A2 "A2" (type $T))
1593 )
1594 "#,
1595 )?;
1596
1597 let mut validator =
1598 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1599
1600 let types = validator.validate_all(&bytes)?;
1601 let types = types.as_ref();
1602
1603 let t_id = types.component_defined_type_at(0);
1604 let a1_id = types.component_defined_type_at(1);
1605 let a2_id = types.component_defined_type_at(2);
1606
1607 assert!(t_id != a1_id);
1609 assert!(t_id != a2_id);
1610 assert!(a1_id != a2_id);
1611
1612 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1614 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1615
1616 Ok(())
1617 }
1618
1619 #[test]
1620 fn reset_fresh_validator() {
1621 Validator::new().reset();
1622 }
1623}