1use crate::{
17 limits::*, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser, Payload,
18 Result, SectionLimited, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION,
19};
20use std::mem;
21use std::ops::Range;
22use std::sync::Arc;
23
24pub fn validate(bytes: &[u8]) -> Result<Types> {
39 Validator::new().validate_all(bytes)
40}
41
42#[test]
43fn test_validate() {
44 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0]).is_ok());
45 assert!(validate(&[0x0, 0x61, 0x73, 0x6d, 0x2, 0x0, 0x0, 0x0]).is_err());
46}
47
48mod component;
49mod core;
50mod func;
51mod operators;
52pub mod types;
53
54use self::component::*;
55pub use self::core::ValidatorResources;
56use self::core::*;
57use self::types::{TypeAlloc, Types, TypesRef};
58pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
59pub use operators::{Frame, FrameKind};
60
61fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
62 if max
63 .checked_sub(cur_len)
64 .and_then(|amt| amt.checked_sub(amt_added as usize))
65 .is_none()
66 {
67 if max == 1 {
68 bail!(offset, "multiple {desc}");
69 }
70
71 bail!(offset, "{desc} count exceeds limit of {max}");
72 }
73
74 Ok(())
75}
76
77fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
78 match a.checked_add(b) {
79 Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
80 _ => Err(format_err!(
81 offset,
82 "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
83 )),
84 }
85}
86
87#[derive(Default)]
113pub struct Validator {
114 state: State,
116
117 types: TypeAlloc,
119
120 module: Option<ModuleState>,
122
123 components: Vec<ComponentState>,
126
127 features: WasmFeatures,
130}
131
132#[derive(Debug, Clone, Copy, Eq, PartialEq)]
133enum State {
134 Unparsed(Option<Encoding>),
138 Module,
142 Component,
147 End,
149}
150
151impl State {
152 fn ensure_parsable(&self, offset: usize) -> Result<()> {
153 match self {
154 Self::Module | Self::Component => Ok(()),
155 Self::Unparsed(_) => Err(BinaryReaderError::new(
156 "unexpected section before header was parsed",
157 offset,
158 )),
159 Self::End => Err(BinaryReaderError::new(
160 "unexpected section after parsing has completed",
161 offset,
162 )),
163 }
164 }
165
166 fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
167 self.ensure_parsable(offset)?;
168
169 match self {
170 Self::Module => Ok(()),
171 Self::Component => Err(format_err!(
172 offset,
173 "unexpected module {section} section while parsing a component",
174 )),
175 _ => unreachable!(),
176 }
177 }
178
179 fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
180 self.ensure_parsable(offset)?;
181
182 match self {
183 Self::Component => Ok(()),
184 Self::Module => Err(format_err!(
185 offset,
186 "unexpected component {section} section while parsing a module",
187 )),
188 _ => unreachable!(),
189 }
190 }
191}
192
193impl Default for State {
194 fn default() -> Self {
195 Self::Unparsed(None)
196 }
197}
198
199#[derive(Hash, Debug, Copy, Clone)]
201pub struct WasmFeatures {
202 pub mutable_global: bool,
204 pub saturating_float_to_int: bool,
206 pub sign_extension: bool,
208 pub reference_types: bool,
210 pub multi_value: bool,
212 pub bulk_memory: bool,
214 pub simd: bool,
216 pub relaxed_simd: bool,
218 pub threads: bool,
220 pub tail_call: bool,
222 pub floats: bool,
233 pub multi_memory: bool,
235 pub exceptions: bool,
237 pub memory64: bool,
239 pub extended_const: bool,
241 pub component_model: bool,
243 pub function_references: bool,
245 pub memory_control: bool,
247}
248
249impl WasmFeatures {
250 pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
255 match ty {
256 ValType::I32 | ValType::I64 => Ok(()),
257 ValType::F32 | ValType::F64 => {
258 if self.floats {
259 Ok(())
260 } else {
261 Err("floating-point support is disabled")
262 }
263 }
264 ValType::Ref(r) => {
265 if self.reference_types {
266 if !self.function_references {
267 match (r.heap_type, r.nullable) {
268 (_, false) => {
269 Err("function references required for non-nullable types")
270 }
271 (HeapType::TypedFunc(_), _) => {
272 Err("function references required for index reference types")
273 }
274 _ => Ok(()),
275 }
276 } else {
277 Ok(())
278 }
279 } else {
280 Err("reference types support is not enabled")
281 }
282 }
283 ValType::V128 => {
284 if self.simd {
285 Ok(())
286 } else {
287 Err("SIMD support is not enabled")
288 }
289 }
290 }
291 }
292}
293
294impl Default for WasmFeatures {
295 fn default() -> WasmFeatures {
296 WasmFeatures {
297 relaxed_simd: false,
299 threads: false,
300 multi_memory: false,
301 exceptions: false,
302 memory64: false,
303 extended_const: false,
304 component_model: false,
305 function_references: false,
306 memory_control: false,
307
308 mutable_global: true,
310 saturating_float_to_int: true,
311 sign_extension: true,
312 bulk_memory: true,
313 multi_value: true,
314 reference_types: true,
315 tail_call: true,
316 simd: true,
317 floats: true,
318 }
319 }
320}
321
322#[allow(clippy::large_enum_variant)]
324pub enum ValidPayload<'a> {
325 Ok,
327 Parser(Parser),
332 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
334 End(Types),
337}
338
339impl Validator {
340 pub fn new() -> Validator {
347 Validator::default()
348 }
349
350 pub fn new_with_features(features: WasmFeatures) -> Validator {
358 let mut ret = Validator::new();
359 ret.features = features;
360 ret
361 }
362
363 pub fn features(&self) -> &WasmFeatures {
365 &self.features
366 }
367
368 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
377 let mut functions_to_validate = Vec::new();
378 let mut last_types = None;
379 for payload in Parser::new(0).parse_all(bytes) {
380 match self.payload(&payload?)? {
381 ValidPayload::Func(a, b) => {
382 functions_to_validate.push((a, b));
383 }
384 ValidPayload::End(types) => {
385 last_types = Some(types);
387 }
388 _ => {}
389 }
390 }
391
392 let mut allocs = FuncValidatorAllocations::default();
393 for (func, body) in functions_to_validate {
394 let mut validator = func.into_validator(allocs);
395 validator.validate(&body)?;
396 allocs = validator.into_allocations();
397 }
398
399 Ok(last_types.unwrap())
400 }
401
402 pub fn types(&self, mut level: usize) -> Option<TypesRef> {
412 if let Some(module) = &self.module {
413 if level == 0 {
414 return Some(TypesRef::from_module(&self.types, &module.module));
415 } else {
416 level -= 1;
417 }
418 }
419
420 self.components
421 .iter()
422 .nth_back(level)
423 .map(|component| TypesRef::from_component(&self.types, component))
424 }
425
426 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
440 use crate::Payload::*;
441 match payload {
442 Version {
443 num,
444 encoding,
445 range,
446 } => self.version(*num, *encoding, range)?,
447
448 TypeSection(s) => self.type_section(s)?,
450 ImportSection(s) => self.import_section(s)?,
451 FunctionSection(s) => self.function_section(s)?,
452 TableSection(s) => self.table_section(s)?,
453 MemorySection(s) => self.memory_section(s)?,
454 TagSection(s) => self.tag_section(s)?,
455 GlobalSection(s) => self.global_section(s)?,
456 ExportSection(s) => self.export_section(s)?,
457 StartSection { func, range } => self.start_section(*func, range)?,
458 ElementSection(s) => self.element_section(s)?,
459 DataCountSection { count, range } => self.data_count_section(*count, range)?,
460 CodeSectionStart {
461 count,
462 range,
463 size: _,
464 } => self.code_section_start(*count, range)?,
465 CodeSectionEntry(body) => {
466 let func_validator = self.code_section_entry(body)?;
467 return Ok(ValidPayload::Func(func_validator, body.clone()));
468 }
469 DataSection(s) => self.data_section(s)?,
470
471 ModuleSection { parser, range, .. } => {
473 self.module_section(range)?;
474 return Ok(ValidPayload::Parser(parser.clone()));
475 }
476 InstanceSection(s) => self.instance_section(s)?,
477 CoreTypeSection(s) => self.core_type_section(s)?,
478 ComponentSection { parser, range, .. } => {
479 self.component_section(range)?;
480 return Ok(ValidPayload::Parser(parser.clone()));
481 }
482 ComponentInstanceSection(s) => self.component_instance_section(s)?,
483 ComponentAliasSection(s) => self.component_alias_section(s)?,
484 ComponentTypeSection(s) => self.component_type_section(s)?,
485 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
486 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
487 ComponentImportSection(s) => self.component_import_section(s)?,
488 ComponentExportSection(s) => self.component_export_section(s)?,
489
490 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
491
492 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
494 }
495 Ok(ValidPayload::Ok)
496 }
497
498 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
500 match &self.state {
501 State::Unparsed(expected) => {
502 if let Some(expected) = expected {
503 if *expected != encoding {
504 bail!(
505 range.start,
506 "expected a version header for a {}",
507 match expected {
508 Encoding::Module => "module",
509 Encoding::Component => "component",
510 }
511 );
512 }
513 }
514 }
515 _ => {
516 return Err(BinaryReaderError::new(
517 "wasm version header out of order",
518 range.start,
519 ))
520 }
521 }
522
523 self.state = match encoding {
524 Encoding::Module => {
525 if num == WASM_MODULE_VERSION {
526 assert!(self.module.is_none());
527 self.module = Some(ModuleState::default());
528 State::Module
529 } else {
530 bail!(range.start, "unknown binary version: {num:#x}");
531 }
532 }
533 Encoding::Component => {
534 if !self.features.component_model {
535 bail!(
536 range.start,
537 "unknown binary version and encoding combination: {num:#x} and 0x1, \
538 note: encoded as a component but the WebAssembly component model feature \
539 is not enabled - enable the feature to allow component validation",
540 );
541 }
542 if num == WASM_COMPONENT_VERSION {
543 self.components.push(ComponentState::default());
544 State::Component
545 } else if num < WASM_COMPONENT_VERSION {
546 bail!(range.start, "unsupported component version: {num:#x}");
547 } else {
548 bail!(range.start, "unknown component version: {num:#x}");
549 }
550 }
551 };
552
553 Ok(())
554 }
555
556 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
558 self.process_module_section(
559 Order::Type,
560 section,
561 "type",
562 |state, _, types, count, offset| {
563 check_max(
564 state.module.types.len(),
565 count,
566 MAX_WASM_TYPES,
567 "types",
568 offset,
569 )?;
570 types.reserve(count as usize);
571 state.module.assert_mut().types.reserve(count as usize);
572 Ok(())
573 },
574 |state, features, types, def, offset| {
575 state
576 .module
577 .assert_mut()
578 .add_type(def, features, types, offset, false )
579 },
580 )
581 }
582
583 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
587 self.process_module_section(
588 Order::Import,
589 section,
590 "import",
591 |_, _, _, _, _| Ok(()), |state, features, types, import, offset| {
593 state
594 .module
595 .assert_mut()
596 .add_import(import, features, types, offset)
597 },
598 )
599 }
600
601 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
605 self.process_module_section(
606 Order::Function,
607 section,
608 "function",
609 |state, _, _, count, offset| {
610 check_max(
611 state.module.functions.len(),
612 count,
613 MAX_WASM_FUNCTIONS,
614 "functions",
615 offset,
616 )?;
617 state.module.assert_mut().functions.reserve(count as usize);
618 debug_assert!(state.expected_code_bodies.is_none());
619 state.expected_code_bodies = Some(count);
620 Ok(())
621 },
622 |state, _, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
623 )
624 }
625
626 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
630 let features = self.features;
631 self.process_module_section(
632 Order::Table,
633 section,
634 "table",
635 |state, _, _, count, offset| {
636 check_max(
637 state.module.tables.len(),
638 count,
639 state.module.max_tables(&features),
640 "tables",
641 offset,
642 )?;
643 state.module.assert_mut().tables.reserve(count as usize);
644 Ok(())
645 },
646 |state, features, types, table, offset| state.add_table(table, features, types, offset),
647 )
648 }
649
650 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
654 self.process_module_section(
655 Order::Memory,
656 section,
657 "memory",
658 |state, features, _, count, offset| {
659 check_max(
660 state.module.memories.len(),
661 count,
662 state.module.max_memories(features),
663 "memories",
664 offset,
665 )?;
666 state.module.assert_mut().memories.reserve(count as usize);
667 Ok(())
668 },
669 |state, features, _, ty, offset| {
670 state.module.assert_mut().add_memory(ty, features, offset)
671 },
672 )
673 }
674
675 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
679 if !self.features.exceptions {
680 return Err(BinaryReaderError::new(
681 "exceptions proposal not enabled",
682 section.range().start,
683 ));
684 }
685
686 self.process_module_section(
687 Order::Tag,
688 section,
689 "tag",
690 |state, _, _, count, offset| {
691 check_max(
692 state.module.tags.len(),
693 count,
694 MAX_WASM_TAGS,
695 "tags",
696 offset,
697 )?;
698 state.module.assert_mut().tags.reserve(count as usize);
699 Ok(())
700 },
701 |state, features, types, ty, offset| {
702 state
703 .module
704 .assert_mut()
705 .add_tag(ty, features, types, offset)
706 },
707 )
708 }
709
710 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
714 self.process_module_section(
715 Order::Global,
716 section,
717 "global",
718 |state, _, _, count, offset| {
719 check_max(
720 state.module.globals.len(),
721 count,
722 MAX_WASM_GLOBALS,
723 "globals",
724 offset,
725 )?;
726 state.module.assert_mut().globals.reserve(count as usize);
727 Ok(())
728 },
729 |state, features, types, global, offset| {
730 state.add_global(global, features, types, offset)
731 },
732 )
733 }
734
735 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
739 self.process_module_section(
740 Order::Export,
741 section,
742 "export",
743 |state, _, _, count, offset| {
744 check_max(
745 state.module.exports.len(),
746 count,
747 MAX_WASM_EXPORTS,
748 "exports",
749 offset,
750 )?;
751 state.module.assert_mut().exports.reserve(count as usize);
752 Ok(())
753 },
754 |state, features, _, e, offset| {
755 let state = state.module.assert_mut();
756 let ty = state.export_to_entity_type(&e, offset)?;
757 state.add_export(e.name, ty, features, offset, false )
758 },
759 )
760 }
761
762 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
766 let offset = range.start;
767 self.state.ensure_module("start", offset)?;
768 let state = self.module.as_mut().unwrap();
769 state.update_order(Order::Start, offset)?;
770
771 let ty = state.module.get_func_type(func, &self.types, offset)?;
772 if !ty.params().is_empty() || !ty.results().is_empty() {
773 return Err(BinaryReaderError::new(
774 "invalid start function type",
775 offset,
776 ));
777 }
778
779 Ok(())
780 }
781
782 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
786 self.process_module_section(
787 Order::Element,
788 section,
789 "element",
790 |state, _, _, count, offset| {
791 check_max(
792 state.module.element_types.len(),
793 count,
794 MAX_WASM_ELEMENT_SEGMENTS,
795 "element segments",
796 offset,
797 )?;
798 state
799 .module
800 .assert_mut()
801 .element_types
802 .reserve(count as usize);
803 Ok(())
804 },
805 |state, features, types, e, offset| {
806 state.add_element_segment(e, features, types, offset)
807 },
808 )
809 }
810
811 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
815 let offset = range.start;
816 self.state.ensure_module("data count", offset)?;
817
818 let state = self.module.as_mut().unwrap();
819 state.update_order(Order::DataCount, offset)?;
820
821 if count > MAX_WASM_DATA_SEGMENTS as u32 {
822 return Err(BinaryReaderError::new(
823 "data count section specifies too many data segments",
824 offset,
825 ));
826 }
827
828 state.module.assert_mut().data_count = Some(count);
829 Ok(())
830 }
831
832 pub fn code_section_start(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
836 let offset = range.start;
837 self.state.ensure_module("code", offset)?;
838
839 let state = self.module.as_mut().unwrap();
840 state.update_order(Order::Code, offset)?;
841
842 match state.expected_code_bodies.take() {
843 Some(n) if n == count => {}
844 Some(_) => {
845 return Err(BinaryReaderError::new(
846 "function and code section have inconsistent lengths",
847 offset,
848 ));
849 }
850 None if count == 0 => {}
853 None => {
854 return Err(BinaryReaderError::new(
855 "code section without function section",
856 offset,
857 ))
858 }
859 }
860
861 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
863
864 Ok(())
865 }
866
867 pub fn code_section_entry(
881 &mut self,
882 body: &crate::FunctionBody,
883 ) -> Result<FuncToValidate<ValidatorResources>> {
884 let offset = body.range().start;
885 self.state.ensure_module("code", offset)?;
886
887 let state = self.module.as_mut().unwrap();
888
889 let (index, ty) = state.next_code_index_and_type(offset)?;
890 Ok(FuncToValidate::new(
891 index,
892 ty,
893 ValidatorResources(state.module.arc().clone()),
894 &self.features,
895 ))
896 }
897
898 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
902 self.process_module_section(
903 Order::Data,
904 section,
905 "data",
906 |state, _, _, count, offset| {
907 state.data_segment_count = count;
908 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
909 },
910 |state, features, types, d, offset| state.add_data_segment(d, features, types, offset),
911 )
912 }
913
914 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
918 self.state.ensure_component("module", range.start)?;
919
920 let current = self.components.last_mut().unwrap();
921 check_max(
922 current.core_modules.len(),
923 1,
924 MAX_WASM_MODULES,
925 "modules",
926 range.start,
927 )?;
928
929 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
930 State::Component => {}
931 _ => unreachable!(),
932 }
933
934 Ok(())
935 }
936
937 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
941 self.process_component_section(
942 section,
943 "core instance",
944 |components, _, count, offset| {
945 let current = components.last_mut().unwrap();
946 check_max(
947 current.instance_count(),
948 count,
949 MAX_WASM_INSTANCES,
950 "instances",
951 offset,
952 )?;
953 current.core_instances.reserve(count as usize);
954 Ok(())
955 },
956 |components, types, _, instance, offset| {
957 components
958 .last_mut()
959 .unwrap()
960 .add_core_instance(instance, types, offset)
961 },
962 )
963 }
964
965 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
969 self.process_component_section(
970 section,
971 "core type",
972 |components, types, count, offset| {
973 let current = components.last_mut().unwrap();
974 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
975 types.reserve(count as usize);
976 current.core_types.reserve(count as usize);
977 Ok(())
978 },
979 |components, types, features, ty, offset| {
980 ComponentState::add_core_type(
981 components, ty, features, types, offset, false, )
983 },
984 )
985 }
986
987 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
991 self.state.ensure_component("component", range.start)?;
992
993 let current = self.components.last_mut().unwrap();
994 check_max(
995 current.components.len(),
996 1,
997 MAX_WASM_COMPONENTS,
998 "components",
999 range.start,
1000 )?;
1001
1002 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
1003 State::Component => {}
1004 _ => unreachable!(),
1005 }
1006
1007 Ok(())
1008 }
1009
1010 pub fn component_instance_section(
1014 &mut self,
1015 section: &crate::ComponentInstanceSectionReader,
1016 ) -> Result<()> {
1017 self.process_component_section(
1018 section,
1019 "instance",
1020 |components, _, count, offset| {
1021 let current = components.last_mut().unwrap();
1022 check_max(
1023 current.instance_count(),
1024 count,
1025 MAX_WASM_INSTANCES,
1026 "instances",
1027 offset,
1028 )?;
1029 current.instances.reserve(count as usize);
1030 Ok(())
1031 },
1032 |components, types, _, instance, offset| {
1033 components
1034 .last_mut()
1035 .unwrap()
1036 .add_instance(instance, types, offset)
1037 },
1038 )
1039 }
1040
1041 pub fn component_alias_section(
1045 &mut self,
1046 section: &crate::ComponentAliasSectionReader<'_>,
1047 ) -> Result<()> {
1048 self.process_component_section(
1049 section,
1050 "alias",
1051 |_, _, _, _| Ok(()), |components, types, _, alias, offset| -> Result<(), BinaryReaderError> {
1053 ComponentState::add_alias(components, alias, types, offset)
1054 },
1055 )
1056 }
1057
1058 pub fn component_type_section(
1062 &mut self,
1063 section: &crate::ComponentTypeSectionReader,
1064 ) -> Result<()> {
1065 self.process_component_section(
1066 section,
1067 "type",
1068 |components, types, count, offset| {
1069 let current = components.last_mut().unwrap();
1070 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1071 types.reserve(count as usize);
1072 current.types.reserve(count as usize);
1073 Ok(())
1074 },
1075 |components, types, features, ty, offset| {
1076 ComponentState::add_type(
1077 components, ty, features, types, offset, false, )
1079 },
1080 )
1081 }
1082
1083 pub fn component_canonical_section(
1087 &mut self,
1088 section: &crate::ComponentCanonicalSectionReader,
1089 ) -> Result<()> {
1090 self.process_component_section(
1091 section,
1092 "function",
1093 |components, _, count, offset| {
1094 let current = components.last_mut().unwrap();
1095 check_max(
1096 current.function_count(),
1097 count,
1098 MAX_WASM_FUNCTIONS,
1099 "functions",
1100 offset,
1101 )?;
1102 current.funcs.reserve(count as usize);
1103 Ok(())
1104 },
1105 |components, types, _, func, offset| {
1106 let current = components.last_mut().unwrap();
1107 match func {
1108 crate::CanonicalFunction::Lift {
1109 core_func_index,
1110 type_index,
1111 options,
1112 } => current.lift_function(
1113 core_func_index,
1114 type_index,
1115 options.into_vec(),
1116 types,
1117 offset,
1118 ),
1119 crate::CanonicalFunction::Lower {
1120 func_index,
1121 options,
1122 } => current.lower_function(func_index, options.into_vec(), types, offset),
1123 }
1124 },
1125 )
1126 }
1127
1128 pub fn component_start_section(
1132 &mut self,
1133 f: &crate::ComponentStartFunction,
1134 range: &Range<usize>,
1135 ) -> Result<()> {
1136 self.state.ensure_component("start", range.start)?;
1137
1138 self.components.last_mut().unwrap().add_start(
1149 f.func_index,
1150 &f.arguments,
1151 f.results,
1152 &self.types,
1153 range.start,
1154 )
1155 }
1156
1157 pub fn component_import_section(
1161 &mut self,
1162 section: &crate::ComponentImportSectionReader,
1163 ) -> Result<()> {
1164 self.process_component_section(
1165 section,
1166 "import",
1167 |_, _, _, _| Ok(()), |components, types, _, import, offset| {
1169 components
1170 .last_mut()
1171 .unwrap()
1172 .add_import(import, types, offset)
1173 },
1174 )
1175 }
1176
1177 pub fn component_export_section(
1181 &mut self,
1182 section: &crate::ComponentExportSectionReader,
1183 ) -> Result<()> {
1184 self.process_component_section(
1185 section,
1186 "export",
1187 |components, _, count, offset| {
1188 let current = components.last_mut().unwrap();
1189 check_max(
1190 current.externs.len(),
1191 count,
1192 MAX_WASM_EXPORTS,
1193 "imports and exports",
1194 offset,
1195 )?;
1196 current.externs.reserve(count as usize);
1197 Ok(())
1198 },
1199 |components, types, _, export, offset| {
1200 let current = components.last_mut().unwrap();
1201 let ty = current.export_to_entity_type(&export, types, offset)?;
1202 current.add_export(
1203 export.name,
1204 export.url,
1205 ty,
1206 offset,
1207 false, )
1209 },
1210 )
1211 }
1212
1213 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1217 Err(format_err!(range.start, "malformed section id: {id}"))
1218 }
1219
1220 pub fn end(&mut self, offset: usize) -> Result<Types> {
1224 match std::mem::replace(&mut self.state, State::End) {
1225 State::Unparsed(_) => Err(BinaryReaderError::new(
1226 "cannot call `end` before a header has been parsed",
1227 offset,
1228 )),
1229 State::End => Err(BinaryReaderError::new(
1230 "cannot call `end` after parsing has completed",
1231 offset,
1232 )),
1233 State::Module => {
1234 let mut state = self.module.take().unwrap();
1235 state.validate_end(offset)?;
1236
1237 if let Some(parent) = self.components.last_mut() {
1240 parent.add_core_module(&state.module, &mut self.types, offset)?;
1241 self.state = State::Component;
1242 }
1243
1244 Ok(Types::from_module(
1245 self.types.commit(),
1246 state.module.arc().clone(),
1247 ))
1248 }
1249 State::Component => {
1250 let mut component = self.components.pop().unwrap();
1251
1252 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1254 return Err(
1255 format_err!(offset,"value index {index} was not used as part of an instantiation, start function, or export"
1256 )
1257 );
1258 }
1259
1260 if let Some(parent) = self.components.last_mut() {
1263 parent.add_component(&mut component, &mut self.types);
1264 self.state = State::Component;
1265 }
1266
1267 Ok(Types::from_component(self.types.commit(), component))
1268 }
1269 }
1270 }
1271
1272 fn process_module_section<'a, T>(
1273 &mut self,
1274 order: Order,
1275 section: &SectionLimited<'a, T>,
1276 name: &str,
1277 validate_section: impl FnOnce(
1278 &mut ModuleState,
1279 &WasmFeatures,
1280 &mut TypeAlloc,
1281 u32,
1282 usize,
1283 ) -> Result<()>,
1284 mut validate_item: impl FnMut(
1285 &mut ModuleState,
1286 &WasmFeatures,
1287 &mut TypeAlloc,
1288 T,
1289 usize,
1290 ) -> Result<()>,
1291 ) -> Result<()>
1292 where
1293 T: FromReader<'a>,
1294 {
1295 let offset = section.range().start;
1296 self.state.ensure_module(name, offset)?;
1297
1298 let state = self.module.as_mut().unwrap();
1299 state.update_order(order, offset)?;
1300
1301 validate_section(
1302 state,
1303 &self.features,
1304 &mut self.types,
1305 section.count(),
1306 offset,
1307 )?;
1308
1309 for item in section.clone().into_iter_with_offsets() {
1310 let (offset, item) = item?;
1311 validate_item(state, &self.features, &mut self.types, item, offset)?;
1312 }
1313
1314 Ok(())
1315 }
1316
1317 fn process_component_section<'a, T>(
1318 &mut self,
1319 section: &SectionLimited<'a, T>,
1320 name: &str,
1321 validate_section: impl FnOnce(
1322 &mut Vec<ComponentState>,
1323 &mut TypeAlloc,
1324 u32,
1325 usize,
1326 ) -> Result<()>,
1327 mut validate_item: impl FnMut(
1328 &mut Vec<ComponentState>,
1329 &mut TypeAlloc,
1330 &WasmFeatures,
1331 T,
1332 usize,
1333 ) -> Result<()>,
1334 ) -> Result<()>
1335 where
1336 T: FromReader<'a>,
1337 {
1338 let offset = section.range().start;
1339
1340 if !self.features.component_model {
1341 return Err(BinaryReaderError::new(
1342 "component model feature is not enabled",
1343 offset,
1344 ));
1345 }
1346
1347 self.state.ensure_component(name, offset)?;
1348 validate_section(
1349 &mut self.components,
1350 &mut self.types,
1351 section.count(),
1352 offset,
1353 )?;
1354
1355 for item in section.clone().into_iter_with_offsets() {
1356 let (offset, item) = item?;
1357 validate_item(
1358 &mut self.components,
1359 &mut self.types,
1360 &self.features,
1361 item,
1362 offset,
1363 )?;
1364 }
1365
1366 Ok(())
1367 }
1368}
1369
1370#[cfg(test)]
1371mod tests {
1372 use crate::{GlobalType, MemoryType, RefType, TableType, ValType, Validator, WasmFeatures};
1373 use anyhow::Result;
1374
1375 #[test]
1376 fn test_module_type_information() -> Result<()> {
1377 let bytes = wat::parse_str(
1378 r#"
1379 (module
1380 (type (func (param i32 i64) (result i32)))
1381 (memory 1 5)
1382 (table 10 funcref)
1383 (global (mut i32) (i32.const 0))
1384 (func (type 0) (i32.const 0))
1385 (tag (param i64 i32))
1386 (elem funcref (ref.func 0))
1387 )
1388 "#,
1389 )?;
1390
1391 let mut validator = Validator::new_with_features(WasmFeatures {
1392 exceptions: true,
1393 ..Default::default()
1394 });
1395
1396 let types = validator.validate_all(&bytes)?;
1397
1398 assert_eq!(types.type_count(), 2);
1399 assert_eq!(types.memory_count(), 1);
1400 assert_eq!(types.table_count(), 1);
1401 assert_eq!(types.global_count(), 1);
1402 assert_eq!(types.function_count(), 1);
1403 assert_eq!(types.tag_count(), 1);
1404 assert_eq!(types.element_count(), 1);
1405 assert_eq!(types.module_count(), 0);
1406 assert_eq!(types.component_count(), 0);
1407 assert_eq!(types.instance_count(), 0);
1408 assert_eq!(types.value_count(), 0);
1409
1410 match types.func_type_at(0) {
1411 Some(ty) => {
1412 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1413 assert_eq!(ty.results(), [ValType::I32]);
1414 }
1415 _ => unreachable!(),
1416 }
1417
1418 match types.func_type_at(1) {
1419 Some(ty) => {
1420 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1421 assert_eq!(ty.results(), []);
1422 }
1423 _ => unreachable!(),
1424 }
1425
1426 assert_eq!(
1427 types.memory_at(0),
1428 Some(MemoryType {
1429 memory64: false,
1430 shared: false,
1431 initial: 1,
1432 maximum: Some(5)
1433 })
1434 );
1435
1436 assert_eq!(
1437 types.table_at(0),
1438 Some(TableType {
1439 initial: 10,
1440 maximum: None,
1441 element_type: RefType::FUNCREF,
1442 })
1443 );
1444
1445 assert_eq!(
1446 types.global_at(0),
1447 Some(GlobalType {
1448 content_type: ValType::I32,
1449 mutable: true
1450 })
1451 );
1452
1453 match types.function_at(0) {
1454 Some(ty) => {
1455 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1456 assert_eq!(ty.results(), [ValType::I32]);
1457 }
1458 _ => unreachable!(),
1459 }
1460
1461 match types.tag_at(0) {
1462 Some(ty) => {
1463 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1464 assert_eq!(ty.results(), []);
1465 }
1466 _ => unreachable!(),
1467 }
1468
1469 assert_eq!(types.element_at(0), Some(RefType::FUNCREF));
1470
1471 Ok(())
1472 }
1473
1474 #[test]
1475 fn test_type_id_aliasing() -> Result<()> {
1476 let bytes = wat::parse_str(
1477 r#"
1478 (component
1479 (type $T (list string))
1480 (alias outer 0 $T (type $A1))
1481 (alias outer 0 $T (type $A2))
1482 )
1483 "#,
1484 )?;
1485
1486 let mut validator = Validator::new_with_features(WasmFeatures {
1487 component_model: true,
1488 ..Default::default()
1489 });
1490
1491 let types = validator.validate_all(&bytes)?;
1492
1493 let t_id = types.id_from_type_index(0, false).unwrap();
1494 let a1_id = types.id_from_type_index(1, false).unwrap();
1495 let a2_id = types.id_from_type_index(2, false).unwrap();
1496
1497 assert!(t_id != a1_id);
1499 assert!(t_id != a2_id);
1500 assert!(a1_id != a2_id);
1501
1502 assert!(std::ptr::eq(
1504 types.type_from_id(t_id).unwrap(),
1505 types.type_from_id(a1_id).unwrap()
1506 ));
1507 assert!(std::ptr::eq(
1508 types.type_from_id(t_id).unwrap(),
1509 types.type_from_id(a2_id).unwrap()
1510 ));
1511
1512 Ok(())
1513 }
1514}