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, import, offset| {
772 state.module.assert_mut().add_import(import, types, offset)
773 },
774 )
775 }
776
777 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
781 self.process_module_section(
782 section,
783 "function",
784 |state, _, count, offset| {
785 check_max(
786 state.module.functions.len(),
787 count,
788 MAX_WASM_FUNCTIONS,
789 "functions",
790 offset,
791 )?;
792 state.module.assert_mut().functions.reserve(count as usize);
793 Ok(())
794 },
795 |state, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
796 )
797 }
798
799 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
803 self.process_module_section(
804 section,
805 "table",
806 |state, _, count, offset| {
807 check_max(
808 state.module.tables.len(),
809 count,
810 state.module.max_tables(),
811 "tables",
812 offset,
813 )?;
814 state.module.assert_mut().tables.reserve(count as usize);
815 Ok(())
816 },
817 |state, types, table, offset| state.add_table(table, types, offset),
818 )
819 }
820
821 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
825 self.process_module_section(
826 section,
827 "memory",
828 |state, _, count, offset| {
829 check_max(
830 state.module.memories.len(),
831 count,
832 state.module.max_memories(),
833 "memories",
834 offset,
835 )?;
836 state.module.assert_mut().memories.reserve(count as usize);
837 Ok(())
838 },
839 |state, _, ty, offset| state.module.assert_mut().add_memory(ty, offset),
840 )
841 }
842
843 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
847 if !self.features.exceptions() {
848 return Err(BinaryReaderError::new(
849 "exceptions proposal not enabled",
850 section.range().start,
851 ));
852 }
853 self.process_module_section(
854 section,
855 "tag",
856 |state, _, count, offset| {
857 check_max(
858 state.module.tags.len(),
859 count,
860 MAX_WASM_TAGS,
861 "tags",
862 offset,
863 )?;
864 state.module.assert_mut().tags.reserve(count as usize);
865 Ok(())
866 },
867 |state, types, ty, offset| state.module.assert_mut().add_tag(ty, types, offset),
868 )
869 }
870
871 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
875 self.process_module_section(
876 section,
877 "global",
878 |state, _, count, offset| {
879 check_max(
880 state.module.globals.len(),
881 count,
882 MAX_WASM_GLOBALS,
883 "globals",
884 offset,
885 )?;
886 state.module.assert_mut().globals.reserve(count as usize);
887 Ok(())
888 },
889 |state, types, global, offset| state.add_global(global, types, offset),
890 )
891 }
892
893 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
897 self.process_module_section(
898 section,
899 "export",
900 |state, _, count, offset| {
901 check_max(
902 state.module.exports.len(),
903 count,
904 MAX_WASM_EXPORTS,
905 "exports",
906 offset,
907 )?;
908 state.module.assert_mut().exports.reserve(count as usize);
909 Ok(())
910 },
911 |state, types, e, offset| {
912 let state = state.module.assert_mut();
913 let ty = state.export_to_entity_type(&e, offset)?;
914 state.add_export(e.name, ty, offset, false , types)
915 },
916 )
917 }
918
919 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
923 let offset = range.start;
924 self.state.ensure_module("start", offset)?;
925 let state = self.module.as_mut().unwrap();
926
927 let ty = state.module.get_func_type(func, &self.types, offset)?;
928 if !ty.params().is_empty() || !ty.results().is_empty() {
929 return Err(BinaryReaderError::new(
930 "invalid start function type",
931 offset,
932 ));
933 }
934
935 Ok(())
936 }
937
938 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
942 self.process_module_section(
943 section,
944 "element",
945 |state, _, count, offset| {
946 check_max(
947 state.module.element_types.len(),
948 count,
949 MAX_WASM_ELEMENT_SEGMENTS,
950 "element segments",
951 offset,
952 )?;
953 state
954 .module
955 .assert_mut()
956 .element_types
957 .reserve(count as usize);
958 Ok(())
959 },
960 |state, types, e, offset| state.add_element_segment(e, types, offset),
961 )
962 }
963
964 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
968 let offset = range.start;
969 self.state.ensure_module("data count", offset)?;
970
971 let state = self.module.as_mut().unwrap();
972
973 if count > MAX_WASM_DATA_SEGMENTS as u32 {
974 return Err(BinaryReaderError::new(
975 "data count section specifies too many data segments",
976 offset,
977 ));
978 }
979
980 state.module.assert_mut().data_count = Some(count);
981 Ok(())
982 }
983
984 pub fn code_section_start(&mut self, range: &Range<usize>) -> Result<()> {
988 let offset = range.start;
989 self.state.ensure_module("code", offset)?;
990
991 let state = self.module.as_mut().unwrap();
992
993 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
995
996 Ok(())
997 }
998
999 pub fn code_section_entry(
1013 &mut self,
1014 body: &crate::FunctionBody,
1015 ) -> Result<FuncToValidate<ValidatorResources>> {
1016 let offset = body.range().start;
1017 self.state.ensure_module("code", offset)?;
1018 check_max(
1019 0,
1020 u32::try_from(body.range().len())
1021 .expect("usize already validated to u32 during section-length decoding"),
1022 MAX_WASM_FUNCTION_SIZE,
1023 "function body size",
1024 offset,
1025 )?;
1026
1027 let state = self.module.as_mut().unwrap();
1028
1029 let (index, ty) = state.next_code_index_and_type();
1030 Ok(FuncToValidate {
1031 index,
1032 ty,
1033 resources: ValidatorResources(state.module.arc().clone()),
1034 features: self.features,
1035 })
1036 }
1037
1038 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1042 self.process_module_section(
1043 section,
1044 "data",
1045 |_, _, count, offset| {
1046 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1047 },
1048 |state, types, d, offset| state.add_data_segment(d, types, offset),
1049 )
1050 }
1051
1052 #[cfg(feature = "component-model")]
1056 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1057 self.state.ensure_component("module", range.start)?;
1058
1059 let current = self.components.last_mut().unwrap();
1060 check_max(
1061 current.core_modules.len(),
1062 1,
1063 MAX_WASM_MODULES,
1064 "modules",
1065 range.start,
1066 )?;
1067
1068 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1069 State::Component => {}
1070 _ => unreachable!(),
1071 }
1072
1073 Ok(())
1074 }
1075
1076 #[cfg(feature = "component-model")]
1080 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1081 self.process_component_section(
1082 section,
1083 "core instance",
1084 |components, _, count, offset| {
1085 let current = components.last_mut().unwrap();
1086 check_max(
1087 current.instance_count(),
1088 count,
1089 MAX_WASM_INSTANCES,
1090 "instances",
1091 offset,
1092 )?;
1093 current.core_instances.reserve(count as usize);
1094 Ok(())
1095 },
1096 |components, types, _features, instance, offset| {
1097 components
1098 .last_mut()
1099 .unwrap()
1100 .add_core_instance(instance, types, offset)
1101 },
1102 )
1103 }
1104
1105 #[cfg(feature = "component-model")]
1109 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1110 self.process_component_section(
1111 section,
1112 "core type",
1113 |components, _types, count, offset| {
1114 let current = components.last_mut().unwrap();
1115 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1116 current.core_types.reserve(count as usize);
1117 Ok(())
1118 },
1119 |components, types, _features, ty, offset| {
1120 ComponentState::add_core_type(
1121 components, ty, types, offset, false, )
1123 },
1124 )
1125 }
1126
1127 #[cfg(feature = "component-model")]
1131 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1132 self.state.ensure_component("component", range.start)?;
1133
1134 let current = self.components.last_mut().unwrap();
1135 check_max(
1136 current.components.len(),
1137 1,
1138 MAX_WASM_COMPONENTS,
1139 "components",
1140 range.start,
1141 )?;
1142
1143 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1144 State::Component => {}
1145 _ => unreachable!(),
1146 }
1147
1148 Ok(())
1149 }
1150
1151 #[cfg(feature = "component-model")]
1155 pub fn component_instance_section(
1156 &mut self,
1157 section: &crate::ComponentInstanceSectionReader,
1158 ) -> Result<()> {
1159 self.process_component_section(
1160 section,
1161 "instance",
1162 |components, _, count, offset| {
1163 let current = components.last_mut().unwrap();
1164 check_max(
1165 current.instance_count(),
1166 count,
1167 MAX_WASM_INSTANCES,
1168 "instances",
1169 offset,
1170 )?;
1171 current.instances.reserve(count as usize);
1172 Ok(())
1173 },
1174 |components, types, _features, instance, offset| {
1175 components
1176 .last_mut()
1177 .unwrap()
1178 .add_instance(instance, types, offset)
1179 },
1180 )
1181 }
1182
1183 #[cfg(feature = "component-model")]
1187 pub fn component_alias_section(
1188 &mut self,
1189 section: &crate::ComponentAliasSectionReader<'_>,
1190 ) -> Result<()> {
1191 self.process_component_section(
1192 section,
1193 "alias",
1194 |_, _, _, _| Ok(()), |components, types, _features, alias, offset| -> Result<(), BinaryReaderError> {
1196 ComponentState::add_alias(components, alias, types, offset)
1197 },
1198 )
1199 }
1200
1201 #[cfg(feature = "component-model")]
1205 pub fn component_type_section(
1206 &mut self,
1207 section: &crate::ComponentTypeSectionReader,
1208 ) -> Result<()> {
1209 self.process_component_section(
1210 section,
1211 "type",
1212 |components, _types, count, offset| {
1213 let current = components.last_mut().unwrap();
1214 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1215 current.types.reserve(count as usize);
1216 Ok(())
1217 },
1218 |components, types, _features, ty, offset| {
1219 ComponentState::add_type(
1220 components, ty, types, offset, false, )
1222 },
1223 )
1224 }
1225
1226 #[cfg(feature = "component-model")]
1230 pub fn component_canonical_section(
1231 &mut self,
1232 section: &crate::ComponentCanonicalSectionReader,
1233 ) -> Result<()> {
1234 self.process_component_section(
1235 section,
1236 "function",
1237 |components, _, count, offset| {
1238 let current = components.last_mut().unwrap();
1239 check_max(
1240 current.function_count(),
1241 count,
1242 MAX_WASM_FUNCTIONS,
1243 "functions",
1244 offset,
1245 )?;
1246 current.funcs.reserve(count as usize);
1247 Ok(())
1248 },
1249 |components, types, _features, func, offset| {
1250 let current = components.last_mut().unwrap();
1251 current.canonical_function(func, types, offset)
1252 },
1253 )
1254 }
1255
1256 #[cfg(feature = "component-model")]
1260 pub fn component_start_section(
1261 &mut self,
1262 f: &crate::ComponentStartFunction,
1263 range: &Range<usize>,
1264 ) -> Result<()> {
1265 self.state.ensure_component("start", range.start)?;
1266
1267 self.components.last_mut().unwrap().add_start(
1268 f.func_index,
1269 &f.arguments,
1270 f.results,
1271 &mut self.types,
1272 range.start,
1273 )
1274 }
1275
1276 #[cfg(feature = "component-model")]
1280 pub fn component_import_section(
1281 &mut self,
1282 section: &crate::ComponentImportSectionReader,
1283 ) -> Result<()> {
1284 self.process_component_section(
1285 section,
1286 "import",
1287 |_, _, _, _| Ok(()), |components, types, _features, import, offset| {
1289 components
1290 .last_mut()
1291 .unwrap()
1292 .add_import(import, types, offset)
1293 },
1294 )
1295 }
1296
1297 #[cfg(feature = "component-model")]
1301 pub fn component_export_section(
1302 &mut self,
1303 section: &crate::ComponentExportSectionReader,
1304 ) -> Result<()> {
1305 self.process_component_section(
1306 section,
1307 "export",
1308 |components, _, count, offset| {
1309 let current = components.last_mut().unwrap();
1310 check_max(
1311 current.exports.len(),
1312 count,
1313 MAX_WASM_EXPORTS,
1314 "exports",
1315 offset,
1316 )?;
1317 current.exports.reserve(count as usize);
1318 Ok(())
1319 },
1320 |components, types, _features, export, offset| {
1321 let current = components.last_mut().unwrap();
1322 let ty = current.export_to_entity_type(&export, types, offset)?;
1323 current.add_export(
1324 export.name,
1325 ty,
1326 types,
1327 offset,
1328 false, )
1330 },
1331 )
1332 }
1333
1334 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1338 Err(format_err!(range.start, "malformed section id: {id}"))
1339 }
1340
1341 pub fn end(&mut self, offset: usize) -> Result<Types> {
1345 match mem::replace(&mut self.state, State::End) {
1346 State::Unparsed(_) => Err(BinaryReaderError::new(
1347 "cannot call `end` before a header has been parsed",
1348 offset,
1349 )),
1350 State::End => Err(BinaryReaderError::new(
1351 "cannot call `end` after parsing has completed",
1352 offset,
1353 )),
1354 State::Module => {
1355 let mut state = self.module.take().unwrap();
1356
1357 #[cfg(feature = "component-model")]
1360 if let Some(parent) = self.components.last_mut() {
1361 parent.add_core_module(&state.module, &mut self.types, offset)?;
1362 self.state = State::Component;
1363 }
1364
1365 Ok(Types::from_module(
1366 self.id,
1367 self.types.commit(),
1368 state.module.arc().clone(),
1369 ))
1370 }
1371 #[cfg(feature = "component-model")]
1372 State::Component => {
1373 let mut component = self.components.pop().unwrap();
1374
1375 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1377 bail!(
1378 offset,
1379 "value index {index} was not used as part of an \
1380 instantiation, start function, or export"
1381 );
1382 }
1383
1384 let ty = component.finish(&self.types, offset)?;
1387 if let Some(parent) = self.components.last_mut() {
1388 parent.add_component(ty, &mut self.types)?;
1389 self.state = State::Component;
1390 }
1391
1392 Ok(Types::from_component(
1393 self.id,
1394 self.types.commit(),
1395 component,
1396 ))
1397 }
1398 }
1399 }
1400
1401 fn process_module_section<'a, T>(
1402 &mut self,
1403 section: &SectionLimited<'a, T>,
1404 name: &str,
1405 validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>,
1406 mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>,
1407 ) -> Result<()>
1408 where
1409 T: FromReader<'a>,
1410 {
1411 let offset = section.range().start;
1412 self.state.ensure_module(name, offset)?;
1413
1414 let state = self.module.as_mut().unwrap();
1415
1416 validate_section(state, &mut self.types, section.count(), offset)?;
1417
1418 for item in section.clone().into_iter_with_offsets() {
1419 let (offset, item) = item?;
1420 validate_item(state, &mut self.types, item, offset)?;
1421 }
1422
1423 Ok(())
1424 }
1425
1426 #[cfg(feature = "component-model")]
1427 fn process_component_section<'a, T>(
1428 &mut self,
1429 section: &SectionLimited<'a, T>,
1430 name: &str,
1431 validate_section: impl FnOnce(
1432 &mut Vec<ComponentState>,
1433 &mut TypeAlloc,
1434 u32,
1435 usize,
1436 ) -> Result<()>,
1437 mut validate_item: impl FnMut(
1438 &mut Vec<ComponentState>,
1439 &mut TypeAlloc,
1440 &WasmFeatures,
1441 T,
1442 usize,
1443 ) -> Result<()>,
1444 ) -> Result<()>
1445 where
1446 T: FromReader<'a>,
1447 {
1448 let offset = section.range().start;
1449
1450 self.state.ensure_component(name, offset)?;
1451 validate_section(
1452 &mut self.components,
1453 &mut self.types,
1454 section.count(),
1455 offset,
1456 )?;
1457
1458 for item in section.clone().into_iter_with_offsets() {
1459 let (offset, item) = item?;
1460 validate_item(
1461 &mut self.components,
1462 &mut self.types,
1463 &self.features,
1464 item,
1465 offset,
1466 )?;
1467 }
1468
1469 Ok(())
1470 }
1471}
1472
1473#[cfg(test)]
1474mod tests {
1475 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1476 use anyhow::Result;
1477
1478 #[test]
1479 fn test_module_type_information() -> Result<()> {
1480 let bytes = wat::parse_str(
1481 r#"
1482 (module
1483 (type (func (param i32 i64) (result i32)))
1484 (memory 1 5)
1485 (table 10 funcref)
1486 (global (mut i32) (i32.const 0))
1487 (func (type 0) (i32.const 0))
1488 (tag (param i64 i32))
1489 (elem funcref (ref.func 0))
1490 )
1491 "#,
1492 )?;
1493
1494 let mut validator =
1495 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1496
1497 let types = validator.validate_all(&bytes)?;
1498 let types = types.as_ref();
1499
1500 assert_eq!(types.core_type_count_in_module(), 2);
1501 assert_eq!(types.memory_count(), 1);
1502 assert_eq!(types.table_count(), 1);
1503 assert_eq!(types.global_count(), 1);
1504 assert_eq!(types.function_count(), 1);
1505 assert_eq!(types.tag_count(), 1);
1506 assert_eq!(types.element_count(), 1);
1507 assert_eq!(types.module_count(), 0);
1508 assert_eq!(types.component_count(), 0);
1509 assert_eq!(types.core_instance_count(), 0);
1510 assert_eq!(types.value_count(), 0);
1511
1512 let id = types.core_type_at_in_module(0);
1513 let ty = types[id].unwrap_func();
1514 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1515 assert_eq!(ty.results(), [ValType::I32]);
1516
1517 let id = types.core_type_at_in_module(1);
1518 let ty = types[id].unwrap_func();
1519 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1520 assert_eq!(ty.results(), []);
1521
1522 assert_eq!(
1523 types.memory_at(0),
1524 MemoryType {
1525 memory64: false,
1526 shared: false,
1527 initial: 1,
1528 maximum: Some(5),
1529 page_size_log2: None,
1530 }
1531 );
1532
1533 assert_eq!(
1534 types.table_at(0),
1535 TableType {
1536 initial: 10,
1537 maximum: None,
1538 element_type: RefType::FUNCREF,
1539 table64: false,
1540 shared: false,
1541 }
1542 );
1543
1544 assert_eq!(
1545 types.global_at(0),
1546 GlobalType {
1547 content_type: ValType::I32,
1548 mutable: true,
1549 shared: false
1550 }
1551 );
1552
1553 let id = types.core_function_at(0);
1554 let ty = types[id].unwrap_func();
1555 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1556 assert_eq!(ty.results(), [ValType::I32]);
1557
1558 let ty = types.tag_at(0);
1559 let ty = types[ty].unwrap_func();
1560 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1561 assert_eq!(ty.results(), []);
1562
1563 assert_eq!(types.element_at(0), RefType::FUNCREF);
1564
1565 Ok(())
1566 }
1567
1568 #[test]
1569 fn test_type_id_aliasing() -> Result<()> {
1570 let bytes = wat::parse_str(
1571 r#"
1572 (component
1573 (type $T (list string))
1574 (alias outer 0 $T (type $A1))
1575 (alias outer 0 $T (type $A2))
1576 )
1577 "#,
1578 )?;
1579
1580 let mut validator =
1581 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1582
1583 let types = validator.validate_all(&bytes)?;
1584 let types = types.as_ref();
1585
1586 let t_id = types.component_defined_type_at(0);
1587 let a1_id = types.component_defined_type_at(1);
1588 let a2_id = types.component_defined_type_at(2);
1589
1590 assert!(t_id == a1_id);
1592 assert!(t_id == a2_id);
1593 assert!(a1_id == a2_id);
1594
1595 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1597 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1598
1599 Ok(())
1600 }
1601
1602 #[test]
1603 fn test_type_id_exports() -> Result<()> {
1604 let bytes = wat::parse_str(
1605 r#"
1606 (component
1607 (type $T (list string))
1608 (export $A1 "A1" (type $T))
1609 (export $A2 "A2" (type $T))
1610 )
1611 "#,
1612 )?;
1613
1614 let mut validator =
1615 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1616
1617 let types = validator.validate_all(&bytes)?;
1618 let types = types.as_ref();
1619
1620 let t_id = types.component_defined_type_at(0);
1621 let a1_id = types.component_defined_type_at(1);
1622 let a2_id = types.component_defined_type_at(2);
1623
1624 assert!(t_id != a1_id);
1626 assert!(t_id != a2_id);
1627 assert!(a1_id != a2_id);
1628
1629 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1631 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1632
1633 Ok(())
1634 }
1635
1636 #[test]
1637 fn reset_fresh_validator() {
1638 Validator::new().reset();
1639 }
1640}