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::Exact(_) => {
281 if self.custom_descriptors() {
284 Ok(())
285 } else {
286 Err("custom descriptors required for exact reference types")
287 }
288 }
289 HeapType::Abstract { shared, ty } => {
290 use AbstractHeapType::*;
291 if shared && !self.shared_everything_threads() {
292 return Err(
293 "shared reference types require the shared-everything-threads proposal",
294 );
295 }
296
297 if !self.gc_types() && ty != Func && ty != Exn {
300 return Err("gc types are disallowed but found type which requires gc");
301 }
302
303 match (ty, r.is_nullable()) {
304 (Func, true) | (Extern, true) => Ok(()),
306
307 (Func | Extern, false) => {
310 if self.function_references() {
311 Ok(())
312 } else {
313 Err("function references required for non-nullable types")
314 }
315 }
316
317 (Any | None | Eq | Struct | Array | I31 | NoExtern | NoFunc, _) => {
319 if self.gc() {
320 Ok(())
321 } else {
322 Err("heap types not supported without the gc feature")
323 }
324 }
325
326 (Exn | NoExn, _) => {
328 if self.exceptions() {
329 Ok(())
330 } else {
331 Err(
332 "exception refs not supported without the exception handling feature",
333 )
334 }
335 }
336
337 (Cont | NoCont, _) => {
339 if self.stack_switching() {
340 Ok(())
341 } else {
342 Err(
343 "continuation refs not supported without the stack switching feature",
344 )
345 }
346 }
347 }
348 }
349 }
350 }
351}
352
353#[allow(clippy::large_enum_variant)]
355pub enum ValidPayload<'a> {
356 Ok,
358 Parser(Parser),
363 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
365 End(Types),
368}
369
370impl Validator {
371 pub fn new() -> Validator {
378 Validator::default()
379 }
380
381 pub fn new_with_features(features: WasmFeatures) -> Validator {
389 let mut ret = Validator::new();
390 ret.features = features;
391 ret
392 }
393
394 pub fn features(&self) -> &WasmFeatures {
396 &self.features
397 }
398
399 pub fn reset(&mut self) {
460 let Validator {
461 id: _,
464
465 types: _,
467
468 features: _,
475
476 state,
477 module,
478 #[cfg(feature = "component-model")]
479 components,
480 } = self;
481
482 assert!(
483 matches!(state, State::End) || matches!(state, State::Unparsed(None)),
484 "cannot reset a validator that did not successfully complete validation"
485 );
486 assert!(module.is_none());
487 #[cfg(feature = "component-model")]
488 assert!(components.is_empty());
489
490 *state = State::default();
491 }
492
493 pub fn id(&self) -> ValidatorId {
500 self.id
501 }
502
503 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
512 let mut functions_to_validate = Vec::new();
513 let mut last_types = None;
514 let mut parser = Parser::new(0);
515 let _ = &mut parser;
516 #[cfg(feature = "features")]
517 parser.set_features(self.features);
518 for payload in parser.parse_all(bytes) {
519 match self.payload(&payload?)? {
520 ValidPayload::Func(a, b) => {
521 functions_to_validate.push((a, b));
522 }
523 ValidPayload::End(types) => {
524 last_types = Some(types);
526 }
527 _ => {}
528 }
529 }
530
531 let mut allocs = FuncValidatorAllocations::default();
532 for (func, body) in functions_to_validate {
533 let mut validator = func.into_validator(allocs);
534 validator.validate(&body)?;
535 allocs = validator.into_allocations();
536 }
537
538 Ok(last_types.unwrap())
539 }
540
541 pub fn types(&self, mut level: usize) -> Option<TypesRef<'_>> {
551 if let Some(module) = &self.module {
552 if level == 0 {
553 return Some(TypesRef::from_module(self.id, &self.types, &module.module));
554 } else {
555 level -= 1;
556 let _ = level;
557 }
558 }
559
560 #[cfg(feature = "component-model")]
561 return self
562 .components
563 .iter()
564 .nth_back(level)
565 .map(|component| TypesRef::from_component(self.id, &self.types, component));
566 #[cfg(not(feature = "component-model"))]
567 return None;
568 }
569
570 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
584 use crate::Payload::*;
585 match payload {
586 Version {
587 num,
588 encoding,
589 range,
590 } => self.version(*num, *encoding, range)?,
591
592 TypeSection(s) => self.type_section(s)?,
594 ImportSection(s) => self.import_section(s)?,
595 FunctionSection(s) => self.function_section(s)?,
596 TableSection(s) => self.table_section(s)?,
597 MemorySection(s) => self.memory_section(s)?,
598 TagSection(s) => self.tag_section(s)?,
599 GlobalSection(s) => self.global_section(s)?,
600 ExportSection(s) => self.export_section(s)?,
601 StartSection { func, range } => self.start_section(*func, range)?,
602 ElementSection(s) => self.element_section(s)?,
603 DataCountSection { count, range } => self.data_count_section(*count, range)?,
604 CodeSectionStart {
605 count: _,
606 range,
607 size: _,
608 } => self.code_section_start(range)?,
609 CodeSectionEntry(body) => {
610 let func_validator = self.code_section_entry(body)?;
611 return Ok(ValidPayload::Func(func_validator, body.clone()));
612 }
613 DataSection(s) => self.data_section(s)?,
614
615 #[cfg(feature = "component-model")]
617 ModuleSection {
618 parser,
619 unchecked_range: range,
620 ..
621 } => {
622 self.module_section(range)?;
623 return Ok(ValidPayload::Parser(parser.clone()));
624 }
625 #[cfg(feature = "component-model")]
626 InstanceSection(s) => self.instance_section(s)?,
627 #[cfg(feature = "component-model")]
628 CoreTypeSection(s) => self.core_type_section(s)?,
629 #[cfg(feature = "component-model")]
630 ComponentSection {
631 parser,
632 unchecked_range: range,
633 ..
634 } => {
635 self.component_section(range)?;
636 return Ok(ValidPayload::Parser(parser.clone()));
637 }
638 #[cfg(feature = "component-model")]
639 ComponentInstanceSection(s) => self.component_instance_section(s)?,
640 #[cfg(feature = "component-model")]
641 ComponentAliasSection(s) => self.component_alias_section(s)?,
642 #[cfg(feature = "component-model")]
643 ComponentTypeSection(s) => self.component_type_section(s)?,
644 #[cfg(feature = "component-model")]
645 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
646 #[cfg(feature = "component-model")]
647 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
648 #[cfg(feature = "component-model")]
649 ComponentImportSection(s) => self.component_import_section(s)?,
650 #[cfg(feature = "component-model")]
651 ComponentExportSection(s) => self.component_export_section(s)?,
652
653 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
654
655 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
657 }
658 Ok(ValidPayload::Ok)
659 }
660
661 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
663 match &self.state {
664 State::Unparsed(expected) => {
665 if let Some(expected) = expected {
666 if *expected != encoding {
667 bail!(
668 range.start,
669 "expected a version header for a {}",
670 match expected {
671 Encoding::Module => "module",
672 Encoding::Component => "component",
673 }
674 );
675 }
676 }
677 }
678 _ => {
679 return Err(BinaryReaderError::new(
680 "wasm version header out of order",
681 range.start,
682 ));
683 }
684 }
685
686 self.state = match encoding {
687 Encoding::Module => {
688 if num == WASM_MODULE_VERSION {
689 assert!(self.module.is_none());
690 self.module = Some(ModuleState::new(self.features));
691 State::Module
692 } else {
693 bail!(range.start, "unknown binary version: {num:#x}");
694 }
695 }
696 Encoding::Component => {
697 if !self.features.component_model() {
698 bail!(
699 range.start,
700 "unknown binary version and encoding combination: {num:#x} and 0x1, \
701 note: encoded as a component but the WebAssembly component model feature \
702 is not enabled - enable the feature to allow component validation",
703 );
704 }
705 #[cfg(feature = "component-model")]
706 if num == crate::WASM_COMPONENT_VERSION {
707 self.components
708 .push(ComponentState::new(ComponentKind::Component, self.features));
709 State::Component
710 } else if num < crate::WASM_COMPONENT_VERSION {
711 bail!(range.start, "unsupported component version: {num:#x}");
712 } else {
713 bail!(range.start, "unknown component version: {num:#x}");
714 }
715 #[cfg(not(feature = "component-model"))]
716 bail!(
717 range.start,
718 "component model validation support disabled \
719 at compile time"
720 );
721 }
722 };
723
724 Ok(())
725 }
726
727 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
729 self.process_module_section(
730 section,
731 "type",
732 |state, _types, count, offset| {
733 check_max(
734 state.module.types.len(),
735 count,
736 MAX_WASM_TYPES,
737 "types",
738 offset,
739 )?;
740 state.module.assert_mut().types.reserve(count as usize);
741 Ok(())
742 },
743 |state, types, rec_group, offset| {
744 state
745 .module
746 .assert_mut()
747 .add_types(rec_group, types, offset, true)?;
748 Ok(())
749 },
750 )
751 }
752
753 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
757 self.process_module_section(
758 section,
759 "import",
760 |state, _, count, offset| {
761 check_max(
762 state.module.imports.len(),
763 count,
764 MAX_WASM_IMPORTS,
765 "imports",
766 offset,
767 )?;
768 state.module.assert_mut().imports.reserve(count as usize);
769 Ok(())
770 },
771 |state, types, imports, _offset| {
772 let state = state.module.assert_mut();
773 for import_and_offset in imports {
774 let (offset, import) = import_and_offset?;
775 state.add_import(import, types, offset)?;
776 }
777 Ok(())
778 },
779 )
780 }
781
782 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
786 self.process_module_section(
787 section,
788 "function",
789 |state, _, count, offset| {
790 check_max(
791 state.module.functions.len(),
792 count,
793 MAX_WASM_FUNCTIONS,
794 "functions",
795 offset,
796 )?;
797 state.module.assert_mut().functions.reserve(count as usize);
798 Ok(())
799 },
800 |state, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
801 )
802 }
803
804 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
808 self.process_module_section(
809 section,
810 "table",
811 |state, _, count, offset| {
812 check_max(
813 state.module.tables.len(),
814 count,
815 state.module.max_tables(),
816 "tables",
817 offset,
818 )?;
819 state.module.assert_mut().tables.reserve(count as usize);
820 Ok(())
821 },
822 |state, types, table, offset| state.add_table(table, types, offset),
823 )
824 }
825
826 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
830 self.process_module_section(
831 section,
832 "memory",
833 |state, _, count, offset| {
834 check_max(
835 state.module.memories.len(),
836 count,
837 state.module.max_memories(),
838 "memories",
839 offset,
840 )?;
841 state.module.assert_mut().memories.reserve(count as usize);
842 Ok(())
843 },
844 |state, _, ty, offset| state.module.assert_mut().add_memory(ty, offset),
845 )
846 }
847
848 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
852 if !self.features.exceptions() {
853 return Err(BinaryReaderError::new(
854 "exceptions proposal not enabled",
855 section.range().start,
856 ));
857 }
858 self.process_module_section(
859 section,
860 "tag",
861 |state, _, count, offset| {
862 check_max(
863 state.module.tags.len(),
864 count,
865 MAX_WASM_TAGS,
866 "tags",
867 offset,
868 )?;
869 state.module.assert_mut().tags.reserve(count as usize);
870 Ok(())
871 },
872 |state, types, ty, offset| state.module.assert_mut().add_tag(ty, types, offset),
873 )
874 }
875
876 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
880 self.process_module_section(
881 section,
882 "global",
883 |state, _, count, offset| {
884 check_max(
885 state.module.globals.len(),
886 count,
887 MAX_WASM_GLOBALS,
888 "globals",
889 offset,
890 )?;
891 state.module.assert_mut().globals.reserve(count as usize);
892 Ok(())
893 },
894 |state, types, global, offset| state.add_global(global, types, offset),
895 )
896 }
897
898 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
902 self.process_module_section(
903 section,
904 "export",
905 |state, _, count, offset| {
906 check_max(
907 state.module.exports.len(),
908 count,
909 MAX_WASM_EXPORTS,
910 "exports",
911 offset,
912 )?;
913 state.module.assert_mut().exports.reserve(count as usize);
914 Ok(())
915 },
916 |state, types, e, offset| {
917 let state = state.module.assert_mut();
918 let ty = state.export_to_entity_type(&e, offset)?;
919 state.add_export(e.name, ty, offset, false , types)
920 },
921 )
922 }
923
924 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
928 let offset = range.start;
929 self.state.ensure_module("start", offset)?;
930 let state = self.module.as_mut().unwrap();
931
932 let ty = state.module.get_func_type(func, &self.types, offset)?;
933 if !ty.params().is_empty() || !ty.results().is_empty() {
934 return Err(BinaryReaderError::new(
935 "invalid start function type",
936 offset,
937 ));
938 }
939
940 Ok(())
941 }
942
943 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
947 self.process_module_section(
948 section,
949 "element",
950 |state, _, count, offset| {
951 check_max(
952 state.module.element_types.len(),
953 count,
954 MAX_WASM_ELEMENT_SEGMENTS,
955 "element segments",
956 offset,
957 )?;
958 state
959 .module
960 .assert_mut()
961 .element_types
962 .reserve(count as usize);
963 Ok(())
964 },
965 |state, types, e, offset| state.add_element_segment(e, types, offset),
966 )
967 }
968
969 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
973 let offset = range.start;
974 self.state.ensure_module("data count", offset)?;
975
976 let state = self.module.as_mut().unwrap();
977
978 if count > MAX_WASM_DATA_SEGMENTS as u32 {
979 return Err(BinaryReaderError::new(
980 "data count section specifies too many data segments",
981 offset,
982 ));
983 }
984
985 state.module.assert_mut().data_count = Some(count);
986 Ok(())
987 }
988
989 pub fn code_section_start(&mut self, range: &Range<usize>) -> Result<()> {
993 let offset = range.start;
994 self.state.ensure_module("code", offset)?;
995
996 let state = self.module.as_mut().unwrap();
997
998 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
1000
1001 Ok(())
1002 }
1003
1004 pub fn code_section_entry(
1018 &mut self,
1019 body: &crate::FunctionBody,
1020 ) -> Result<FuncToValidate<ValidatorResources>> {
1021 let offset = body.range().start;
1022 self.state.ensure_module("code", offset)?;
1023 check_max(
1024 0,
1025 u32::try_from(body.range().len())
1026 .expect("usize already validated to u32 during section-length decoding"),
1027 MAX_WASM_FUNCTION_SIZE,
1028 "function body size",
1029 offset,
1030 )?;
1031
1032 let state = self.module.as_mut().unwrap();
1033
1034 let (index, ty) = state.next_code_index_and_type();
1035 Ok(FuncToValidate {
1036 index,
1037 ty,
1038 resources: ValidatorResources(state.module.arc().clone()),
1039 features: self.features,
1040 })
1041 }
1042
1043 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1047 self.process_module_section(
1048 section,
1049 "data",
1050 |_, _, count, offset| {
1051 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1052 },
1053 |state, types, d, offset| state.add_data_segment(d, types, offset),
1054 )
1055 }
1056
1057 #[cfg(feature = "component-model")]
1061 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1062 self.state.ensure_component("module", range.start)?;
1063
1064 let current = self.components.last_mut().unwrap();
1065 check_max(
1066 current.core_modules.len(),
1067 1,
1068 MAX_WASM_MODULES,
1069 "modules",
1070 range.start,
1071 )?;
1072
1073 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1074 State::Component => {}
1075 _ => unreachable!(),
1076 }
1077
1078 Ok(())
1079 }
1080
1081 #[cfg(feature = "component-model")]
1085 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1086 self.process_component_section(
1087 section,
1088 "core instance",
1089 |components, _, count, offset| {
1090 let current = components.last_mut().unwrap();
1091 check_max(
1092 current.instance_count(),
1093 count,
1094 MAX_WASM_INSTANCES,
1095 "instances",
1096 offset,
1097 )?;
1098 current.core_instances.reserve(count as usize);
1099 Ok(())
1100 },
1101 |components, types, _features, instance, offset| {
1102 components
1103 .last_mut()
1104 .unwrap()
1105 .add_core_instance(instance, types, offset)
1106 },
1107 )
1108 }
1109
1110 #[cfg(feature = "component-model")]
1114 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1115 self.process_component_section(
1116 section,
1117 "core type",
1118 |components, _types, count, offset| {
1119 let current = components.last_mut().unwrap();
1120 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1121 current.core_types.reserve(count as usize);
1122 Ok(())
1123 },
1124 |components, types, _features, ty, offset| {
1125 ComponentState::add_core_type(
1126 components, ty, types, offset, false, )
1128 },
1129 )
1130 }
1131
1132 #[cfg(feature = "component-model")]
1136 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1137 self.state.ensure_component("component", range.start)?;
1138
1139 let current = self.components.last_mut().unwrap();
1140 check_max(
1141 current.components.len(),
1142 1,
1143 MAX_WASM_COMPONENTS,
1144 "components",
1145 range.start,
1146 )?;
1147
1148 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1149 State::Component => {}
1150 _ => unreachable!(),
1151 }
1152
1153 Ok(())
1154 }
1155
1156 #[cfg(feature = "component-model")]
1160 pub fn component_instance_section(
1161 &mut self,
1162 section: &crate::ComponentInstanceSectionReader,
1163 ) -> Result<()> {
1164 self.process_component_section(
1165 section,
1166 "instance",
1167 |components, _, count, offset| {
1168 let current = components.last_mut().unwrap();
1169 check_max(
1170 current.instance_count(),
1171 count,
1172 MAX_WASM_INSTANCES,
1173 "instances",
1174 offset,
1175 )?;
1176 current.instances.reserve(count as usize);
1177 Ok(())
1178 },
1179 |components, types, _features, instance, offset| {
1180 components
1181 .last_mut()
1182 .unwrap()
1183 .add_instance(instance, types, offset)
1184 },
1185 )
1186 }
1187
1188 #[cfg(feature = "component-model")]
1192 pub fn component_alias_section(
1193 &mut self,
1194 section: &crate::ComponentAliasSectionReader<'_>,
1195 ) -> Result<()> {
1196 self.process_component_section(
1197 section,
1198 "alias",
1199 |_, _, _, _| Ok(()), |components, types, _features, alias, offset| -> Result<(), BinaryReaderError> {
1201 ComponentState::add_alias(components, alias, types, offset)
1202 },
1203 )
1204 }
1205
1206 #[cfg(feature = "component-model")]
1210 pub fn component_type_section(
1211 &mut self,
1212 section: &crate::ComponentTypeSectionReader,
1213 ) -> Result<()> {
1214 self.process_component_section(
1215 section,
1216 "type",
1217 |components, _types, count, offset| {
1218 let current = components.last_mut().unwrap();
1219 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1220 current.types.reserve(count as usize);
1221 Ok(())
1222 },
1223 |components, types, _features, ty, offset| {
1224 ComponentState::add_type(
1225 components, ty, types, offset, false, )
1227 },
1228 )
1229 }
1230
1231 #[cfg(feature = "component-model")]
1235 pub fn component_canonical_section(
1236 &mut self,
1237 section: &crate::ComponentCanonicalSectionReader,
1238 ) -> Result<()> {
1239 self.process_component_section(
1240 section,
1241 "function",
1242 |components, _, count, offset| {
1243 let current = components.last_mut().unwrap();
1244 check_max(
1245 current.function_count(),
1246 count,
1247 MAX_WASM_FUNCTIONS,
1248 "functions",
1249 offset,
1250 )?;
1251 current.funcs.reserve(count as usize);
1252 Ok(())
1253 },
1254 |components, types, _features, func, offset| {
1255 let current = components.last_mut().unwrap();
1256 current.canonical_function(func, types, offset)
1257 },
1258 )
1259 }
1260
1261 #[cfg(feature = "component-model")]
1265 pub fn component_start_section(
1266 &mut self,
1267 f: &crate::ComponentStartFunction,
1268 range: &Range<usize>,
1269 ) -> Result<()> {
1270 self.state.ensure_component("start", range.start)?;
1271
1272 self.components.last_mut().unwrap().add_start(
1273 f.func_index,
1274 &f.arguments,
1275 f.results,
1276 &mut self.types,
1277 range.start,
1278 )
1279 }
1280
1281 #[cfg(feature = "component-model")]
1285 pub fn component_import_section(
1286 &mut self,
1287 section: &crate::ComponentImportSectionReader,
1288 ) -> Result<()> {
1289 self.process_component_section(
1290 section,
1291 "import",
1292 |_, _, _, _| Ok(()), |components, types, _features, import, offset| {
1294 components
1295 .last_mut()
1296 .unwrap()
1297 .add_import(import, types, offset)
1298 },
1299 )
1300 }
1301
1302 #[cfg(feature = "component-model")]
1306 pub fn component_export_section(
1307 &mut self,
1308 section: &crate::ComponentExportSectionReader,
1309 ) -> Result<()> {
1310 self.process_component_section(
1311 section,
1312 "export",
1313 |components, _, count, offset| {
1314 let current = components.last_mut().unwrap();
1315 check_max(
1316 current.exports.len(),
1317 count,
1318 MAX_WASM_EXPORTS,
1319 "exports",
1320 offset,
1321 )?;
1322 current.exports.reserve(count as usize);
1323 Ok(())
1324 },
1325 |components, types, _features, export, offset| {
1326 let current = components.last_mut().unwrap();
1327 let ty = current.export_to_entity_type(&export, types, offset)?;
1328 current.add_export(
1329 export.name,
1330 ty,
1331 types,
1332 offset,
1333 false, )
1335 },
1336 )
1337 }
1338
1339 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1343 Err(format_err!(range.start, "malformed section id: {id}"))
1344 }
1345
1346 pub fn end(&mut self, offset: usize) -> Result<Types> {
1350 match mem::replace(&mut self.state, State::End) {
1351 State::Unparsed(_) => Err(BinaryReaderError::new(
1352 "cannot call `end` before a header has been parsed",
1353 offset,
1354 )),
1355 State::End => Err(BinaryReaderError::new(
1356 "cannot call `end` after parsing has completed",
1357 offset,
1358 )),
1359 State::Module => {
1360 let mut state = self.module.take().unwrap();
1361
1362 #[cfg(feature = "component-model")]
1365 if let Some(parent) = self.components.last_mut() {
1366 parent.add_core_module(&state.module, &mut self.types, offset)?;
1367 self.state = State::Component;
1368 }
1369
1370 Ok(Types::from_module(
1371 self.id,
1372 self.types.commit(),
1373 state.module.arc().clone(),
1374 ))
1375 }
1376 #[cfg(feature = "component-model")]
1377 State::Component => {
1378 let mut component = self.components.pop().unwrap();
1379
1380 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1382 bail!(
1383 offset,
1384 "value index {index} was not used as part of an \
1385 instantiation, start function, or export"
1386 );
1387 }
1388
1389 let ty = component.finish(&self.types, offset)?;
1392 if let Some(parent) = self.components.last_mut() {
1393 parent.add_component(ty, &mut self.types)?;
1394 self.state = State::Component;
1395 }
1396
1397 Ok(Types::from_component(
1398 self.id,
1399 self.types.commit(),
1400 component,
1401 ))
1402 }
1403 }
1404 }
1405
1406 fn process_module_section<'a, T>(
1407 &mut self,
1408 section: &SectionLimited<'a, T>,
1409 name: &str,
1410 validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>,
1411 mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>,
1412 ) -> Result<()>
1413 where
1414 T: FromReader<'a>,
1415 {
1416 let offset = section.range().start;
1417 self.state.ensure_module(name, offset)?;
1418
1419 let state = self.module.as_mut().unwrap();
1420
1421 validate_section(state, &mut self.types, section.count(), offset)?;
1422
1423 for item in section.clone().into_iter_with_offsets() {
1424 let (offset, item) = item?;
1425 validate_item(state, &mut self.types, item, offset)?;
1426 }
1427
1428 Ok(())
1429 }
1430
1431 #[cfg(feature = "component-model")]
1432 fn process_component_section<'a, T>(
1433 &mut self,
1434 section: &SectionLimited<'a, T>,
1435 name: &str,
1436 validate_section: impl FnOnce(
1437 &mut Vec<ComponentState>,
1438 &mut TypeAlloc,
1439 u32,
1440 usize,
1441 ) -> Result<()>,
1442 mut validate_item: impl FnMut(
1443 &mut Vec<ComponentState>,
1444 &mut TypeAlloc,
1445 &WasmFeatures,
1446 T,
1447 usize,
1448 ) -> Result<()>,
1449 ) -> Result<()>
1450 where
1451 T: FromReader<'a>,
1452 {
1453 let offset = section.range().start;
1454
1455 self.state.ensure_component(name, offset)?;
1456 validate_section(
1457 &mut self.components,
1458 &mut self.types,
1459 section.count(),
1460 offset,
1461 )?;
1462
1463 for item in section.clone().into_iter_with_offsets() {
1464 let (offset, item) = item?;
1465 validate_item(
1466 &mut self.components,
1467 &mut self.types,
1468 &self.features,
1469 item,
1470 offset,
1471 )?;
1472 }
1473
1474 Ok(())
1475 }
1476}
1477
1478#[cfg(test)]
1479mod tests {
1480 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1481 use anyhow::Result;
1482
1483 #[test]
1484 fn test_module_type_information() -> Result<()> {
1485 let bytes = wat::parse_str(
1486 r#"
1487 (module
1488 (type (func (param i32 i64) (result i32)))
1489 (memory 1 5)
1490 (table 10 funcref)
1491 (global (mut i32) (i32.const 0))
1492 (func (type 0) (i32.const 0))
1493 (tag (param i64 i32))
1494 (elem funcref (ref.func 0))
1495 )
1496 "#,
1497 )?;
1498
1499 let mut validator =
1500 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1501
1502 let types = validator.validate_all(&bytes)?;
1503 let types = types.as_ref();
1504
1505 assert_eq!(types.core_type_count_in_module(), 2);
1506 assert_eq!(types.memory_count(), 1);
1507 assert_eq!(types.table_count(), 1);
1508 assert_eq!(types.global_count(), 1);
1509 assert_eq!(types.function_count(), 1);
1510 assert_eq!(types.tag_count(), 1);
1511 assert_eq!(types.element_count(), 1);
1512 assert_eq!(types.module_count(), 0);
1513 assert_eq!(types.component_count(), 0);
1514 assert_eq!(types.core_instance_count(), 0);
1515 assert_eq!(types.value_count(), 0);
1516
1517 let id = types.core_type_at_in_module(0);
1518 let ty = types[id].unwrap_func();
1519 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1520 assert_eq!(ty.results(), [ValType::I32]);
1521
1522 let id = types.core_type_at_in_module(1);
1523 let ty = types[id].unwrap_func();
1524 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1525 assert_eq!(ty.results(), []);
1526
1527 assert_eq!(
1528 types.memory_at(0),
1529 MemoryType {
1530 memory64: false,
1531 shared: false,
1532 initial: 1,
1533 maximum: Some(5),
1534 page_size_log2: None,
1535 }
1536 );
1537
1538 assert_eq!(
1539 types.table_at(0),
1540 TableType {
1541 initial: 10,
1542 maximum: None,
1543 element_type: RefType::FUNCREF,
1544 table64: false,
1545 shared: false,
1546 }
1547 );
1548
1549 assert_eq!(
1550 types.global_at(0),
1551 GlobalType {
1552 content_type: ValType::I32,
1553 mutable: true,
1554 shared: false
1555 }
1556 );
1557
1558 let id = types.core_function_at(0);
1559 let ty = types[id].unwrap_func();
1560 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1561 assert_eq!(ty.results(), [ValType::I32]);
1562
1563 let ty = types.tag_at(0);
1564 let ty = types[ty].unwrap_func();
1565 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1566 assert_eq!(ty.results(), []);
1567
1568 assert_eq!(types.element_at(0), RefType::FUNCREF);
1569
1570 Ok(())
1571 }
1572
1573 #[test]
1574 fn test_type_id_aliasing() -> Result<()> {
1575 let bytes = wat::parse_str(
1576 r#"
1577 (component
1578 (type $T (list string))
1579 (alias outer 0 $T (type $A1))
1580 (alias outer 0 $T (type $A2))
1581 )
1582 "#,
1583 )?;
1584
1585 let mut validator =
1586 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1587
1588 let types = validator.validate_all(&bytes)?;
1589 let types = types.as_ref();
1590
1591 let t_id = types.component_defined_type_at(0);
1592 let a1_id = types.component_defined_type_at(1);
1593 let a2_id = types.component_defined_type_at(2);
1594
1595 assert!(t_id == a1_id);
1597 assert!(t_id == a2_id);
1598 assert!(a1_id == a2_id);
1599
1600 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1602 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1603
1604 Ok(())
1605 }
1606
1607 #[test]
1608 fn test_type_id_exports() -> Result<()> {
1609 let bytes = wat::parse_str(
1610 r#"
1611 (component
1612 (type $T (list string))
1613 (export $A1 "A1" (type $T))
1614 (export $A2 "A2" (type $T))
1615 )
1616 "#,
1617 )?;
1618
1619 let mut validator =
1620 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1621
1622 let types = validator.validate_all(&bytes)?;
1623 let types = types.as_ref();
1624
1625 let t_id = types.component_defined_type_at(0);
1626 let a1_id = types.component_defined_type_at(1);
1627 let a2_id = types.component_defined_type_at(2);
1628
1629 assert!(t_id != a1_id);
1631 assert!(t_id != a2_id);
1632 assert!(a1_id != a2_id);
1633
1634 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1636 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1637
1638 Ok(())
1639 }
1640
1641 #[test]
1642 fn reset_fresh_validator() {
1643 Validator::new().reset();
1644 }
1645}