1use crate::{
17 limits::*, BinaryReaderError, Encoding, FromReader, FunctionBody, Parser, Payload, Result,
18 SectionLimited, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION,
19};
20use ::alloc::sync::Arc;
21use ::alloc::vec::Vec;
22use ::core::mem;
23use ::core::ops::Range;
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;
52mod operators;
53pub mod types;
54
55use self::component::*;
56pub use self::core::ValidatorResources;
57use self::core::*;
58use self::types::{TypeAlloc, Types, TypesRef};
59pub use func::{FuncToValidate, FuncValidator, FuncValidatorAllocations};
60pub use operators::{Frame, FrameKind};
61
62fn check_max(cur_len: usize, amt_added: u32, max: usize, desc: &str, offset: usize) -> Result<()> {
63 if max
64 .checked_sub(cur_len)
65 .and_then(|amt| amt.checked_sub(amt_added as usize))
66 .is_none()
67 {
68 if max == 1 {
69 bail!(offset, "multiple {desc}");
70 }
71
72 bail!(offset, "{desc} count exceeds limit of {max}");
73 }
74
75 Ok(())
76}
77
78fn combine_type_sizes(a: u32, b: u32, offset: usize) -> Result<u32> {
79 match a.checked_add(b) {
80 Some(sum) if sum < MAX_WASM_TYPE_SIZE => Ok(sum),
81 _ => Err(format_err!(
82 offset,
83 "effective type size exceeds the limit of {MAX_WASM_TYPE_SIZE}",
84 )),
85 }
86}
87
88#[derive(Default)]
114pub struct Validator {
115 state: State,
117
118 types: TypeAlloc,
120
121 module: Option<ModuleState>,
123
124 components: Vec<ComponentState>,
127
128 features: WasmFeatures,
131}
132
133#[derive(Debug, Clone, Copy, Eq, PartialEq)]
134enum State {
135 Unparsed(Option<Encoding>),
139 Module,
143 Component,
148 End,
150}
151
152impl State {
153 fn ensure_parsable(&self, offset: usize) -> Result<()> {
154 match self {
155 Self::Module | Self::Component => Ok(()),
156 Self::Unparsed(_) => Err(BinaryReaderError::new(
157 "unexpected section before header was parsed",
158 offset,
159 )),
160 Self::End => Err(BinaryReaderError::new(
161 "unexpected section after parsing has completed",
162 offset,
163 )),
164 }
165 }
166
167 fn ensure_module(&self, section: &str, offset: usize) -> Result<()> {
168 self.ensure_parsable(offset)?;
169
170 match self {
171 Self::Module => Ok(()),
172 Self::Component => Err(format_err!(
173 offset,
174 "unexpected module {section} section while parsing a component",
175 )),
176 _ => unreachable!(),
177 }
178 }
179
180 fn ensure_component(&self, section: &str, offset: usize) -> Result<()> {
181 self.ensure_parsable(offset)?;
182
183 match self {
184 Self::Component => Ok(()),
185 Self::Module => Err(format_err!(
186 offset,
187 "unexpected component {section} section while parsing a module",
188 )),
189 _ => unreachable!(),
190 }
191 }
192}
193
194impl Default for State {
195 fn default() -> Self {
196 Self::Unparsed(None)
197 }
198}
199
200#[derive(Hash, Debug, Copy, Clone)]
202pub struct WasmFeatures {
203 pub mutable_global: bool,
205 pub saturating_float_to_int: bool,
207 pub sign_extension: bool,
209 pub reference_types: bool,
211 pub multi_value: bool,
213 pub bulk_memory: bool,
215 pub simd: bool,
217 pub relaxed_simd: bool,
219 pub threads: bool,
221 pub tail_call: bool,
223 pub floats: bool,
234 pub multi_memory: bool,
236 pub exceptions: bool,
238 pub memory64: bool,
240 pub extended_const: bool,
242 pub component_model: bool,
244 pub memory_control: bool,
246}
247
248impl WasmFeatures {
249 pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> {
250 match ty {
251 ValType::I32 | ValType::I64 => Ok(()),
252 ValType::F32 | ValType::F64 => {
253 if self.floats {
254 Ok(())
255 } else {
256 Err("floating-point support is disabled")
257 }
258 }
259 ValType::FuncRef | ValType::ExternRef => {
260 if self.reference_types {
261 Ok(())
262 } else {
263 Err("reference types support is not enabled")
264 }
265 }
266 ValType::V128 => {
267 if self.simd {
268 Ok(())
269 } else {
270 Err("SIMD support is not enabled")
271 }
272 }
273 }
274 }
275}
276
277impl Default for WasmFeatures {
278 fn default() -> WasmFeatures {
279 WasmFeatures {
280 relaxed_simd: false,
282 threads: false,
283 multi_memory: false,
284 exceptions: false,
285 memory64: false,
286 extended_const: false,
287 component_model: false,
288 memory_control: false,
289
290 mutable_global: true,
292 saturating_float_to_int: true,
293 sign_extension: true,
294 bulk_memory: true,
295 multi_value: true,
296 reference_types: true,
297 tail_call: true,
298 simd: true,
299 floats: true,
300 }
301 }
302}
303
304#[allow(clippy::large_enum_variant)]
306pub enum ValidPayload<'a> {
307 Ok,
309 Parser(Parser),
314 Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>),
316 End(Types),
319}
320
321impl Validator {
322 pub fn new() -> Validator {
329 Validator::default()
330 }
331
332 pub fn new_with_features(features: WasmFeatures) -> Validator {
340 let mut ret = Validator::new();
341 ret.features = features;
342 ret
343 }
344
345 pub fn features(&self) -> &WasmFeatures {
347 &self.features
348 }
349
350 pub fn validate_all(&mut self, bytes: &[u8]) -> Result<Types> {
359 let mut functions_to_validate = Vec::new();
360 let mut last_types = None;
361 for payload in Parser::new(0).parse_all(bytes) {
362 match self.payload(&payload?)? {
363 ValidPayload::Func(a, b) => {
364 functions_to_validate.push((a, b));
365 }
366 ValidPayload::End(types) => {
367 last_types = Some(types);
369 }
370 _ => {}
371 }
372 }
373
374 let mut allocs = FuncValidatorAllocations::default();
375 for (func, body) in functions_to_validate {
376 let mut validator = func.into_validator(allocs);
377 validator.validate(&body)?;
378 allocs = validator.into_allocations();
379 }
380
381 Ok(last_types.unwrap())
382 }
383
384 pub fn types(&self, mut level: usize) -> Option<TypesRef> {
394 if let Some(module) = &self.module {
395 if level == 0 {
396 return Some(TypesRef::from_module(&self.types, &module.module));
397 } else {
398 level -= 1;
399 }
400 }
401
402 self.components
403 .iter()
404 .nth_back(level)
405 .map(|component| TypesRef::from_component(&self.types, component))
406 }
407
408 pub fn payload<'a>(&mut self, payload: &Payload<'a>) -> Result<ValidPayload<'a>> {
422 use crate::Payload::*;
423 match payload {
424 Version {
425 num,
426 encoding,
427 range,
428 } => self.version(*num, *encoding, range)?,
429
430 TypeSection(s) => self.type_section(s)?,
432 ImportSection(s) => self.import_section(s)?,
433 FunctionSection(s) => self.function_section(s)?,
434 TableSection(s) => self.table_section(s)?,
435 MemorySection(s) => self.memory_section(s)?,
436 TagSection(s) => self.tag_section(s)?,
437 GlobalSection(s) => self.global_section(s)?,
438 ExportSection(s) => self.export_section(s)?,
439 StartSection { func, range } => self.start_section(*func, range)?,
440 ElementSection(s) => self.element_section(s)?,
441 DataCountSection { count, range } => self.data_count_section(*count, range)?,
442 CodeSectionStart {
443 count,
444 range,
445 size: _,
446 } => self.code_section_start(*count, range)?,
447 CodeSectionEntry(body) => {
448 let func_validator = self.code_section_entry(body)?;
449 return Ok(ValidPayload::Func(func_validator, body.clone()));
450 }
451 DataSection(s) => self.data_section(s)?,
452
453 ModuleSection { parser, range, .. } => {
455 self.module_section(range)?;
456 return Ok(ValidPayload::Parser(parser.clone()));
457 }
458 InstanceSection(s) => self.instance_section(s)?,
459 CoreTypeSection(s) => self.core_type_section(s)?,
460 ComponentSection { parser, range, .. } => {
461 self.component_section(range)?;
462 return Ok(ValidPayload::Parser(parser.clone()));
463 }
464 ComponentInstanceSection(s) => self.component_instance_section(s)?,
465 ComponentAliasSection(s) => self.component_alias_section(s)?,
466 ComponentTypeSection(s) => self.component_type_section(s)?,
467 ComponentCanonicalSection(s) => self.component_canonical_section(s)?,
468 ComponentStartSection { start, range } => self.component_start_section(start, range)?,
469 ComponentImportSection(s) => self.component_import_section(s)?,
470 ComponentExportSection(s) => self.component_export_section(s)?,
471
472 End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)),
473
474 CustomSection { .. } => {} UnknownSection { id, range, .. } => self.unknown_section(*id, range)?,
476 }
477 Ok(ValidPayload::Ok)
478 }
479
480 pub fn version(&mut self, num: u16, encoding: Encoding, range: &Range<usize>) -> Result<()> {
482 match &self.state {
483 State::Unparsed(expected) => {
484 if let Some(expected) = expected {
485 if *expected != encoding {
486 bail!(
487 range.start,
488 "expected a version header for a {}",
489 match expected {
490 Encoding::Module => "module",
491 Encoding::Component => "component",
492 }
493 );
494 }
495 }
496 }
497 _ => {
498 return Err(BinaryReaderError::new(
499 "wasm version header out of order",
500 range.start,
501 ))
502 }
503 }
504
505 self.state = match encoding {
506 Encoding::Module => {
507 if num == WASM_MODULE_VERSION {
508 assert!(self.module.is_none());
509 self.module = Some(ModuleState::default());
510 State::Module
511 } else {
512 bail!(range.start, "unknown binary version: {num:#x}");
513 }
514 }
515 Encoding::Component => {
516 if !self.features.component_model {
517 bail!(
518 range.start,
519 "unknown binary version: {num:#x}, \
520 note: the WebAssembly component model feature is not enabled",
521 );
522 }
523 if num == WASM_COMPONENT_VERSION {
524 self.components.push(ComponentState::default());
525 State::Component
526 } else if num < WASM_COMPONENT_VERSION {
527 bail!(range.start, "unsupported component version: {num:#x}");
528 } else {
529 bail!(range.start, "unknown component version: {num:#x}");
530 }
531 }
532 };
533
534 Ok(())
535 }
536
537 pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> {
539 self.process_module_section(
540 Order::Type,
541 section,
542 "type",
543 |state, _, types, count, offset| {
544 check_max(
545 state.module.types.len(),
546 count,
547 MAX_WASM_TYPES,
548 "types",
549 offset,
550 )?;
551 types.reserve(count as usize);
552 state.module.assert_mut().types.reserve(count as usize);
553 Ok(())
554 },
555 |state, features, types, def, offset| {
556 state
557 .module
558 .assert_mut()
559 .add_type(def, features, types, offset, false )
560 },
561 )
562 }
563
564 pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> {
568 self.process_module_section(
569 Order::Import,
570 section,
571 "import",
572 |_, _, _, _, _| Ok(()), |state, features, types, import, offset| {
574 state
575 .module
576 .assert_mut()
577 .add_import(import, features, types, offset)
578 },
579 )
580 }
581
582 pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> {
586 self.process_module_section(
587 Order::Function,
588 section,
589 "function",
590 |state, _, _, count, offset| {
591 check_max(
592 state.module.functions.len(),
593 count,
594 MAX_WASM_FUNCTIONS,
595 "functions",
596 offset,
597 )?;
598 state.module.assert_mut().functions.reserve(count as usize);
599 debug_assert!(state.expected_code_bodies.is_none());
600 state.expected_code_bodies = Some(count);
601 Ok(())
602 },
603 |state, _, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset),
604 )
605 }
606
607 pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> {
611 let features = self.features;
612 self.process_module_section(
613 Order::Table,
614 section,
615 "table",
616 |state, _, _, count, offset| {
617 check_max(
618 state.module.tables.len(),
619 count,
620 state.module.max_tables(&features),
621 "tables",
622 offset,
623 )?;
624 state.module.assert_mut().tables.reserve(count as usize);
625 Ok(())
626 },
627 |state, features, _, ty, offset| {
628 state.module.assert_mut().add_table(ty, features, offset)
629 },
630 )
631 }
632
633 pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> {
637 self.process_module_section(
638 Order::Memory,
639 section,
640 "memory",
641 |state, features, _, count, offset| {
642 check_max(
643 state.module.memories.len(),
644 count,
645 state.module.max_memories(features),
646 "memories",
647 offset,
648 )?;
649 state.module.assert_mut().memories.reserve(count as usize);
650 Ok(())
651 },
652 |state, features, _, ty, offset| {
653 state.module.assert_mut().add_memory(ty, features, offset)
654 },
655 )
656 }
657
658 pub fn tag_section(&mut self, section: &crate::TagSectionReader<'_>) -> Result<()> {
662 if !self.features.exceptions {
663 return Err(BinaryReaderError::new(
664 "exceptions proposal not enabled",
665 section.range().start,
666 ));
667 }
668
669 self.process_module_section(
670 Order::Tag,
671 section,
672 "tag",
673 |state, _, _, count, offset| {
674 check_max(
675 state.module.tags.len(),
676 count,
677 MAX_WASM_TAGS,
678 "tags",
679 offset,
680 )?;
681 state.module.assert_mut().tags.reserve(count as usize);
682 Ok(())
683 },
684 |state, features, types, ty, offset| {
685 state
686 .module
687 .assert_mut()
688 .add_tag(ty, features, types, offset)
689 },
690 )
691 }
692
693 pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> {
697 self.process_module_section(
698 Order::Global,
699 section,
700 "global",
701 |state, _, _, count, offset| {
702 check_max(
703 state.module.globals.len(),
704 count,
705 MAX_WASM_GLOBALS,
706 "globals",
707 offset,
708 )?;
709 state.module.assert_mut().globals.reserve(count as usize);
710 Ok(())
711 },
712 |state, features, types, global, offset| {
713 state.add_global(global, features, types, offset)
714 },
715 )
716 }
717
718 pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> {
722 self.process_module_section(
723 Order::Export,
724 section,
725 "export",
726 |state, _, _, count, offset| {
727 check_max(
728 state.module.exports.len(),
729 count,
730 MAX_WASM_EXPORTS,
731 "exports",
732 offset,
733 )?;
734 state.module.assert_mut().exports.reserve(count as usize);
735 Ok(())
736 },
737 |state, features, _, e, offset| {
738 let state = state.module.assert_mut();
739 let ty = state.export_to_entity_type(&e, offset)?;
740 state.add_export(e.name, ty, features, offset, false )
741 },
742 )
743 }
744
745 pub fn start_section(&mut self, func: u32, range: &Range<usize>) -> Result<()> {
749 let offset = range.start;
750 self.state.ensure_module("start", offset)?;
751 let state = self.module.as_mut().unwrap();
752 state.update_order(Order::Start, offset)?;
753
754 let ty = state.module.get_func_type(func, &self.types, offset)?;
755 if !ty.params().is_empty() || !ty.results().is_empty() {
756 return Err(BinaryReaderError::new(
757 "invalid start function type",
758 offset,
759 ));
760 }
761
762 Ok(())
763 }
764
765 pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> {
769 self.process_module_section(
770 Order::Element,
771 section,
772 "element",
773 |state, _, _, count, offset| {
774 check_max(
775 state.module.element_types.len(),
776 count,
777 MAX_WASM_ELEMENT_SEGMENTS,
778 "element segments",
779 offset,
780 )?;
781 state
782 .module
783 .assert_mut()
784 .element_types
785 .reserve(count as usize);
786 Ok(())
787 },
788 |state, features, types, e, offset| {
789 state.add_element_segment(e, features, types, offset)
790 },
791 )
792 }
793
794 pub fn data_count_section(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
798 let offset = range.start;
799 self.state.ensure_module("data count", offset)?;
800
801 let state = self.module.as_mut().unwrap();
802 state.update_order(Order::DataCount, offset)?;
803
804 if count > MAX_WASM_DATA_SEGMENTS as u32 {
805 return Err(BinaryReaderError::new(
806 "data count section specifies too many data segments",
807 offset,
808 ));
809 }
810
811 state.module.assert_mut().data_count = Some(count);
812 Ok(())
813 }
814
815 pub fn code_section_start(&mut self, count: u32, range: &Range<usize>) -> Result<()> {
819 let offset = range.start;
820 self.state.ensure_module("code", offset)?;
821
822 let state = self.module.as_mut().unwrap();
823 state.update_order(Order::Code, offset)?;
824
825 match state.expected_code_bodies.take() {
826 Some(n) if n == count => {}
827 Some(_) => {
828 return Err(BinaryReaderError::new(
829 "function and code section have inconsistent lengths",
830 offset,
831 ));
832 }
833 None if count == 0 => {}
836 None => {
837 return Err(BinaryReaderError::new(
838 "code section without function section",
839 offset,
840 ))
841 }
842 }
843
844 state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit()));
846
847 Ok(())
848 }
849
850 pub fn code_section_entry(
864 &mut self,
865 body: &crate::FunctionBody,
866 ) -> Result<FuncToValidate<ValidatorResources>> {
867 let offset = body.range().start;
868 self.state.ensure_module("code", offset)?;
869
870 let state = self.module.as_mut().unwrap();
871
872 let (index, ty) = state.next_code_index_and_type(offset)?;
873 Ok(FuncToValidate::new(
874 index,
875 ty,
876 ValidatorResources(state.module.arc().clone()),
877 &self.features,
878 ))
879 }
880
881 pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> {
885 self.process_module_section(
886 Order::Data,
887 section,
888 "data",
889 |state, _, _, count, offset| {
890 state.data_segment_count = count;
891 check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset)
892 },
893 |state, features, types, d, offset| state.add_data_segment(d, features, types, offset),
894 )
895 }
896
897 pub fn module_section(&mut self, range: &Range<usize>) -> Result<()> {
901 self.state.ensure_component("module", range.start)?;
902
903 let current = self.components.last_mut().unwrap();
904 check_max(
905 current.core_modules.len(),
906 1,
907 MAX_WASM_MODULES,
908 "modules",
909 range.start,
910 )?;
911
912 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) {
913 State::Component => {}
914 _ => unreachable!(),
915 }
916
917 Ok(())
918 }
919
920 pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> {
924 self.process_component_section(
925 section,
926 "core instance",
927 |components, _, count, offset| {
928 let current = components.last_mut().unwrap();
929 check_max(
930 current.instance_count(),
931 count,
932 MAX_WASM_INSTANCES,
933 "instances",
934 offset,
935 )?;
936 current.core_instances.reserve(count as usize);
937 Ok(())
938 },
939 |components, types, _, instance, offset| {
940 components
941 .last_mut()
942 .unwrap()
943 .add_core_instance(instance, types, offset)
944 },
945 )
946 }
947
948 pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> {
952 self.process_component_section(
953 section,
954 "core type",
955 |components, types, count, offset| {
956 let current = components.last_mut().unwrap();
957 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
958 types.reserve(count as usize);
959 current.core_types.reserve(count as usize);
960 Ok(())
961 },
962 |components, types, features, ty, offset| {
963 ComponentState::add_core_type(
964 components, ty, features, types, offset, false, )
966 },
967 )
968 }
969
970 pub fn component_section(&mut self, range: &Range<usize>) -> Result<()> {
974 self.state.ensure_component("component", range.start)?;
975
976 let current = self.components.last_mut().unwrap();
977 check_max(
978 current.components.len(),
979 1,
980 MAX_WASM_COMPONENTS,
981 "components",
982 range.start,
983 )?;
984
985 match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) {
986 State::Component => {}
987 _ => unreachable!(),
988 }
989
990 Ok(())
991 }
992
993 pub fn component_instance_section(
997 &mut self,
998 section: &crate::ComponentInstanceSectionReader,
999 ) -> Result<()> {
1000 self.process_component_section(
1001 section,
1002 "instance",
1003 |components, _, count, offset| {
1004 let current = components.last_mut().unwrap();
1005 check_max(
1006 current.instance_count(),
1007 count,
1008 MAX_WASM_INSTANCES,
1009 "instances",
1010 offset,
1011 )?;
1012 current.instances.reserve(count as usize);
1013 Ok(())
1014 },
1015 |components, types, _, instance, offset| {
1016 components
1017 .last_mut()
1018 .unwrap()
1019 .add_instance(instance, types, offset)
1020 },
1021 )
1022 }
1023
1024 pub fn component_alias_section(
1028 &mut self,
1029 section: &crate::ComponentAliasSectionReader<'_>,
1030 ) -> Result<()> {
1031 self.process_component_section(
1032 section,
1033 "alias",
1034 |_, _, _, _| Ok(()), |components, types, _, alias, offset| -> Result<(), BinaryReaderError> {
1036 ComponentState::add_alias(components, alias, types, offset)
1037 },
1038 )
1039 }
1040
1041 pub fn component_type_section(
1045 &mut self,
1046 section: &crate::ComponentTypeSectionReader,
1047 ) -> Result<()> {
1048 self.process_component_section(
1049 section,
1050 "type",
1051 |components, types, count, offset| {
1052 let current = components.last_mut().unwrap();
1053 check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?;
1054 types.reserve(count as usize);
1055 current.types.reserve(count as usize);
1056 Ok(())
1057 },
1058 |components, types, features, ty, offset| {
1059 ComponentState::add_type(
1060 components, ty, features, types, offset, false, )
1062 },
1063 )
1064 }
1065
1066 pub fn component_canonical_section(
1070 &mut self,
1071 section: &crate::ComponentCanonicalSectionReader,
1072 ) -> Result<()> {
1073 self.process_component_section(
1074 section,
1075 "function",
1076 |components, _, count, offset| {
1077 let current = components.last_mut().unwrap();
1078 check_max(
1079 current.function_count(),
1080 count,
1081 MAX_WASM_FUNCTIONS,
1082 "functions",
1083 offset,
1084 )?;
1085 current.funcs.reserve(count as usize);
1086 Ok(())
1087 },
1088 |components, types, _, func, offset| {
1089 let current = components.last_mut().unwrap();
1090 match func {
1091 crate::CanonicalFunction::Lift {
1092 core_func_index,
1093 type_index,
1094 options,
1095 } => current.lift_function(
1096 core_func_index,
1097 type_index,
1098 options.into_vec(),
1099 types,
1100 offset,
1101 ),
1102 crate::CanonicalFunction::Lower {
1103 func_index,
1104 options,
1105 } => current.lower_function(func_index, options.into_vec(), types, offset),
1106 }
1107 },
1108 )
1109 }
1110
1111 pub fn component_start_section(
1115 &mut self,
1116 f: &crate::ComponentStartFunction,
1117 range: &Range<usize>,
1118 ) -> Result<()> {
1119 self.state.ensure_component("start", range.start)?;
1120
1121 self.components.last_mut().unwrap().add_start(
1132 f.func_index,
1133 &f.arguments,
1134 f.results,
1135 &self.types,
1136 range.start,
1137 )
1138 }
1139
1140 pub fn component_import_section(
1144 &mut self,
1145 section: &crate::ComponentImportSectionReader,
1146 ) -> Result<()> {
1147 self.process_component_section(
1148 section,
1149 "import",
1150 |_, _, _, _| Ok(()), |components, types, _, import, offset| {
1152 components
1153 .last_mut()
1154 .unwrap()
1155 .add_import(import, types, offset)
1156 },
1157 )
1158 }
1159
1160 pub fn component_export_section(
1164 &mut self,
1165 section: &crate::ComponentExportSectionReader,
1166 ) -> Result<()> {
1167 self.process_component_section(
1168 section,
1169 "export",
1170 |components, _, count, offset| {
1171 let current = components.last_mut().unwrap();
1172 check_max(
1173 current.exports.len(),
1174 count,
1175 MAX_WASM_EXPORTS,
1176 "exports",
1177 offset,
1178 )?;
1179 current.exports.reserve(count as usize);
1180 Ok(())
1181 },
1182 |components, types, _, export, offset| {
1183 let current = components.last_mut().unwrap();
1184 let ty = current.export_to_entity_type(&export, types, offset)?;
1185 current.add_export(
1186 export.name,
1187 export.url,
1188 ty,
1189 offset,
1190 false, )
1192 },
1193 )
1194 }
1195
1196 pub fn unknown_section(&mut self, id: u8, range: &Range<usize>) -> Result<()> {
1200 Err(format_err!(range.start, "malformed section id: {id}"))
1201 }
1202
1203 pub fn end(&mut self, offset: usize) -> Result<Types> {
1207 match ::core::mem::replace(&mut self.state, State::End) {
1208 State::Unparsed(_) => Err(BinaryReaderError::new(
1209 "cannot call `end` before a header has been parsed",
1210 offset,
1211 )),
1212 State::End => Err(BinaryReaderError::new(
1213 "cannot call `end` after parsing has completed",
1214 offset,
1215 )),
1216 State::Module => {
1217 let mut state = self.module.take().unwrap();
1218 state.validate_end(offset)?;
1219
1220 if let Some(parent) = self.components.last_mut() {
1223 parent.add_core_module(&state.module, &mut self.types, offset)?;
1224 self.state = State::Component;
1225 }
1226
1227 Ok(Types::from_module(
1228 self.types.commit(),
1229 state.module.arc().clone(),
1230 ))
1231 }
1232 State::Component => {
1233 let mut component = self.components.pop().unwrap();
1234
1235 if let Some(index) = component.values.iter().position(|(_, used)| !*used) {
1237 return Err(
1238 format_err!(offset,"value index {index} was not used as part of an instantiation, start function, or export"
1239 )
1240 );
1241 }
1242
1243 if let Some(parent) = self.components.last_mut() {
1246 parent.add_component(&mut component, &mut self.types);
1247 self.state = State::Component;
1248 }
1249
1250 Ok(Types::from_component(self.types.commit(), component))
1251 }
1252 }
1253 }
1254
1255 fn process_module_section<'a, T>(
1256 &mut self,
1257 order: Order,
1258 section: &SectionLimited<'a, T>,
1259 name: &str,
1260 validate_section: impl FnOnce(
1261 &mut ModuleState,
1262 &WasmFeatures,
1263 &mut TypeAlloc,
1264 u32,
1265 usize,
1266 ) -> Result<()>,
1267 mut validate_item: impl FnMut(
1268 &mut ModuleState,
1269 &WasmFeatures,
1270 &mut TypeAlloc,
1271 T,
1272 usize,
1273 ) -> Result<()>,
1274 ) -> Result<()>
1275 where
1276 T: FromReader<'a>,
1277 {
1278 let offset = section.range().start;
1279 self.state.ensure_module(name, offset)?;
1280
1281 let state = self.module.as_mut().unwrap();
1282 state.update_order(order, offset)?;
1283
1284 validate_section(
1285 state,
1286 &self.features,
1287 &mut self.types,
1288 section.count(),
1289 offset,
1290 )?;
1291
1292 for item in section.clone().into_iter_with_offsets() {
1293 let (offset, item) = item?;
1294 validate_item(state, &self.features, &mut self.types, item, offset)?;
1295 }
1296
1297 Ok(())
1298 }
1299
1300 fn process_component_section<'a, T>(
1301 &mut self,
1302 section: &SectionLimited<'a, T>,
1303 name: &str,
1304 validate_section: impl FnOnce(
1305 &mut Vec<ComponentState>,
1306 &mut TypeAlloc,
1307 u32,
1308 usize,
1309 ) -> Result<()>,
1310 mut validate_item: impl FnMut(
1311 &mut Vec<ComponentState>,
1312 &mut TypeAlloc,
1313 &WasmFeatures,
1314 T,
1315 usize,
1316 ) -> Result<()>,
1317 ) -> Result<()>
1318 where
1319 T: FromReader<'a>,
1320 {
1321 let offset = section.range().start;
1322
1323 if !self.features.component_model {
1324 return Err(BinaryReaderError::new(
1325 "component model feature is not enabled",
1326 offset,
1327 ));
1328 }
1329
1330 self.state.ensure_component(name, offset)?;
1331 validate_section(
1332 &mut self.components,
1333 &mut self.types,
1334 section.count(),
1335 offset,
1336 )?;
1337
1338 for item in section.clone().into_iter_with_offsets() {
1339 let (offset, item) = item?;
1340 validate_item(
1341 &mut self.components,
1342 &mut self.types,
1343 &self.features,
1344 item,
1345 offset,
1346 )?;
1347 }
1348
1349 Ok(())
1350 }
1351}
1352
1353#[cfg(test)]
1354mod tests {
1355 use crate::{GlobalType, MemoryType, TableType, ValType, Validator, WasmFeatures};
1356 use anyhow::Result;
1357
1358 #[test]
1359 fn test_module_type_information() -> Result<()> {
1360 let bytes = wat::parse_str(
1361 r#"
1362 (module
1363 (type (func (param i32 i64) (result i32)))
1364 (memory 1 5)
1365 (table 10 funcref)
1366 (global (mut i32) (i32.const 0))
1367 (func (type 0) (i32.const 0))
1368 (tag (param i64 i32))
1369 (elem funcref (ref.func 0))
1370 )
1371 "#,
1372 )?;
1373
1374 let mut validator = Validator::new_with_features(WasmFeatures {
1375 exceptions: true,
1376 ..Default::default()
1377 });
1378
1379 let types = validator.validate_all(&bytes)?;
1380
1381 assert_eq!(types.type_count(), 2);
1382 assert_eq!(types.memory_count(), 1);
1383 assert_eq!(types.table_count(), 1);
1384 assert_eq!(types.global_count(), 1);
1385 assert_eq!(types.function_count(), 1);
1386 assert_eq!(types.tag_count(), 1);
1387 assert_eq!(types.element_count(), 1);
1388 assert_eq!(types.module_count(), 0);
1389 assert_eq!(types.component_count(), 0);
1390 assert_eq!(types.instance_count(), 0);
1391 assert_eq!(types.value_count(), 0);
1392
1393 match types.func_type_at(0) {
1394 Some(ty) => {
1395 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1396 assert_eq!(ty.results(), [ValType::I32]);
1397 }
1398 _ => unreachable!(),
1399 }
1400
1401 match types.func_type_at(1) {
1402 Some(ty) => {
1403 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1404 assert_eq!(ty.results(), []);
1405 }
1406 _ => unreachable!(),
1407 }
1408
1409 assert_eq!(
1410 types.memory_at(0),
1411 Some(MemoryType {
1412 memory64: false,
1413 shared: false,
1414 initial: 1,
1415 maximum: Some(5)
1416 })
1417 );
1418
1419 assert_eq!(
1420 types.table_at(0),
1421 Some(TableType {
1422 initial: 10,
1423 maximum: None,
1424 element_type: ValType::FuncRef,
1425 })
1426 );
1427
1428 assert_eq!(
1429 types.global_at(0),
1430 Some(GlobalType {
1431 content_type: ValType::I32,
1432 mutable: true
1433 })
1434 );
1435
1436 match types.function_at(0) {
1437 Some(ty) => {
1438 assert_eq!(ty.params(), [ValType::I32, ValType::I64]);
1439 assert_eq!(ty.results(), [ValType::I32]);
1440 }
1441 _ => unreachable!(),
1442 }
1443
1444 match types.tag_at(0) {
1445 Some(ty) => {
1446 assert_eq!(ty.params(), [ValType::I64, ValType::I32]);
1447 assert_eq!(ty.results(), []);
1448 }
1449 _ => unreachable!(),
1450 }
1451
1452 assert_eq!(types.element_at(0), Some(ValType::FuncRef));
1453
1454 Ok(())
1455 }
1456
1457 #[test]
1458 fn test_type_id_aliasing() -> Result<()> {
1459 let bytes = wat::parse_str(
1460 r#"
1461 (component
1462 (type $T (list string))
1463 (alias outer 0 $T (type $A1))
1464 (alias outer 0 $T (type $A2))
1465 )
1466 "#,
1467 )?;
1468
1469 let mut validator = Validator::new_with_features(WasmFeatures {
1470 component_model: true,
1471 ..Default::default()
1472 });
1473
1474 let types = validator.validate_all(&bytes)?;
1475
1476 let t_id = types.id_from_type_index(0, false).unwrap();
1477 let a1_id = types.id_from_type_index(1, false).unwrap();
1478 let a2_id = types.id_from_type_index(2, false).unwrap();
1479
1480 assert!(t_id != a1_id);
1482 assert!(t_id != a2_id);
1483 assert!(a1_id != a2_id);
1484
1485 assert!(::core::ptr::eq(
1487 types.type_from_id(t_id).unwrap(),
1488 types.type_from_id(a1_id).unwrap()
1489 ));
1490 assert!(::core::ptr::eq(
1491 types.type_from_id(t_id).unwrap(),
1492 types.type_from_id(a2_id).unwrap()
1493 ));
1494
1495 Ok(())
1496 }
1497}