1use crate::prelude::*;
17use crate::{
18 limits::*, AbstractHeapType, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType,
19 Parser, Payload, RefType, Result, SectionLimited, ValType, WasmFeatures, WASM_MODULE_VERSION,
20};
21use ::core::mem;
22use ::core::ops::Range;
23use ::core::sync::atomic::{AtomicUsize, Ordering};
24use alloc::sync::Arc;
25
26pub fn validate(bytes: &[u8]) -> Result<Types> {
41 Validator::new().validate_all(bytes)
42}
43
44#[test]
45fn test_validate() {
46 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0]).is_ok());
47 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0]).is_err());
48}
49
50#[cfg(feature = "component-model")]
51mod component;
52#[cfg(feature = "component-model")]
53pub mod component_types;
54mod core;
55mod func;
56#[cfg(feature = "component-model")]
57pub mod names;
58mod operators;
59pub mod types;
60
61#[cfg(feature = "component-model")]
62use self::component::*;
63pub use self::core::ValidatorResources;
64use self::core::*;
65use self::types::{TypeAlloc, Types, TypesRef};
66pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
67pub use operators::Frame;
68
69fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
70 if max
71 .checked_sub(cur_len)
72 .and_then(|amt| amt.checked_sub(amt_added as usize))
73 .is_none()
74 {
75 if max == 1 {
76 bail!(offset, "multiple {desc}");
77 }
78
79 bail!(offset, "{desc} count exceeds limit of {max}");
80 }
81
82 Ok(())
83}
84
85fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
86 match a.checked_add(b) {
87 Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
88 _ => Err(format_err!(
89 offset,
90 "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
91 )),
92 }
93}
94
95#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
102pub struct ValidatorId(usize);
103
104impl Default for ValidatorId {
105 #[inline]
106 fn default() -> Self {
107 static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
108 ValidatorId(ID_COUNTER.fetch_add(1, Ordering::AcqRel))
109 }
110}
111
112#[derive(Default)]
138pub struct Validator {
139 id: ValidatorId,
140
141 state: State,
143
144 types: TypeAlloc,
146
147 module: Option<ModuleState>,
149
150 #[cfg(feature = "component-model")]
153 components: Vec<ComponentState>,
154
155 features: WasmFeatures,
158}
159
160#[derive(Debug, Clone, Copy, Eq, PartialEq)]
161enum State {
162 Unparsed(Option<Encoding>),
166 Module,
170 #[cfg(feature = "component-model")]
175 Component,
176 End,
178}
179
180impl State {
181 fn ensure_parsable(&self, offset: usize) -> Result<()> {
182 match self {
183 Self::Module => Ok(()),
184 #[cfg(feature = "component-model")]
185 Self::Component => Ok(()),
186 Self::Unparsed(_) => Err(BinaryReaderError::new(
187 "unexpected section before header was parsed",
188 offset,
189 )),
190 Self::End => Err(BinaryReaderError::new(
191 "unexpected section after parsing has completed",
192 offset,
193 )),
194 }
195 }
196
197 fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
198 self.ensure_parsable(offset)?;
199 let _ = section;
200
201 match self {
202 Self::Module => Ok(()),
203 #[cfg(feature = "component-model")]
204 Self::Component => Err(format_err!(
205 offset,
206 "unexpected module {section} section while parsing a component",
207 )),
208 _ => unreachable!(),
209 }
210 }
211
212 #[cfg(feature = "component-model")]
213 fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
214 self.ensure_parsable(offset)?;
215
216 match self {
217 Self::Component => Ok(()),
218 Self::Module => Err(format_err!(
219 offset,
220 "unexpected component {section} section while parsing a module",
221 )),
222 _ => unreachable!(),
223 }
224 }
225}
226
227impl Default for State {
228 fn default() -> Self {
229 Self::Unparsed(None)
230 }
231}
232
233impl WasmFeatures {
234 pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
239 match ty {
240 ValType::I32 | ValType::I64 => Ok(()),
241 ValType::F32 | ValType::F64 => {
242 if self.floats() {
243 Ok(())
244 } else {
245 Err("floating-point support is disabled")
246 }
247 }
248 ValType::Ref(r) => self.check_ref_type(r),
249 ValType::V128 => {
250 if self.simd() {
251 Ok(())
252 } else {
253 Err("SIMD support is not enabled")
254 }
255 }
256 }
257 }
258
259 pub(crate) fn check_ref_type(&self, r: RefType) -> Result<(), &'static str> {
260 if !self.reference_types() {
261 return Err("reference types support is not enabled");
262 }
263 match r.heap_type() {
264 HeapType::Concrete(_) => {
265 if self.function_references() || self.gc() {
274 Ok(())
275 } else {
276 Err("function references required for index reference types")
277 }
278 }
279 HeapType::Abstract { shared, ty } => {
280 use AbstractHeapType::*;
281 if shared && !self.shared_everything_threads() {
282 return Err(
283 "shared reference types require the shared-everything-threads proposal",
284 );
285 }
286
287 if !self.gc_types() && ty != Func && ty != Exn {
290 return Err("gc types are disallowed but found type which requires gc");
291 }
292
293 match (ty, r.is_nullable()) {
294 (Func, true) | (Extern, true) => Ok(()),
296
297 (Func | Extern, false) => {
300 if self.function_references() {
301 Ok(())
302 } else {
303 Err("function references required for non-nullable types")
304 }
305 }
306
307 (Any | None | Eq | Struct | Array | I31 | NoExtern | NoFunc, _) => {
309 if self.gc() {
310 Ok(())
311 } else {
312 Err("heap types not supported without the gc feature")
313 }
314 }
315
316 (Exn | NoExn, _) => {
318 if self.exceptions() {
319 Ok(())
320 } else {
321 Err("exception refs not supported without the exception handling feature")
322 }
323 }
324
325 (Cont | NoCont, _) => {
327 if self.stack_switching() {
328 Ok(())
329 } else {
330 Err("continuation refs not supported without the stack switching feature")
331 }
332 }
333 }
334 }
335 }
336 }
337}
338
339#[allow(clippy::large_enum_variant)]
341pub enum ValidPayload<'a> {
342 Ok,
344 Parser(Parser),
349 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
351 End(Types),
354}
355
356impl Validator {
357 pub fn new() -> Validator {
364 Validator::default()
365 }
366
367 pub fn new_with_features(features: WasmFeatures) -> Validator {
375 let mut ret = Validator::new();
376 ret.features = features;
377 ret
378 }
379
380 pub fn features(&self) -> &WasmFeatures {
382 &self.features
383 }
384
385 pub fn reset(&mut self) {
438 let Validator {
439 id: _,
442
443 types: _,
445
446 features: _,
453
454 state,
455 module,
456 #[cfg(feature = "component-model")]
457 components,
458 } = self;
459
460 assert!(
461 matches!(state, State::End),
462 "cannot reset a validator that did not successfully complete validation"
463 );
464 assert!(module.is_none());
465 #[cfg(feature = "component-model")]
466 assert!(components.is_empty());
467
468 *state = State::default();
469 }
470
471 pub fn id(&self) -> ValidatorId {
478 self.id
479 }
480
481 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
490 let mut functions_to_validate = Vec::new();
491 let mut last_types = None;
492 let mut parser = Parser::new(0);
493 let _ = &mut parser;
494 #[cfg(feature = "features")]
495 parser.set_features(self.features);
496 for payload in parser.parse_all(bytes) {
497 match self.payload(&payload?)? {
498 ValidPayload::Func(a, b) => {
499 functions_to_validate.push((a, b));
500 }
501 ValidPayload::End(types) => {
502 last_types = Some(types);
504 }
505 _ => {}
506 }
507 }
508
509 let mut allocs = FuncValidatorAllocations::default();
510 for (func, body) in functions_to_validate {
511 let mut validator = func.into_validator(allocs);
512 validator.validate(&body)?;
513 allocs = validator.into_allocations();
514 }
515
516 Ok(last_types.unwrap())
517 }
518
519 pub fn types(&self, mut level: usize) -> Option<TypesRef> {
529 if let Some(module) = &self.module {
530 if level == 0 {
531 return Some(TypesRef::from_module(self.id, &self.types, &module.module));
532 } else {
533 level -= 1;
534 let _ = level;
535 }
536 }
537
538 #[cfg(feature = "component-model")]
539 return self
540 .components
541 .iter()
542 .nth_back(level)
543 .map(|component| TypesRef::from_component(self.id, &self.types, component));
544 #[cfg(not(feature = "component-model"))]
545 return None;
546 }
547
548 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
562 use crate::Payload::*;
563 match payload {
564 Version {
565 num,
566 encoding,
567 range,
568 } => self.version(*num, *encoding, range)?,
569
570 TypeSection(s) => self.type_section(s)?,
572 ImportSection(s) => self.import_section(s)?,
573 FunctionSection(s) => self.function_section(s)?,
574 TableSection(s) => self.table_section(s)?,
575 MemorySection(s) => self.memory_section(s)?,
576 TagSection(s) => self.tag_section(s)?,
577 GlobalSection(s) => self.global_section(s)?,
578 ExportSection(s) => self.export_section(s)?,
579 StartSection { func, range } => self.start_section(*func, range)?,
580 ElementSection(s) => self.element_section(s)?,
581 DataCountSection { count, range } => self.data_count_section(*count, range)?,
582 CodeSectionStart {
583 count,
584 range,
585 size: _,
586 } => self.code_section_start(*count, range)?,
587 CodeSectionEntry(body) => {
588 let func_validator = self.code_section_entry(body)?;
589 return Ok(ValidPayload::Func(func_validator, body.clone()));
590 }
591 DataSection(s) => self.data_section(s)?,
592
593 #[cfg(feature = "component-model")]
595 ModuleSection {
596 parser,
597 unchecked_range: range,
598 ..
599 } => {
600 self.module_section(range)?;
601 return Ok(ValidPayload::Parser(parser.clone()));
602 }
603 #[cfg(feature = "component-model")]
604 InstanceSection(s) => self.instance_section(s)?,
605 #[cfg(feature = "component-model")]
606 CoreTypeSection(s) => self.core_type_section(s)?,
607 #[cfg(feature = "component-model")]
608 ComponentSection {
609 parser,
610 unchecked_range: range,
611 ..
612 } => {
613 self.component_section(range)?;
614 return Ok(ValidPayload::Parser(parser.clone()));
615 }
616 #[cfg(feature = "component-model")]
617 ComponentInstanceSection(s) => self.component_instance_section(s)?,
618 #[cfg(feature = "component-model")]
619 ComponentAliasSection(s) => self.component_alias_section(s)?,
620 #[cfg(feature = "component-model")]
621 ComponentTypeSection(s) => self.component_type_section(s)?,
622 #[cfg(feature = "component-model")]
623 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
624 #[cfg(feature = "component-model")]
625 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
626 #[cfg(feature = "component-model")]
627 ComponentImportSection(s) => self.component_import_section(s)?,
628 #[cfg(feature = "component-model")]
629 ComponentExportSection(s) => self.component_export_section(s)?,
630
631 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
632
633 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
635 }
636 Ok(ValidPayload::Ok)
637 }
638
639 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
641 match &self.state {
642 State::Unparsed(expected) => {
643 if let Some(expected) = expected {
644 if *expected != encoding {
645 bail!(
646 range.start,
647 "expected a version header for a {}",
648 match expected {
649 Encoding::Module => "module",
650 Encoding::Component => "component",
651 }
652 );
653 }
654 }
655 }
656 _ => {
657 return Err(BinaryReaderError::new(
658 "wasm version header out of order",
659 range.start,
660 ))
661 }
662 }
663
664 self.state = match encoding {
665 Encoding::Module => {
666 if num == WASM_MODULE_VERSION {
667 assert!(self.module.is_none());
668 self.module = Some(ModuleState::default());
669 State::Module
670 } else {
671 bail!(range.start, "unknown binary version: {num:#x}");
672 }
673 }
674 Encoding::Component => {
675 if !self.features.component_model() {
676 bail!(
677 range.start,
678 "unknown binary version and encoding combination: {num:#x} and 0x1, \
679 note: encoded as a component but the WebAssembly component model feature \
680 is not enabled - enable the feature to allow component validation",
681 );
682 }
683 #[cfg(feature = "component-model")]
684 if num == crate::WASM_COMPONENT_VERSION {
685 self.components
686 .push(ComponentState::new(ComponentKind::Component));
687 State::Component
688 } else if num < crate::WASM_COMPONENT_VERSION {
689 bail!(range.start, "unsupported component version: {num:#x}");
690 } else {
691 bail!(range.start, "unknown component version: {num:#x}");
692 }
693 #[cfg(not(feature = "component-model"))]
694 bail!(
695 range.start,
696 "component model validation support disabled \
697 at compile time"
698 );
699 }
700 };
701
702 Ok(())
703 }
704
705 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
707 self.process_module_section(
708 Order::Type,
709 section,
710 "type",
711 |state, _, _types, count, offset| {
712 check_max(
713 state.module.types.len(),
714 count,
715 MAX_WASM_TYPES,
716 "types",
717 offset,
718 )?;
719 state.module.assert_mut().types.reserve(count as usize);
720 Ok(())
721 },
722 |state, features, types, rec_group, offset| {
723 state
724 .module
725 .assert_mut()
726 .add_types(rec_group, features, types, offset, true)?;
727 Ok(())
728 },
729 )
730 }
731
732 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
736 self.process_module_section(
737 Order::Import,
738 section,
739 "import",
740 |state, _, _, count, offset| {
741 check_max(
742 state.module.imports.len(),
743 count,
744 MAX_WASM_IMPORTS,
745 "imports",
746 offset,
747 )?;
748 state.module.assert_mut().imports.reserve(count as usize);
749 Ok(())
750 },
751 |state, features, types, import, offset| {
752 state
753 .module
754 .assert_mut()
755 .add_import(import, features, types, offset)
756 },
757 )
758 }
759
760 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
764 self.process_module_section(
765 Order::Function,
766 section,
767 "function",
768 |state, _, _, count, offset| {
769 check_max(
770 state.module.functions.len(),
771 count,
772 MAX_WASM_FUNCTIONS,
773 "functions",
774 offset,
775 )?;
776 state.module.assert_mut().functions.reserve(count as usize);
777 debug_assert!(state.expected_code_bodies.is_none());
778 state.expected_code_bodies = Some(count);
779 Ok(())
780 },
781 |state, _, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
782 )
783 }
784
785 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
789 let features = self.features;
790 self.process_module_section(
791 Order::Table,
792 section,
793 "table",
794 |state, _, _, count, offset| {
795 check_max(
796 state.module.tables.len(),
797 count,
798 state.module.max_tables(&features),
799 "tables",
800 offset,
801 )?;
802 state.module.assert_mut().tables.reserve(count as usize);
803 Ok(())
804 },
805 |state, features, types, table, offset| state.add_table(table, features, types, offset),
806 )
807 }
808
809 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
813 self.process_module_section(
814 Order::Memory,
815 section,
816 "memory",
817 |state, features, _, count, offset| {
818 check_max(
819 state.module.memories.len(),
820 count,
821 state.module.max_memories(features),
822 "memories",
823 offset,
824 )?;
825 state.module.assert_mut().memories.reserve(count as usize);
826 Ok(())
827 },
828 |state, features, _, ty, offset| {
829 state.module.assert_mut().add_memory(ty, features, offset)
830 },
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
845 self.process_module_section(
846 Order::Tag,
847 section,
848 "tag",
849 |state, _, _, count, offset| {
850 check_max(
851 state.module.tags.len(),
852 count,
853 MAX_WASM_TAGS,
854 "tags",
855 offset,
856 )?;
857 state.module.assert_mut().tags.reserve(count as usize);
858 Ok(())
859 },
860 |state, features, types, ty, offset| {
861 state
862 .module
863 .assert_mut()
864 .add_tag(ty, features, types, offset)
865 },
866 )
867 }
868
869 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
873 self.process_module_section(
874 Order::Global,
875 section,
876 "global",
877 |state, _, _, count, offset| {
878 check_max(
879 state.module.globals.len(),
880 count,
881 MAX_WASM_GLOBALS,
882 "globals",
883 offset,
884 )?;
885 state.module.assert_mut().globals.reserve(count as usize);
886 Ok(())
887 },
888 |state, features, types, global, offset| {
889 state.add_global(global, features, types, offset)
890 },
891 )
892 }
893
894 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
898 self.process_module_section(
899 Order::Export,
900 section,
901 "export",
902 |state, _, _, count, offset| {
903 check_max(
904 state.module.exports.len(),
905 count,
906 MAX_WASM_EXPORTS,
907 "exports",
908 offset,
909 )?;
910 state.module.assert_mut().exports.reserve(count as usize);
911 Ok(())
912 },
913 |state, features, types, e, offset| {
914 let state = state.module.assert_mut();
915 let ty = state.export_to_entity_type(&e, offset)?;
916 state.add_export(
917 e.name, ty, features, offset, false, types,
919 )
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 state.update_order(Order::Start, offset)?;
932
933 let ty = state.module.get_func_type(func, &self.types, offset)?;
934 if !ty.params().is_empty() || !ty.results().is_empty() {
935 return Err(BinaryReaderError::new(
936 "invalid start function type",
937 offset,
938 ));
939 }
940
941 Ok(())
942 }
943
944 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
948 self.process_module_section(
949 Order::Element,
950 section,
951 "element",
952 |state, _, _, count, offset| {
953 check_max(
954 state.module.element_types.len(),
955 count,
956 MAX_WASM_ELEMENT_SEGMENTS,
957 "element segments",
958 offset,
959 )?;
960 state
961 .module
962 .assert_mut()
963 .element_types
964 .reserve(count as usize);
965 Ok(())
966 },
967 |state, features, types, e, offset| {
968 state.add_element_segment(e, features, types, offset)
969 },
970 )
971 }
972
973 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
977 let offset = range.start;
978 self.state.ensure_module("data count", offset)?;
979
980 let state = self.module.as_mut().unwrap();
981 state.update_order(Order::DataCount, offset)?;
982
983 if count > MAX_WASM_DATA_SEGMENTS as u32 {
984 return Err(BinaryReaderError::new(
985 "data count section specifies too many data segments",
986 offset,
987 ));
988 }
989
990 state.module.assert_mut().data_count = Some(count);
991 Ok(())
992 }
993
994 pub fn code_section_start(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
998 let offset = range.start;
999 self.state.ensure_module("code", offset)?;
1000
1001 let state = self.module.as_mut().unwrap();
1002 state.update_order(Order::Code, offset)?;
1003
1004 match state.expected_code_bodies.take() {
1005 Some(n) if n == count => {}
1006 Some(_) => {
1007 return Err(BinaryReaderError::new(
1008 "function and code section have inconsistent lengths",
1009 offset,
1010 ));
1011 }
1012 None if count == 0 => {}
1015 None => {
1016 return Err(BinaryReaderError::new(
1017 "code section without function section",
1018 offset,
1019 ))
1020 }
1021 }
1022
1023 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
1025
1026 Ok(())
1027 }
1028
1029 pub fn code_section_entry(
1043 &mut self,
1044 body: &crate::FunctionBody,
1045 ) -> Result<FuncToValidate<ValidatorResources>> {
1046 let offset = body.range().start;
1047 self.state.ensure_module("code", offset)?;
1048
1049 let state = self.module.as_mut().unwrap();
1050
1051 let (index, ty) = state.next_code_index_and_type(offset)?;
1052 Ok(FuncToValidate {
1053 index,
1054 ty,
1055 resources: ValidatorResources(state.module.arc().clone()),
1056 features: self.features,
1057 })
1058 }
1059
1060 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
1064 self.process_module_section(
1065 Order::Data,
1066 section,
1067 "data",
1068 |state, _, _, count, offset| {
1069 state.data_segment_count = count;
1070 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
1071 },
1072 |state, features, types, d, offset| state.add_data_segment(d, features, types, offset),
1073 )
1074 }
1075
1076 #[cfg(feature = "component-model")]
1080 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1081 self.state.ensure_component("module", range.start)?;
1082
1083 let current = self.components.last_mut().unwrap();
1084 check_max(
1085 current.core_modules.len(),
1086 1,
1087 MAX_WASM_MODULES,
1088 "modules",
1089 range.start,
1090 )?;
1091
1092 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1093 State::Component => {}
1094 _ => unreachable!(),
1095 }
1096
1097 Ok(())
1098 }
1099
1100 #[cfg(feature = "component-model")]
1104 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1105 self.process_component_section(
1106 section,
1107 "core instance",
1108 |components, _, count, offset| {
1109 let current = components.last_mut().unwrap();
1110 check_max(
1111 current.instance_count(),
1112 count,
1113 MAX_WASM_INSTANCES,
1114 "instances",
1115 offset,
1116 )?;
1117 current.core_instances.reserve(count as usize);
1118 Ok(())
1119 },
1120 |components, types, features, instance, offset| {
1121 components
1122 .last_mut()
1123 .unwrap()
1124 .add_core_instance(instance, features, types, offset)
1125 },
1126 )
1127 }
1128
1129 #[cfg(feature = "component-model")]
1133 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1134 self.process_component_section(
1135 section,
1136 "core type",
1137 |components, _types, count, offset| {
1138 let current = components.last_mut().unwrap();
1139 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1140 current.core_types.reserve(count as usize);
1141 Ok(())
1142 },
1143 |components, types, features, ty, offset| {
1144 ComponentState::add_core_type(
1145 components, ty, features, types, offset, false, )
1147 },
1148 )
1149 }
1150
1151 #[cfg(feature = "component-model")]
1155 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1156 self.state.ensure_component("component", range.start)?;
1157
1158 let current = self.components.last_mut().unwrap();
1159 check_max(
1160 current.components.len(),
1161 1,
1162 MAX_WASM_COMPONENTS,
1163 "components",
1164 range.start,
1165 )?;
1166
1167 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1168 State::Component => {}
1169 _ => unreachable!(),
1170 }
1171
1172 Ok(())
1173 }
1174
1175 #[cfg(feature = "component-model")]
1179 pub fn component_instance_section(
1180 &mut self,
1181 section: &crate::ComponentInstanceSectionReader,
1182 ) -> Result<()> {
1183 self.process_component_section(
1184 section,
1185 "instance",
1186 |components, _, count, offset| {
1187 let current = components.last_mut().unwrap();
1188 check_max(
1189 current.instance_count(),
1190 count,
1191 MAX_WASM_INSTANCES,
1192 "instances",
1193 offset,
1194 )?;
1195 current.instances.reserve(count as usize);
1196 Ok(())
1197 },
1198 |components, types, features, instance, offset| {
1199 components
1200 .last_mut()
1201 .unwrap()
1202 .add_instance(instance, features, types, offset)
1203 },
1204 )
1205 }
1206
1207 #[cfg(feature = "component-model")]
1211 pub fn component_alias_section(
1212 &mut self,
1213 section: &crate::ComponentAliasSectionReader<'_>,
1214 ) -> Result<()> {
1215 self.process_component_section(
1216 section,
1217 "alias",
1218 |_, _, _, _| Ok(()), |components, types, features, alias, offset| -> Result<(), BinaryReaderError> {
1220 ComponentState::add_alias(components, alias, features, types, offset)
1221 },
1222 )
1223 }
1224
1225 #[cfg(feature = "component-model")]
1229 pub fn component_type_section(
1230 &mut self,
1231 section: &crate::ComponentTypeSectionReader,
1232 ) -> Result<()> {
1233 self.process_component_section(
1234 section,
1235 "type",
1236 |components, _types, count, offset| {
1237 let current = components.last_mut().unwrap();
1238 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1239 current.types.reserve(count as usize);
1240 Ok(())
1241 },
1242 |components, types, features, ty, offset| {
1243 ComponentState::add_type(
1244 components, ty, features, types, offset, false, )
1246 },
1247 )
1248 }
1249
1250 #[cfg(feature = "component-model")]
1254 pub fn component_canonical_section(
1255 &mut self,
1256 section: &crate::ComponentCanonicalSectionReader,
1257 ) -> Result<()> {
1258 self.process_component_section(
1259 section,
1260 "function",
1261 |components, _, count, offset| {
1262 let current = components.last_mut().unwrap();
1263 check_max(
1264 current.function_count(),
1265 count,
1266 MAX_WASM_FUNCTIONS,
1267 "functions",
1268 offset,
1269 )?;
1270 current.funcs.reserve(count as usize);
1271 Ok(())
1272 },
1273 |components, types, features, func, offset| {
1274 let current = components.last_mut().unwrap();
1275 current.canonical_function(func, types, offset, features)
1276 },
1277 )
1278 }
1279
1280 #[cfg(feature = "component-model")]
1284 pub fn component_start_section(
1285 &mut self,
1286 f: &crate::ComponentStartFunction,
1287 range: &Range<usize>,
1288 ) -> Result<()> {
1289 self.state.ensure_component("start", range.start)?;
1290
1291 self.components.last_mut().unwrap().add_start(
1292 f.func_index,
1293 &f.arguments,
1294 f.results,
1295 &self.features,
1296 &mut self.types,
1297 range.start,
1298 )
1299 }
1300
1301 #[cfg(feature = "component-model")]
1305 pub fn component_import_section(
1306 &mut self,
1307 section: &crate::ComponentImportSectionReader,
1308 ) -> Result<()> {
1309 self.process_component_section(
1310 section,
1311 "import",
1312 |_, _, _, _| Ok(()), |components, types, features, import, offset| {
1314 components
1315 .last_mut()
1316 .unwrap()
1317 .add_import(import, features, types, offset)
1318 },
1319 )
1320 }
1321
1322 #[cfg(feature = "component-model")]
1326 pub fn component_export_section(
1327 &mut self,
1328 section: &crate::ComponentExportSectionReader,
1329 ) -> Result<()> {
1330 self.process_component_section(
1331 section,
1332 "export",
1333 |components, _, count, offset| {
1334 let current = components.last_mut().unwrap();
1335 check_max(
1336 current.exports.len(),
1337 count,
1338 MAX_WASM_EXPORTS,
1339 "exports",
1340 offset,
1341 )?;
1342 current.exports.reserve(count as usize);
1343 Ok(())
1344 },
1345 |components, types, features, export, offset| {
1346 let current = components.last_mut().unwrap();
1347 let ty = current.export_to_entity_type(&export, features, types, offset)?;
1348 current.add_export(
1349 export.name,
1350 ty,
1351 features,
1352 types,
1353 offset,
1354 false, )
1356 },
1357 )
1358 }
1359
1360 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1364 Err(format_err!(range.start, "malformed section id: {id}"))
1365 }
1366
1367 pub fn end(&mut self, offset: usize) -> Result<Types> {
1371 match mem::replace(&mut self.state, State::End) {
1372 State::Unparsed(_) => Err(BinaryReaderError::new(
1373 "cannot call `end` before a header has been parsed",
1374 offset,
1375 )),
1376 State::End => Err(BinaryReaderError::new(
1377 "cannot call `end` after parsing has completed",
1378 offset,
1379 )),
1380 State::Module => {
1381 let mut state = self.module.take().unwrap();
1382 state.validate_end(offset)?;
1383
1384 #[cfg(feature = "component-model")]
1387 if let Some(parent) = self.components.last_mut() {
1388 parent.add_core_module(&state.module, &mut self.types, offset)?;
1389 self.state = State::Component;
1390 }
1391
1392 Ok(Types::from_module(
1393 self.id,
1394 self.types.commit(),
1395 state.module.arc().clone(),
1396 ))
1397 }
1398 #[cfg(feature = "component-model")]
1399 State::Component => {
1400 let mut component = self.components.pop().unwrap();
1401
1402 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1404 bail!(
1405 offset,
1406 "value index {index} was not used as part of an \
1407 instantiation, start function, or export"
1408 );
1409 }
1410
1411 let ty = component.finish(&mut self.types, offset)?;
1414 if let Some(parent) = self.components.last_mut() {
1415 parent.add_component(ty, &mut self.types)?;
1416 self.state = State::Component;
1417 }
1418
1419 Ok(Types::from_component(
1420 self.id,
1421 self.types.commit(),
1422 component,
1423 ))
1424 }
1425 }
1426 }
1427
1428 fn process_module_section<'a, T>(
1429 &mut self,
1430 order: Order,
1431 section: &SectionLimited<'a, T>,
1432 name: &str,
1433 validate_section: impl FnOnce(
1434 &mut ModuleState,
1435 &WasmFeatures,
1436 &mut TypeAlloc,
1437 u32,
1438 usize,
1439 ) -> Result<()>,
1440 mut validate_item: impl FnMut(
1441 &mut ModuleState,
1442 &WasmFeatures,
1443 &mut TypeAlloc,
1444 T,
1445 usize,
1446 ) -> Result<()>,
1447 ) -> Result<()>
1448 where
1449 T: FromReader<'a>,
1450 {
1451 let offset = section.range().start;
1452 self.state.ensure_module(name, offset)?;
1453
1454 let state = self.module.as_mut().unwrap();
1455 state.update_order(order, offset)?;
1456
1457 validate_section(
1458 state,
1459 &self.features,
1460 &mut self.types,
1461 section.count(),
1462 offset,
1463 )?;
1464
1465 for item in section.clone().into_iter_with_offsets() {
1466 let (offset, item) = item?;
1467 validate_item(state, &self.features, &mut self.types, item, offset)?;
1468 }
1469
1470 Ok(())
1471 }
1472
1473 #[cfg(feature = "component-model")]
1474 fn process_component_section<'a, T>(
1475 &mut self,
1476 section: &SectionLimited<'a, T>,
1477 name: &str,
1478 validate_section: impl FnOnce(
1479 &mut Vec<ComponentState>,
1480 &mut TypeAlloc,
1481 u32,
1482 usize,
1483 ) -> Result<()>,
1484 mut validate_item: impl FnMut(
1485 &mut Vec<ComponentState>,
1486 &mut TypeAlloc,
1487 &WasmFeatures,
1488 T,
1489 usize,
1490 ) -> Result<()>,
1491 ) -> Result<()>
1492 where
1493 T: FromReader<'a>,
1494 {
1495 let offset = section.range().start;
1496
1497 if !self.features.component_model() {
1498 return Err(BinaryReaderError::new(
1499 "component model feature is not enabled",
1500 offset,
1501 ));
1502 }
1503
1504 self.state.ensure_component(name, offset)?;
1505 validate_section(
1506 &mut self.components,
1507 &mut self.types,
1508 section.count(),
1509 offset,
1510 )?;
1511
1512 for item in section.clone().into_iter_with_offsets() {
1513 let (offset, item) = item?;
1514 validate_item(
1515 &mut self.components,
1516 &mut self.types,
1517 &self.features,
1518 item,
1519 offset,
1520 )?;
1521 }
1522
1523 Ok(())
1524 }
1525}
1526
1527#[cfg(test)]
1528mod tests {
1529 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1530 use anyhow::Result;
1531
1532 #[test]
1533 fn test_module_type_information() -> Result<()> {
1534 let bytes = wat::parse_str(
1535 r#"
1536 (module
1537 (type (func (param i32 i64) (result i32)))
1538 (memory 1 5)
1539 (table 10 funcref)
1540 (global (mut i32) (i32.const 0))
1541 (func (type 0) (i32.const 0))
1542 (tag (param i64 i32))
1543 (elem funcref (ref.func 0))
1544 )
1545 "#,
1546 )?;
1547
1548 let mut validator =
1549 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::EXCEPTIONS);
1550
1551 let types = validator.validate_all(&bytes)?;
1552 let types = types.as_ref();
1553
1554 assert_eq!(types.core_type_count_in_module(), 2);
1555 assert_eq!(types.memory_count(), 1);
1556 assert_eq!(types.table_count(), 1);
1557 assert_eq!(types.global_count(), 1);
1558 assert_eq!(types.function_count(), 1);
1559 assert_eq!(types.tag_count(), 1);
1560 assert_eq!(types.element_count(), 1);
1561 assert_eq!(types.module_count(), 0);
1562 assert_eq!(types.component_count(), 0);
1563 assert_eq!(types.core_instance_count(), 0);
1564 assert_eq!(types.value_count(), 0);
1565
1566 let id = types.core_type_at_in_module(0);
1567 let ty = types[id].unwrap_func();
1568 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1569 assert_eq!(ty.results(), [ValType::I32]);
1570
1571 let id = types.core_type_at_in_module(1);
1572 let ty = types[id].unwrap_func();
1573 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1574 assert_eq!(ty.results(), []);
1575
1576 assert_eq!(
1577 types.memory_at(0),
1578 MemoryType {
1579 memory64: false,
1580 shared: false,
1581 initial: 1,
1582 maximum: Some(5),
1583 page_size_log2: None,
1584 }
1585 );
1586
1587 assert_eq!(
1588 types.table_at(0),
1589 TableType {
1590 initial: 10,
1591 maximum: None,
1592 element_type: RefType::FUNCREF,
1593 table64: false,
1594 shared: false,
1595 }
1596 );
1597
1598 assert_eq!(
1599 types.global_at(0),
1600 GlobalType {
1601 content_type: ValType::I32,
1602 mutable: true,
1603 shared: false
1604 }
1605 );
1606
1607 let id = types.core_function_at(0);
1608 let ty = types[id].unwrap_func();
1609 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1610 assert_eq!(ty.results(), [ValType::I32]);
1611
1612 let ty = types.tag_at(0);
1613 let ty = types[ty].unwrap_func();
1614 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1615 assert_eq!(ty.results(), []);
1616
1617 assert_eq!(types.element_at(0), RefType::FUNCREF);
1618
1619 Ok(())
1620 }
1621
1622 #[test]
1623 fn test_type_id_aliasing() -> Result<()> {
1624 let bytes = wat::parse_str(
1625 r#"
1626 (component
1627 (type $T (list string))
1628 (alias outer 0 $T (type $A1))
1629 (alias outer 0 $T (type $A2))
1630 )
1631 "#,
1632 )?;
1633
1634 let mut validator =
1635 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1636
1637 let types = validator.validate_all(&bytes)?;
1638 let types = types.as_ref();
1639
1640 let t_id = types.component_defined_type_at(0);
1641 let a1_id = types.component_defined_type_at(1);
1642 let a2_id = types.component_defined_type_at(2);
1643
1644 assert!(t_id == a1_id);
1646 assert!(t_id == a2_id);
1647 assert!(a1_id == a2_id);
1648
1649 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1651 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1652
1653 Ok(())
1654 }
1655
1656 #[test]
1657 fn test_type_id_exports() -> Result<()> {
1658 let bytes = wat::parse_str(
1659 r#"
1660 (component
1661 (type $T (list string))
1662 (export $A1 "A1" (type $T))
1663 (export $A2 "A2" (type $T))
1664 )
1665 "#,
1666 )?;
1667
1668 let mut validator =
1669 Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
1670
1671 let types = validator.validate_all(&bytes)?;
1672 let types = types.as_ref();
1673
1674 let t_id = types.component_defined_type_at(0);
1675 let a1_id = types.component_defined_type_at(1);
1676 let a2_id = types.component_defined_type_at(2);
1677
1678 assert!(t_id != a1_id);
1680 assert!(t_id != a2_id);
1681 assert!(a1_id != a2_id);
1682
1683 assert!(std::ptr::eq(&types[t_id], &types[a1_id],));
1685 assert!(std::ptr::eq(&types[t_id], &types[a2_id],));
1686
1687 Ok(())
1688 }
1689}