1use crate::std::mem;
17use crate::std::ops::Range;
18use crate::{
19 limits::*, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser, Payload,
20 RefType, Result, SectionLimited, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION,
21};
22use alloc::sync::Arc;
23use alloc::vec::Vec;
24
25pub fn validate(bytes: &[u8]) -> Result<Types> {
40 Validator::new().validate_all(bytes)
41}
42
43#[test]
44fn test_validate() {
45 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0]).is_ok());
46 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0]).is_err());
47}
48
49mod component;
50mod core;
51mod func;
52pub mod names;
53mod operators;
54pub mod types;
55
56use self::component::*;
57pub use self::core::ValidatorResources;
58use self::core::*;
59use self::types::{TypeAlloc, Types, TypesRef};
60pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
61pub use operators::{Frame, FrameKind};
62
63fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
64 if max
65 .checked_sub(cur_len)
66 .and_then(|amt| amt.checked_sub(amt_added as usize))
67 .is_none()
68 {
69 if max == 1 {
70 bail!(offset, "multiple {desc}");
71 }
72
73 bail!(offset, "{desc} count exceeds limit of {max}");
74 }
75
76 Ok(())
77}
78
79fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
80 match a.checked_add(b) {
81 Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
82 _ => Err(format_err!(
83 offset,
84 "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
85 )),
86 }
87}
88
89#[derive(Default)]
115pub struct Validator {
116 state: State,
118
119 types: TypeAlloc,
121
122 module: Option<ModuleState>,
124
125 components: Vec<ComponentState>,
128
129 features: WasmFeatures,
132}
133
134#[derive(Debug, Clone, Copy, Eq, PartialEq)]
135enum State {
136 Unparsed(Option<Encoding>),
140 Module,
144 Component,
149 End,
151}
152
153impl State {
154 fn ensure_parsable(&self, offset: usize) -> Result<()> {
155 match self {
156 Self::Module | Self::Component => Ok(()),
157 Self::Unparsed(_) => Err(BinaryReaderError::new(
158 "unexpected section before header was parsed",
159 offset,
160 )),
161 Self::End => Err(BinaryReaderError::new(
162 "unexpected section after parsing has completed",
163 offset,
164 )),
165 }
166 }
167
168 fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
169 self.ensure_parsable(offset)?;
170
171 match self {
172 Self::Module => Ok(()),
173 Self::Component => Err(format_err!(
174 offset,
175 "unexpected module {section} section while parsing a component",
176 )),
177 _ => unreachable!(),
178 }
179 }
180
181 fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
182 self.ensure_parsable(offset)?;
183
184 match self {
185 Self::Component => Ok(()),
186 Self::Module => Err(format_err!(
187 offset,
188 "unexpected component {section} section while parsing a module",
189 )),
190 _ => unreachable!(),
191 }
192 }
193}
194
195impl Default for State {
196 fn default() -> Self {
197 Self::Unparsed(None)
198 }
199}
200
201#[derive(Hash, Debug, Copy, Clone)]
203pub struct WasmFeatures {
204 pub mutable_global: bool,
206 pub saturating_float_to_int: bool,
208 pub sign_extension: bool,
210 pub reference_types: bool,
212 pub multi_value: bool,
214 pub bulk_memory: bool,
216 pub simd: bool,
218 pub relaxed_simd: bool,
220 pub threads: bool,
222 pub tail_call: bool,
224 pub floats: bool,
235 pub multi_memory: bool,
237 pub exceptions: bool,
239 pub memory64: bool,
241 pub extended_const: bool,
243 pub component_model: bool,
245 pub function_references: bool,
247 pub memory_control: bool,
249 pub gc: bool,
251 pub component_model_values: bool,
253 pub component_model_nested_names: bool,
255}
256
257impl WasmFeatures {
258 pub fn all() -> Self {
260 WasmFeatures {
261 mutable_global: true,
262 saturating_float_to_int: true,
263 sign_extension: true,
264 reference_types: true,
265 multi_value: true,
266 bulk_memory: true,
267 simd: true,
268 relaxed_simd: true,
269 threads: true,
270 tail_call: true,
271 floats: true,
272 multi_memory: true,
273 exceptions: true,
274 memory64: true,
275 extended_const: true,
276 component_model: true,
277 function_references: true,
278 memory_control: true,
279 gc: true,
280 component_model_values: true,
281 component_model_nested_names: true,
282 }
283 }
284
285 pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
290 match ty {
291 ValType::I32 | ValType::I64 => Ok(()),
292 ValType::F32 | ValType::F64 => {
293 if self.floats {
294 Ok(())
295 } else {
296 Err("floating-point support is disabled")
297 }
298 }
299 ValType::Ref(r) => self.check_ref_type(r),
300 ValType::V128 => {
301 if self.simd {
302 Ok(())
303 } else {
304 Err("SIMD support is not enabled")
305 }
306 }
307 }
308 }
309
310 pub(crate) fn check_ref_type(&self, r: RefType) -> Result<(), &'static str> {
311 if !self.reference_types {
312 return Err("reference types support is not enabled");
313 }
314 match (r.heap_type(), r.is_nullable()) {
315 (HeapType::Func, true) | (HeapType::Extern, true) => Ok(()),
317
318 (HeapType::Func | HeapType::Extern, false) => {
321 if self.function_references {
322 Ok(())
323 } else {
324 Err("function references required for non-nullable types")
325 }
326 }
327
328 (HeapType::Concrete(_), _) => {
331 if self.function_references || self.gc {
332 Ok(())
333 } else {
334 Err("function references required for index reference types")
335 }
336 }
337
338 (
340 HeapType::Any
341 | HeapType::None
342 | HeapType::Eq
343 | HeapType::Struct
344 | HeapType::Array
345 | HeapType::I31
346 | HeapType::NoExtern
347 | HeapType::NoFunc,
348 _,
349 ) => {
350 if self.gc {
351 Ok(())
352 } else {
353 Err("heap types not supported without the gc feature")
354 }
355 }
356
357 (HeapType::Exn, _) => {
359 if self.exceptions {
360 Ok(())
361 } else {
362 Err("exception refs not supported without the exception handling feature")
363 }
364 }
365 }
366 }
367}
368
369impl Default for WasmFeatures {
370 fn default() -> WasmFeatures {
371 WasmFeatures {
372 exceptions: false,
374 memory64: false,
375 extended_const: false,
376 function_references: false,
377 memory_control: false,
378 gc: false,
379 component_model_values: false,
380 component_model_nested_names: false,
381
382 mutable_global: true,
384 saturating_float_to_int: true,
385 sign_extension: true,
386 bulk_memory: true,
387 multi_value: true,
388 reference_types: true,
389 tail_call: true,
390 simd: true,
391 floats: true,
392 relaxed_simd: true,
393 threads: true,
394 multi_memory: true,
395 component_model: true,
396 }
397 }
398}
399
400#[allow(clippy::large_enum_variant)]
402pub enum ValidPayload<'a> {
403 Ok,
405 Parser(Parser),
410 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
412 End(Types),
415}
416
417impl Validator {
418 pub fn new() -> Validator {
425 Validator::default()
426 }
427
428 pub fn new_with_features(features: WasmFeatures) -> Validator {
436 let mut ret = Validator::new();
437 ret.features = features;
438 ret
439 }
440
441 pub fn features(&self) -> &WasmFeatures {
443 &self.features
444 }
445
446 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
455 let mut functions_to_validate = Vec::new();
456 let mut last_types = None;
457 for payload in Parser::new(0).parse_all(bytes) {
458 match self.payload(&payload?)? {
459 ValidPayload::Func(a, b) => {
460 functions_to_validate.push((a, b));
461 }
462 ValidPayload::End(types) => {
463 last_types = Some(types);
465 }
466 _ => {}
467 }
468 }
469
470 let mut allocs = FuncValidatorAllocations::default();
471 for (func, body) in functions_to_validate {
472 let mut validator = func.into_validator(allocs);
473 validator.validate(&body)?;
474 allocs = validator.into_allocations();
475 }
476
477 Ok(last_types.unwrap())
478 }
479
480 pub fn types(&self, mut level: usize) -> Option<TypesRef> {
490 if let Some(module) = &self.module {
491 if level == 0 {
492 return Some(TypesRef::from_module(&self.types, &module.module));
493 } else {
494 level -= 1;
495 }
496 }
497
498 self.components
499 .iter()
500 .nth_back(level)
501 .map(|component| TypesRef::from_component(&self.types, component))
502 }
503
504 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
518 use crate::Payload::*;
519 match payload {
520 Version {
521 num,
522 encoding,
523 range,
524 } => self.version(*num, *encoding, range)?,
525
526 TypeSection(s) => self.type_section(s)?,
528 ImportSection(s) => self.import_section(s)?,
529 FunctionSection(s) => self.function_section(s)?,
530 TableSection(s) => self.table_section(s)?,
531 MemorySection(s) => self.memory_section(s)?,
532 TagSection(s) => self.tag_section(s)?,
533 GlobalSection(s) => self.global_section(s)?,
534 ExportSection(s) => self.export_section(s)?,
535 StartSection { func, range } => self.start_section(*func, range)?,
536 ElementSection(s) => self.element_section(s)?,
537 DataCountSection { count, range } => self.data_count_section(*count, range)?,
538 CodeSectionStart {
539 count,
540 range,
541 size: _,
542 } => self.code_section_start(*count, range)?,
543 CodeSectionEntry(body) => {
544 let func_validator = self.code_section_entry(body)?;
545 return Ok(ValidPayload::Func(func_validator, body.clone()));
546 }
547 DataSection(s) => self.data_section(s)?,
548
549 ModuleSection { parser, range, .. } => {
551 self.module_section(range)?;
552 return Ok(ValidPayload::Parser(parser.clone()));
553 }
554 InstanceSection(s) => self.instance_section(s)?,
555 CoreTypeSection(s) => self.core_type_section(s)?,
556 ComponentSection { parser, range, .. } => {
557 self.component_section(range)?;
558 return Ok(ValidPayload::Parser(parser.clone()));
559 }
560 ComponentInstanceSection(s) => self.component_instance_section(s)?,
561 ComponentAliasSection(s) => self.component_alias_section(s)?,
562 ComponentTypeSection(s) => self.component_type_section(s)?,
563 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
564 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
565 ComponentImportSection(s) => self.component_import_section(s)?,
566 ComponentExportSection(s) => self.component_export_section(s)?,
567
568 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
569
570 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
572 }
573 Ok(ValidPayload::Ok)
574 }
575
576 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
578 match &self.state {
579 State::Unparsed(expected) => {
580 if let Some(expected) = expected {
581 if *expected != encoding {
582 bail!(
583 range.start,
584 "expected a version header for a {}",
585 match expected {
586 Encoding::Module => "module",
587 Encoding::Component => "component",
588 }
589 );
590 }
591 }
592 }
593 _ => {
594 return Err(BinaryReaderError::new(
595 "wasm version header out of order",
596 range.start,
597 ))
598 }
599 }
600
601 self.state = match encoding {
602 Encoding::Module => {
603 if num == WASM_MODULE_VERSION {
604 assert!(self.module.is_none());
605 self.module = Some(ModuleState::default());
606 State::Module
607 } else {
608 bail!(range.start, "unknown binary version: {num:#x}");
609 }
610 }
611 Encoding::Component => {
612 if !self.features.component_model {
613 bail!(
614 range.start,
615 "unknown binary version and encoding combination: {num:#x} and 0x1, \
616 note: encoded as a component but the WebAssembly component model feature \
617 is not enabled - enable the feature to allow component validation",
618 );
619 }
620 if num == WASM_COMPONENT_VERSION {
621 self.components
622 .push(ComponentState::new(ComponentKind::Component));
623 State::Component
624 } else if num < WASM_COMPONENT_VERSION {
625 bail!(range.start, "unsupported component version: {num:#x}");
626 } else {
627 bail!(range.start, "unknown component version: {num:#x}");
628 }
629 }
630 };
631
632 Ok(())
633 }
634
635 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
637 self.process_module_section(
638 Order::Type,
639 section,
640 "type",
641 |state, _, _types, count, offset| {
642 check_max(
643 state.module.types.len(),
644 count,
645 MAX_WASM_TYPES,
646 "types",
647 offset,
648 )?;
649 state.module.assert_mut().types.reserve(count as usize);
650 Ok(())
651 },
652 |state, features, types, rec_group, offset| {
653 state
654 .module
655 .assert_mut()
656 .add_types(rec_group, features, types, offset, true)?;
657 Ok(())
658 },
659 )
660 }
661
662 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
666 self.process_module_section(
667 Order::Import,
668 section,
669 "import",
670 |_, _, _, _, _| Ok(()), |state, features, types, import, offset| {
672 state
673 .module
674 .assert_mut()
675 .add_import(import, features, types, offset)
676 },
677 )
678 }
679
680 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
684 self.process_module_section(
685 Order::Function,
686 section,
687 "function",
688 |state, _, _, count, offset| {
689 check_max(
690 state.module.functions.len(),
691 count,
692 MAX_WASM_FUNCTIONS,
693 "functions",
694 offset,
695 )?;
696 state.module.assert_mut().functions.reserve(count as usize);
697 debug_assert!(state.expected_code_bodies.is_none());
698 state.expected_code_bodies = Some(count);
699 Ok(())
700 },
701 |state, _, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
702 )
703 }
704
705 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
709 let features = self.features;
710 self.process_module_section(
711 Order::Table,
712 section,
713 "table",
714 |state, _, _, count, offset| {
715 check_max(
716 state.module.tables.len(),
717 count,
718 state.module.max_tables(&features),
719 "tables",
720 offset,
721 )?;
722 state.module.assert_mut().tables.reserve(count as usize);
723 Ok(())
724 },
725 |state, features, types, table, offset| state.add_table(table, features, types, offset),
726 )
727 }
728
729 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
733 self.process_module_section(
734 Order::Memory,
735 section,
736 "memory",
737 |state, features, _, count, offset| {
738 check_max(
739 state.module.memories.len(),
740 count,
741 state.module.max_memories(features),
742 "memories",
743 offset,
744 )?;
745 state.module.assert_mut().memories.reserve(count as usize);
746 Ok(())
747 },
748 |state, features, _, ty, offset| {
749 state.module.assert_mut().add_memory(ty, features, offset)
750 },
751 )
752 }
753
754 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
758 if !self.features.exceptions {
759 return Err(BinaryReaderError::new(
760 "exceptions proposal not enabled",
761 section.range().start,
762 ));
763 }
764
765 self.process_module_section(
766 Order::Tag,
767 section,
768 "tag",
769 |state, _, _, count, offset| {
770 check_max(
771 state.module.tags.len(),
772 count,
773 MAX_WASM_TAGS,
774 "tags",
775 offset,
776 )?;
777 state.module.assert_mut().tags.reserve(count as usize);
778 Ok(())
779 },
780 |state, features, types, ty, offset| {
781 state
782 .module
783 .assert_mut()
784 .add_tag(ty, features, types, offset)
785 },
786 )
787 }
788
789 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
793 self.process_module_section(
794 Order::Global,
795 section,
796 "global",
797 |state, _, _, count, offset| {
798 check_max(
799 state.module.globals.len(),
800 count,
801 MAX_WASM_GLOBALS,
802 "globals",
803 offset,
804 )?;
805 state.module.assert_mut().globals.reserve(count as usize);
806 Ok(())
807 },
808 |state, features, types, global, offset| {
809 state.add_global(global, features, types, offset)
810 },
811 )
812 }
813
814 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
818 self.process_module_section(
819 Order::Export,
820 section,
821 "export",
822 |state, _, _, count, offset| {
823 check_max(
824 state.module.exports.len(),
825 count,
826 MAX_WASM_EXPORTS,
827 "exports",
828 offset,
829 )?;
830 state.module.assert_mut().exports.reserve(count as usize);
831 Ok(())
832 },
833 |state, features, types, e, offset| {
834 let state = state.module.assert_mut();
835 let ty = state.export_to_entity_type(&e, offset)?;
836 state.add_export(
837 e.name, ty, features, offset, false, types,
839 )
840 },
841 )
842 }
843
844 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
848 let offset = range.start;
849 self.state.ensure_module("start", offset)?;
850 let state = self.module.as_mut().unwrap();
851 state.update_order(Order::Start, offset)?;
852
853 let ty = state.module.get_func_type(func, &self.types, offset)?;
854 if !ty.params().is_empty() || !ty.results().is_empty() {
855 return Err(BinaryReaderError::new(
856 "invalid start function type",
857 offset,
858 ));
859 }
860
861 Ok(())
862 }
863
864 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
868 self.process_module_section(
869 Order::Element,
870 section,
871 "element",
872 |state, _, _, count, offset| {
873 check_max(
874 state.module.element_types.len(),
875 count,
876 MAX_WASM_ELEMENT_SEGMENTS,
877 "element segments",
878 offset,
879 )?;
880 state
881 .module
882 .assert_mut()
883 .element_types
884 .reserve(count as usize);
885 Ok(())
886 },
887 |state, features, types, e, offset| {
888 state.add_element_segment(e, features, types, offset)
889 },
890 )
891 }
892
893 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
897 let offset = range.start;
898 self.state.ensure_module("data count", offset)?;
899
900 let state = self.module.as_mut().unwrap();
901 state.update_order(Order::DataCount, offset)?;
902
903 if count > MAX_WASM_DATA_SEGMENTS as u32 {
904 return Err(BinaryReaderError::new(
905 "data count section specifies too many data segments",
906 offset,
907 ));
908 }
909
910 state.module.assert_mut().data_count = Some(count);
911 Ok(())
912 }
913
914 pub fn code_section_start(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
918 let offset = range.start;
919 self.state.ensure_module("code", offset)?;
920
921 let state = self.module.as_mut().unwrap();
922 state.update_order(Order::Code, offset)?;
923
924 match state.expected_code_bodies.take() {
925 Some(n) if n == count => {}
926 Some(_) => {
927 return Err(BinaryReaderError::new(
928 "function and code section have inconsistent lengths",
929 offset,
930 ));
931 }
932 None if count == 0 => {}
935 None => {
936 return Err(BinaryReaderError::new(
937 "code section without function section",
938 offset,
939 ))
940 }
941 }
942
943 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
945
946 Ok(())
947 }
948
949 pub fn code_section_entry(
963 &mut self,
964 body: &crate::FunctionBody,
965 ) -> Result<FuncToValidate<ValidatorResources>> {
966 let offset = body.range().start;
967 self.state.ensure_module("code", offset)?;
968
969 let state = self.module.as_mut().unwrap();
970
971 let (index, ty) = state.next_code_index_and_type(offset)?;
972 Ok(FuncToValidate::new(
973 index,
974 ty,
975 ValidatorResources(state.module.arc().clone()),
976 &self.features,
977 ))
978 }
979
980 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
984 self.process_module_section(
985 Order::Data,
986 section,
987 "data",
988 |state, _, _, count, offset| {
989 state.data_segment_count = count;
990 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
991 },
992 |state, features, types, d, offset| state.add_data_segment(d, features, types, offset),
993 )
994 }
995
996 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
1000 self.state.ensure_component("module", range.start)?;
1001
1002 let current = self.components.last_mut().unwrap();
1003 check_max(
1004 current.core_modules.len(),
1005 1,
1006 MAX_WASM_MODULES,
1007 "modules",
1008 range.start,
1009 )?;
1010
1011 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
1012 State::Component => {}
1013 _ => unreachable!(),
1014 }
1015
1016 Ok(())
1017 }
1018
1019 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
1023 self.process_component_section(
1024 section,
1025 "core instance",
1026 |components, _, count, offset| {
1027 let current = components.last_mut().unwrap();
1028 check_max(
1029 current.instance_count(),
1030 count,
1031 MAX_WASM_INSTANCES,
1032 "instances",
1033 offset,
1034 )?;
1035 current.core_instances.reserve(count as usize);
1036 Ok(())
1037 },
1038 |components, types, _, instance, offset| {
1039 components
1040 .last_mut()
1041 .unwrap()
1042 .add_core_instance(instance, types, offset)
1043 },
1044 )
1045 }
1046
1047 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
1051 self.process_component_section(
1052 section,
1053 "core type",
1054 |components, _types, count, offset| {
1055 let current = components.last_mut().unwrap();
1056 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1057 current.core_types.reserve(count as usize);
1058 Ok(())
1059 },
1060 |components, types, features, ty, offset| {
1061 ComponentState::add_core_type(
1062 components, ty, features, types, offset, false, )
1064 },
1065 )
1066 }
1067
1068 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
1072 self.state.ensure_component("component", range.start)?;
1073
1074 let current = self.components.last_mut().unwrap();
1075 check_max(
1076 current.components.len(),
1077 1,
1078 MAX_WASM_COMPONENTS,
1079 "components",
1080 range.start,
1081 )?;
1082
1083 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1084 State::Component => {}
1085 _ => unreachable!(),
1086 }
1087
1088 Ok(())
1089 }
1090
1091 pub fn component_instance_section(
1095 &mut self,
1096 section: &crate::ComponentInstanceSectionReader,
1097 ) -> Result<()> {
1098 self.process_component_section(
1099 section,
1100 "instance",
1101 |components, _, count, offset| {
1102 let current = components.last_mut().unwrap();
1103 check_max(
1104 current.instance_count(),
1105 count,
1106 MAX_WASM_INSTANCES,
1107 "instances",
1108 offset,
1109 )?;
1110 current.instances.reserve(count as usize);
1111 Ok(())
1112 },
1113 |components, types, features, instance, offset| {
1114 components
1115 .last_mut()
1116 .unwrap()
1117 .add_instance(instance, features, types, offset)
1118 },
1119 )
1120 }
1121
1122 pub fn component_alias_section(
1126 &mut self,
1127 section: &crate::ComponentAliasSectionReader<'_>,
1128 ) -> Result<()> {
1129 self.process_component_section(
1130 section,
1131 "alias",
1132 |_, _, _, _| Ok(()), |components, types, features, alias, offset| -> Result<(), BinaryReaderError> {
1134 ComponentState::add_alias(components, alias, features, types, offset)
1135 },
1136 )
1137 }
1138
1139 pub fn component_type_section(
1143 &mut self,
1144 section: &crate::ComponentTypeSectionReader,
1145 ) -> Result<()> {
1146 self.process_component_section(
1147 section,
1148 "type",
1149 |components, _types, count, offset| {
1150 let current = components.last_mut().unwrap();
1151 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1152 current.types.reserve(count as usize);
1153 Ok(())
1154 },
1155 |components, types, features, ty, offset| {
1156 ComponentState::add_type(
1157 components, ty, features, types, offset, false, )
1159 },
1160 )
1161 }
1162
1163 pub fn component_canonical_section(
1167 &mut self,
1168 section: &crate::ComponentCanonicalSectionReader,
1169 ) -> Result<()> {
1170 self.process_component_section(
1171 section,
1172 "function",
1173 |components, _, count, offset| {
1174 let current = components.last_mut().unwrap();
1175 check_max(
1176 current.function_count(),
1177 count,
1178 MAX_WASM_FUNCTIONS,
1179 "functions",
1180 offset,
1181 )?;
1182 current.funcs.reserve(count as usize);
1183 Ok(())
1184 },
1185 |components, types, _, func, offset| {
1186 let current = components.last_mut().unwrap();
1187 match func {
1188 crate::CanonicalFunction::Lift {
1189 core_func_index,
1190 type_index,
1191 options,
1192 } => current.lift_function(
1193 core_func_index,
1194 type_index,
1195 options.into_vec(),
1196 types,
1197 offset,
1198 ),
1199 crate::CanonicalFunction::Lower {
1200 func_index,
1201 options,
1202 } => current.lower_function(func_index, options.into_vec(), types, offset),
1203 crate::CanonicalFunction::ResourceNew { resource } => {
1204 current.resource_new(resource, types, offset)
1205 }
1206 crate::CanonicalFunction::ResourceDrop { resource } => {
1207 current.resource_drop(resource, types, offset)
1208 }
1209 crate::CanonicalFunction::ResourceRep { resource } => {
1210 current.resource_rep(resource, types, offset)
1211 }
1212 }
1213 },
1214 )
1215 }
1216
1217 pub fn component_start_section(
1221 &mut self,
1222 f: &crate::ComponentStartFunction,
1223 range: &Range<usize>,
1224 ) -> Result<()> {
1225 self.state.ensure_component("start", range.start)?;
1226
1227 self.components.last_mut().unwrap().add_start(
1228 f.func_index,
1229 &f.arguments,
1230 f.results,
1231 &self.features,
1232 &mut self.types,
1233 range.start,
1234 )
1235 }
1236
1237 pub fn component_import_section(
1241 &mut self,
1242 section: &crate::ComponentImportSectionReader,
1243 ) -> Result<()> {
1244 self.process_component_section(
1245 section,
1246 "import",
1247 |_, _, _, _| Ok(()), |components, types, features, import, offset| {
1249 components
1250 .last_mut()
1251 .unwrap()
1252 .add_import(import, features, types, offset)
1253 },
1254 )
1255 }
1256
1257 pub fn component_export_section(
1261 &mut self,
1262 section: &crate::ComponentExportSectionReader,
1263 ) -> Result<()> {
1264 self.process_component_section(
1265 section,
1266 "export",
1267 |components, _, count, offset| {
1268 let current = components.last_mut().unwrap();
1269 check_max(
1270 current.exports.len(),
1271 count,
1272 MAX_WASM_EXPORTS,
1273 "exports",
1274 offset,
1275 )?;
1276 current.exports.reserve(count as usize);
1277 Ok(())
1278 },
1279 |components, types, features, export, offset| {
1280 let current = components.last_mut().unwrap();
1281 let ty = current.export_to_entity_type(&export, features, types, offset)?;
1282 current.add_export(
1283 export.name,
1284 ty,
1285 features,
1286 types,
1287 offset,
1288 false, )
1290 },
1291 )
1292 }
1293
1294 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1298 Err(format_err!(range.start, "malformed section id: {id}"))
1299 }
1300
1301 pub fn end(&mut self, offset: usize) -> Result<Types> {
1305 match crate::std::mem::replace(&mut self.state, State::End) {
1306 State::Unparsed(_) => Err(BinaryReaderError::new(
1307 "cannot call `end` before a header has been parsed",
1308 offset,
1309 )),
1310 State::End => Err(BinaryReaderError::new(
1311 "cannot call `end` after parsing has completed",
1312 offset,
1313 )),
1314 State::Module => {
1315 let mut state = self.module.take().unwrap();
1316 state.validate_end(offset)?;
1317
1318 if let Some(parent) = self.components.last_mut() {
1321 parent.add_core_module(&state.module, &mut self.types, offset)?;
1322 self.state = State::Component;
1323 }
1324
1325 Ok(Types::from_module(
1326 self.types.commit(),
1327 state.module.arc().clone(),
1328 ))
1329 }
1330 State::Component => {
1331 let mut component = self.components.pop().unwrap();
1332
1333 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1335 bail!(
1336 offset,
1337 "value index {index} was not used as part of an \
1338 instantiation, start function, or export"
1339 );
1340 }
1341
1342 let ty = component.finish(&mut self.types, offset)?;
1345 if let Some(parent) = self.components.last_mut() {
1346 parent.add_component(ty, &mut self.types)?;
1347 self.state = State::Component;
1348 }
1349
1350 Ok(Types::from_component(self.types.commit(), component))
1351 }
1352 }
1353 }
1354
1355 fn process_module_section<'a, T>(
1356 &mut self,
1357 order: Order,
1358 section: &SectionLimited<'a, T>,
1359 name: &str,
1360 validate_section: impl FnOnce(
1361 &mut ModuleState,
1362 &WasmFeatures,
1363 &mut TypeAlloc,
1364 u32,
1365 usize,
1366 ) -> Result<()>,
1367 mut validate_item: impl FnMut(
1368 &mut ModuleState,
1369 &WasmFeatures,
1370 &mut TypeAlloc,
1371 T,
1372 usize,
1373 ) -> Result<()>,
1374 ) -> Result<()>
1375 where
1376 T: FromReader<'a>,
1377 {
1378 let offset = section.range().start;
1379 self.state.ensure_module(name, offset)?;
1380
1381 let state = self.module.as_mut().unwrap();
1382 state.update_order(order, offset)?;
1383
1384 validate_section(
1385 state,
1386 &self.features,
1387 &mut self.types,
1388 section.count(),
1389 offset,
1390 )?;
1391
1392 for item in section.clone().into_iter_with_offsets() {
1393 let (offset, item) = item?;
1394 validate_item(state, &self.features, &mut self.types, item, offset)?;
1395 }
1396
1397 Ok(())
1398 }
1399
1400 fn process_component_section<'a, T>(
1401 &mut self,
1402 section: &SectionLimited<'a, T>,
1403 name: &str,
1404 validate_section: impl FnOnce(
1405 &mut Vec<ComponentState>,
1406 &mut TypeAlloc,
1407 u32,
1408 usize,
1409 ) -> Result<()>,
1410 mut validate_item: impl FnMut(
1411 &mut Vec<ComponentState>,
1412 &mut TypeAlloc,
1413 &WasmFeatures,
1414 T,
1415 usize,
1416 ) -> Result<()>,
1417 ) -> Result<()>
1418 where
1419 T: FromReader<'a>,
1420 {
1421 let offset = section.range().start;
1422
1423 if !self.features.component_model {
1424 return Err(BinaryReaderError::new(
1425 "component model feature is not enabled",
1426 offset,
1427 ));
1428 }
1429
1430 self.state.ensure_component(name, offset)?;
1431 validate_section(
1432 &mut self.components,
1433 &mut self.types,
1434 section.count(),
1435 offset,
1436 )?;
1437
1438 for item in section.clone().into_iter_with_offsets() {
1439 let (offset, item) = item?;
1440 validate_item(
1441 &mut self.components,
1442 &mut self.types,
1443 &self.features,
1444 item,
1445 offset,
1446 )?;
1447 }
1448
1449 Ok(())
1450 }
1451}
1452
1453#[cfg(test)]
1454mod tests {
1455 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1456 use anyhow::Result;
1457
1458 #[test]
1459 fn test_module_type_information() -> Result<()> {
1460 let bytes = wat::parse_str(
1461 r#"
1462 (module
1463 (type (func (param i32 i64) (result i32)))
1464 (memory 1 5)
1465 (table 10 funcref)
1466 (global (mut i32) (i32.const 0))
1467 (func (type 0) (i32.const 0))
1468 (tag (param i64 i32))
1469 (elem funcref (ref.func 0))
1470 )
1471 "#,
1472 )?;
1473
1474 let mut validator = Validator::new_with_features(WasmFeatures {
1475 exceptions: true,
1476 ..Default::default()
1477 });
1478
1479 let types = validator.validate_all(&bytes).unwrap();
1480
1481 assert_eq!(types.type_count(), 2);
1482 assert_eq!(types.memory_count(), 1);
1483 assert_eq!(types.table_count(), 1);
1484 assert_eq!(types.global_count(), 1);
1485 assert_eq!(types.core_function_count(), 1);
1486 assert_eq!(types.tag_count(), 1);
1487 assert_eq!(types.element_count(), 1);
1488 assert_eq!(types.module_count(), 0);
1489 assert_eq!(types.component_count(), 0);
1490 assert_eq!(types.core_instance_count(), 0);
1491 assert_eq!(types.value_count(), 0);
1492
1493 let id = match types.core_type_at(0) {
1494 crate::types::ComponentCoreTypeId::Sub(s) => s,
1495 crate::types::ComponentCoreTypeId::Module(_) => panic!(),
1496 };
1497 let ty = types[id].unwrap_func();
1498 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1499 assert_eq!(ty.results(), [ValType::I32]);
1500
1501 let id = match types.core_type_at(1) {
1502 crate::types::ComponentCoreTypeId::Sub(s) => s,
1503 crate::types::ComponentCoreTypeId::Module(_) => panic!(),
1504 };
1505 let ty = types[id].unwrap_func();
1506 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1507 assert_eq!(ty.results(), []);
1508
1509 assert_eq!(
1510 types.memory_at(0),
1511 MemoryType {
1512 memory64: false,
1513 shared: false,
1514 initial: 1,
1515 maximum: Some(5)
1516 }
1517 );
1518
1519 assert_eq!(
1520 types.table_at(0),
1521 TableType {
1522 initial: 10,
1523 maximum: None,
1524 element_type: RefType::FUNCREF,
1525 }
1526 );
1527
1528 assert_eq!(
1529 types.global_at(0),
1530 GlobalType {
1531 content_type: ValType::I32,
1532 mutable: true
1533 }
1534 );
1535
1536 let id = types.core_function_at(0);
1537 let ty = types[id].unwrap_func();
1538 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1539 assert_eq!(ty.results(), [ValType::I32]);
1540
1541 let ty = types.tag_at(0);
1542 let ty = types[ty].unwrap_func();
1543 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1544 assert_eq!(ty.results(), []);
1545
1546 assert_eq!(types.element_at(0), RefType::FUNCREF);
1547
1548 Ok(())
1549 }
1550
1551 #[test]
1552 fn test_type_id_aliasing() -> Result<()> {
1553 let bytes = wat::parse_str(
1554 r#"
1555 (component
1556 (type $T (list string))
1557 (alias outer 0 $T (type $A1))
1558 (alias outer 0 $T (type $A2))
1559 )
1560 "#,
1561 )?;
1562
1563 let mut validator = Validator::new_with_features(WasmFeatures {
1564 component_model: true,
1565 ..Default::default()
1566 });
1567
1568 let types = validator.validate_all(&bytes).unwrap();
1569
1570 let t_id = types.component_defined_type_at(0);
1571 let a1_id = types.component_defined_type_at(1);
1572 let a2_id = types.component_defined_type_at(2);
1573
1574 assert!(t_id == a1_id);
1576 assert!(t_id == a2_id);
1577 assert!(a1_id == a2_id);
1578
1579 assert!(crate::std::ptr::eq(&types[t_id], &types[a1_id],));
1581 assert!(crate::std::ptr::eq(&types[t_id], &types[a2_id],));
1582
1583 Ok(())
1584 }
1585
1586 #[test]
1587 fn test_type_id_exports() -> Result<()> {
1588 let bytes = wat::parse_str(
1589 r#"
1590 (component
1591 (type $T (list string))
1592 (export $A1 "A1" (type $T))
1593 (export $A2 "A2" (type $T))
1594 )
1595 "#,
1596 )?;
1597
1598 let mut validator = Validator::new_with_features(WasmFeatures {
1599 component_model: true,
1600 ..Default::default()
1601 });
1602
1603 let types = validator.validate_all(&bytes).unwrap();
1604
1605 let t_id = types.component_defined_type_at(0);
1606 let a1_id = types.component_defined_type_at(1);
1607 let a2_id = types.component_defined_type_at(2);
1608
1609 assert!(t_id != a1_id);
1611 assert!(t_id != a2_id);
1612 assert!(a1_id != a2_id);
1613
1614 assert!(crate::std::ptr::eq(&types[t_id], &types[a1_id],));
1616 assert!(crate::std::ptr::eq(&types[t_id], &types[a2_id],));
1617
1618 Ok(())
1619 }
1620}