1use crate::{
22 gas_metering::{CustomConstantCostRules, Rules},
23 ids::{prelude::*, CodeId},
24 message::DispatchKind,
25 pages::{WasmPage, WasmPagesAmount},
26};
27use alloc::{collections::BTreeSet, vec::Vec};
28use gear_wasm_instrument::{InstrumentationBuilder, Module, GEAR_SUPPORTED_FEATURES};
29
30mod errors;
31mod instrumented;
32mod utils;
33
34pub use errors::*;
35pub use instrumented::*;
36pub use utils::{ALLOWED_EXPORTS, MAX_WASM_PAGES_AMOUNT, REQUIRED_EXPORTS};
37
38use utils::CodeTypeSectionSizes;
39
40const GENERIC_OS_PAGE_SIZE: u32 = 4096;
42
43#[derive(Clone, Debug, PartialEq, Eq)]
45pub struct Code {
46 code: Vec<u8>,
48 original_code: Vec<u8>,
50 exports: BTreeSet<DispatchKind>,
52 static_pages: WasmPagesAmount,
54 stack_end: Option<WasmPage>,
56 instruction_weights_version: u32,
58 instantiated_section_sizes: InstantiatedSectionSizes,
60}
61
62pub struct TryNewCodeConfig {
65 pub version: u32,
67 pub stack_height: Option<u32>,
69 pub data_segments_amount_limit: Option<u32>,
71 pub export_stack_height: bool,
73 pub check_exports: bool,
75 pub check_imports: bool,
77 pub check_and_canonize_stack_end: bool,
79 pub check_mut_global_exports: bool,
81 pub check_start_section: bool,
83 pub check_data_section: bool,
85 pub check_table_section: bool,
87 pub make_validation: bool,
89}
90
91impl Default for TryNewCodeConfig {
92 fn default() -> Self {
93 Self {
94 version: 1,
95 stack_height: None,
96 data_segments_amount_limit: None,
97 export_stack_height: false,
98 check_exports: true,
99 check_imports: true,
100 check_and_canonize_stack_end: true,
101 check_mut_global_exports: true,
102 check_start_section: true,
103 check_data_section: true,
104 check_table_section: true,
105 make_validation: true,
106 }
107 }
108}
109
110impl TryNewCodeConfig {
111 pub fn new_no_exports_check() -> Self {
113 Self {
114 check_exports: false,
115 ..Default::default()
116 }
117 }
118}
119
120impl Code {
121 fn try_new_internal<R, GetRulesFn>(
123 original_code: Vec<u8>,
124 get_gas_rules: Option<GetRulesFn>,
125 config: TryNewCodeConfig,
126 ) -> Result<Self, CodeError>
127 where
128 R: Rules,
129 GetRulesFn: FnMut(&Module) -> R,
130 {
131 if config.make_validation {
132 wasmparser::Validator::new_with_features(GEAR_SUPPORTED_FEATURES)
133 .validate_all(&original_code)
134 .map_err(CodeError::Validation)?;
135 }
136
137 let mut module = Module::new(&original_code)?;
138
139 let static_pages = utils::get_static_pages(&module)?;
140
141 let stack_end = match config.check_and_canonize_stack_end {
143 true => utils::check_and_canonize_gear_stack_end(&mut module, static_pages)?,
144 false => None,
145 };
146
147 if config.check_data_section {
149 utils::check_data_section(
150 &module,
151 static_pages,
152 stack_end,
153 config.data_segments_amount_limit,
154 )?;
155 }
156 if config.check_mut_global_exports {
157 utils::check_mut_global_exports(&module)?;
158 }
159 if config.check_start_section {
160 utils::check_start_section(&module)?;
161 }
162 if config.check_exports {
163 utils::check_exports(&module)?;
164 }
165 if config.check_imports {
166 utils::check_imports(&module)?;
167 }
168
169 let exports = utils::get_exports(&module);
171
172 let mut instrumentation_builder = InstrumentationBuilder::new("env");
173 if let Some(stack_limit) = config.stack_height {
174 instrumentation_builder.with_stack_limiter(stack_limit, config.export_stack_height);
175 }
176 if let Some(get_gas_rules) = get_gas_rules {
177 instrumentation_builder.with_gas_limiter(get_gas_rules);
178 }
179 module = instrumentation_builder.instrument(module)?;
180
181 let data_section_size = utils::get_data_section_size(&module)?;
183 let global_section_size = utils::get_instantiated_global_section_size(&module)?;
184 let table_section_size = utils::get_instantiated_table_section_size(&module);
185 let element_section_size = utils::get_instantiated_element_section_size(&module)?;
186
187 let code = module.serialize()?;
188
189 let CodeTypeSectionSizes {
191 code_section,
192 type_section,
193 } = utils::get_code_type_sections_sizes(&code)?;
194
195 Ok(Self {
196 code,
197 original_code,
198 exports,
199 static_pages,
200 stack_end,
201 instruction_weights_version: config.version,
202 instantiated_section_sizes: InstantiatedSectionSizes {
203 code_section,
204 data_section: data_section_size,
205 global_section: global_section_size,
206 table_section: table_section_size,
207 element_section: element_section_size,
208 type_section,
209 },
210 })
211 }
212
213 pub fn try_new<R, GetRulesFn>(
290 original_code: Vec<u8>,
291 version: u32,
292 get_gas_rules: GetRulesFn,
293 stack_height: Option<u32>,
294 data_segments_amount_limit: Option<u32>,
295 ) -> Result<Self, CodeError>
296 where
297 R: Rules,
298 GetRulesFn: FnMut(&Module) -> R,
299 {
300 Self::try_new_internal(
301 original_code,
302 Some(get_gas_rules),
303 TryNewCodeConfig {
304 version,
305 stack_height,
306 data_segments_amount_limit,
307 ..Default::default()
308 },
309 )
310 }
311
312 pub fn try_new_mock_const_or_no_rules(
314 original_code: Vec<u8>,
315 const_rules: bool,
316 config: TryNewCodeConfig,
317 ) -> Result<Self, CodeError> {
318 let get_gas_rules =
319 const_rules.then_some(|_module: &Module| CustomConstantCostRules::default());
320 Self::try_new_internal(original_code, get_gas_rules, config)
321 }
322
323 pub fn try_new_mock_with_rules<R, GetRulesFn>(
325 original_code: Vec<u8>,
326 get_gas_rules: GetRulesFn,
327 config: TryNewCodeConfig,
328 ) -> Result<Self, CodeError>
329 where
330 R: Rules,
331 GetRulesFn: FnMut(&Module) -> R,
332 {
333 Self::try_new_internal(original_code, Some(get_gas_rules), config)
334 }
335
336 pub fn original_code(&self) -> &[u8] {
338 &self.original_code
339 }
340
341 pub fn code(&self) -> &[u8] {
343 &self.code
344 }
345
346 pub fn exports(&self) -> &BTreeSet<DispatchKind> {
348 &self.exports
349 }
350
351 pub fn instruction_weights_version(&self) -> u32 {
353 self.instruction_weights_version
354 }
355
356 pub fn static_pages(&self) -> WasmPagesAmount {
358 self.static_pages
359 }
360
361 pub fn into_parts(self) -> (InstrumentedCode, Vec<u8>) {
363 let original_code_len = self.original_code.len() as u32;
364 (
365 InstrumentedCode {
366 code: self.code,
367 original_code_len,
368 exports: self.exports,
369 static_pages: self.static_pages,
370 stack_end: self.stack_end,
371 instantiated_section_sizes: self.instantiated_section_sizes,
372 version: self.instruction_weights_version,
373 },
374 self.original_code,
375 )
376 }
377}
378
379#[derive(Clone, Debug)]
381pub struct CodeAndId {
382 code: Code,
383 code_id: CodeId,
384}
385
386impl CodeAndId {
387 pub fn new(code: Code) -> Self {
389 let code_id = CodeId::generate(code.original_code());
390 Self { code, code_id }
391 }
392
393 pub fn from_parts_unchecked(code: Code, code_id: CodeId) -> Self {
395 debug_assert_eq!(code_id, CodeId::generate(code.original_code()));
396 Self { code, code_id }
397 }
398
399 pub unsafe fn from_incompatible_parts(code: Code, code_id: CodeId) -> Self {
404 Self { code, code_id }
405 }
406
407 pub fn code_id(&self) -> CodeId {
409 self.code_id
410 }
411
412 pub fn code(&self) -> &Code {
414 &self.code
415 }
416
417 pub fn into_parts(self) -> (Code, CodeId) {
419 (self.code, self.code_id)
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use crate::{
426 code::{
427 utils::REF_TYPE_SIZE, Code, CodeError, DataSectionError, ExportError, ImportError,
428 StackEndError, TryNewCodeConfig, GENERIC_OS_PAGE_SIZE,
429 },
430 gas_metering::CustomConstantCostRules,
431 };
432 use alloc::{format, vec::Vec};
433 use gear_wasm_instrument::{InstrumentationError, ModuleError, STACK_END_EXPORT_NAME};
434
435 fn wat2wasm_with_validate(s: &str, validate: bool) -> Vec<u8> {
436 let code = wat::parse_str(s).unwrap();
437 if validate {
438 wasmparser::validate(&code).unwrap();
439 }
440 code
441 }
442
443 fn wat2wasm(s: &str) -> Vec<u8> {
444 wat2wasm_with_validate(s, true)
445 }
446
447 macro_rules! assert_code_err {
448 ($res:expr, $expected:pat) => {
449 let err = $res.expect_err("Code::try_new must return an error");
450 let expected_err = stringify!($expected);
451 assert!(
452 matches!(err, $expected),
453 "Must receive {:?}, got {:?}",
454 expected_err,
455 err
456 );
457 };
458 }
459
460 fn try_new_code_from_wat_with_params(
461 wat: &str,
462 stack_height: Option<u32>,
463 data_segments_amount_limit: Option<u32>,
464 make_validation: bool,
465 ) -> Result<Code, CodeError> {
466 Code::try_new_mock_const_or_no_rules(
467 wat2wasm(wat),
468 true,
469 TryNewCodeConfig {
470 stack_height,
471 data_segments_amount_limit,
472 make_validation,
473 ..Default::default()
474 },
475 )
476 }
477
478 fn try_new_code_from_wat(wat: &str, stack_height: Option<u32>) -> Result<Code, CodeError> {
479 try_new_code_from_wat_with_params(wat, stack_height, None, true)
480 }
481
482 #[test]
483 fn reject_unknown_exports() {
484 let wat = r#"
485 (module
486 (import "env" "memory" (memory 1))
487 (export "this_import_is_unknown" (func $test))
488 (func $test)
489 )
490 "#;
491
492 assert_code_err!(
493 try_new_code_from_wat(wat, None),
494 CodeError::Export(ExportError::ExcessExport(0))
495 );
496 }
497
498 #[test]
499 fn required_fn_not_found() {
500 let wat = r#"
501 (module
502 (import "env" "memory" (memory 1))
503 (export "handle_signal" (func $handle_signal))
504 (func $handle_signal)
505 )
506 "#;
507
508 assert_code_err!(
509 try_new_code_from_wat(wat, None),
510 CodeError::Export(ExportError::RequiredExportNotFound)
511 );
512 }
513
514 #[test]
515 fn stack_limit_injection_works() {
516 let wat = r#"
517 (module
518 (import "env" "memory" (memory 1))
519 (export "init" (func $init))
520 (func $init)
521 )
522 "#;
523
524 let _ = try_new_code_from_wat(wat, Some(16 * 1024)).unwrap();
525 }
526
527 #[test]
528 fn data_segment_out_of_static_memory() {
529 let wat = r#"
531 (module
532 (import "env" "memory" (memory 1))
533 (export "init" (func $init))
534 (func $init)
535 (data (;0;) (i32.const 0x10000) "gear")
536 )
537 "#;
538
539 assert_code_err!(
540 try_new_code_from_wat(wat, None),
541 CodeError::DataSection(DataSectionError::EndAddressOutOfStaticMemory(
542 0x10000, 0x10003, 0x10000
543 ))
544 );
545
546 let wat = r#"
548 (module
549 (import "env" "memory" (memory 1))
550 (export "init" (func $init))
551 (func $init)
552 (data (;0;) (i32.const 0xfffd) "gear")
553 )
554 "#;
555
556 assert_code_err!(
557 try_new_code_from_wat(wat, None),
558 CodeError::DataSection(DataSectionError::EndAddressOutOfStaticMemory(
559 0xfffd, 0x10000, 0x10000
560 ))
561 );
562 }
563
564 #[test]
565 fn data_segment_out_of_u32() {
566 let wat = r#"
568 (module
569 (import "env" "memory" (memory 1))
570 (export "init" (func $init))
571 (func $init)
572 (data (;0;) (i32.const 0xffffffff) "gear")
573 )
574 "#;
575
576 assert_code_err!(
577 try_new_code_from_wat(wat, None),
578 CodeError::DataSection(DataSectionError::EndAddressOverflow(0xffffffff))
579 );
580 }
581
582 #[test]
583 fn data_segment_stack_overlaps() {
584 let wat = format!(
586 r#"
587 (module
588 (import "env" "memory" (memory 3))
589 (export "init" (func $init))
590 (func $init)
591 (data (;0;) (i32.const 0x10000) "gear")
592 (export "{STACK_END_EXPORT_NAME}" (global 0))
593 (global (mut i32) (i32.const 0x20000))
594 )"#
595 );
596
597 assert_code_err!(
598 try_new_code_from_wat(wat.as_str(), None),
599 CodeError::DataSection(DataSectionError::GearStackOverlaps(0x10000, 0x20000))
600 );
601 }
602
603 #[test]
604 fn data_section() {
605 let wat = format!(
606 r#"
607 (module
608 (import "env" "memory" (memory 3))
609 (export "init" (func $init))
610 (func $init)
611 (data (i32.const 0x20000) "gear")
612 (data (i32.const 0x10000) "") ;; empty data segment
613 (data (i32.const 0x1ffff) "gear") ;; overlapping other segments, also ok
614 (data (i32.const 0x2ffff) "g") ;; one byte before the end of memory
615 (export "{STACK_END_EXPORT_NAME}" (global 0))
616 (global (mut i32) (i32.const 0x10000))
617 )"#
618 );
619
620 try_new_code_from_wat(wat.as_str(), None).expect("Must be ok");
621 }
622
623 #[test]
624 fn check_mutable_global_exports_restriction() {
625 let wat = r#"
626 (module
627 (import "env" "memory" (memory 0))
628 (func $init)
629 (export "init" (func $init))
630 (export "global" (global 0))
631 (global (;0;) (mut i32) (i32.const 0))
632 )"#;
633
634 assert_code_err!(
635 try_new_code_from_wat(wat, None),
636 CodeError::Export(ExportError::MutableGlobalExport(0, 1))
637 );
638 }
639
640 #[test]
641 fn stack_end_initialization() {
642 let wat = format!(
643 r#"
644 (module
645 (import "env" "memory" (memory 1))
646 (import "env" "unknown" (global i32))
647 (func $init)
648 (export "init" (func $init))
649 (export "{STACK_END_EXPORT_NAME}" (global 1))
650 (global (mut i32) (global.get 0))
651 )"#
652 );
653
654 assert_code_err!(
655 try_new_code_from_wat(wat.as_str(), None),
656 CodeError::StackEnd(StackEndError::Initialization)
657 );
658 }
659
660 #[test]
661 fn stack_end_alignment() {
662 let wat = format!(
663 r#"
664 (module
665 (import "env" "memory" (memory 2))
666 (func $init)
667 (export "init" (func $init))
668 (export "{STACK_END_EXPORT_NAME}" (global 0))
669 (global (;0;) (mut i32) (i32.const 0x10001))
670 )"#
671 );
672
673 assert_code_err!(
674 try_new_code_from_wat(wat.as_str(), None),
675 CodeError::StackEnd(StackEndError::NotAligned(0x10001))
676 );
677 }
678
679 #[test]
680 fn stack_end_out_of_static_memory() {
681 let wat = format!(
682 r#"
683 (module
684 (import "env" "memory" (memory 1))
685 (func $init)
686 (export "init" (func $init))
687 (export "{STACK_END_EXPORT_NAME}" (global 0))
688 (global (;0;) (mut i32) (i32.const 0x20000))
689 )"#
690 );
691
692 assert_code_err!(
693 try_new_code_from_wat(wat.as_str(), None),
694 CodeError::StackEnd(StackEndError::OutOfStatic(0x20000, 0x10000))
695 );
696 }
697
698 #[test]
699 fn stack_end() {
700 let wat = format!(
701 r#"
702 (module
703 (import "env" "memory" (memory 1))
704 (func $init)
705 (export "init" (func $init))
706 (export "{STACK_END_EXPORT_NAME}" (global 0))
707 (global (;0;) (mut i32) (i32.const 0x10000))
708 )"#
709 );
710
711 let code = try_new_code_from_wat(wat.as_str(), None).expect("Must be ok");
712 assert_eq!(code.stack_end, Some(1.into()));
713 }
714
715 #[test]
716 fn export_to_imported_function() {
717 let wat = r#"
718 (module
719 (import "env" "memory" (memory 1))
720 (import "env" "gr_leave" (func $gr_leave))
721 (export "init" (func $gr_leave))
722 (func)
723 )"#;
724
725 assert_code_err!(
726 try_new_code_from_wat(wat, None),
727 CodeError::Export(ExportError::ExportReferencesToImportFunction(0, 0))
728 );
729 }
730
731 #[test]
732 fn export_to_imported_global() {
733 let wat = r#"
734 (module
735 (import "env" "memory" (memory 1))
736 (import "env" "global" (global i32))
737 (export "init" (func 0))
738 (export "global" (global 0))
739 (func)
740 )"#;
741
742 assert_code_err!(
743 try_new_code_from_wat(wat, None),
744 CodeError::Export(ExportError::ExportReferencesToImportGlobal(1, 0))
745 );
746 }
747
748 #[test]
749 fn multi_memory_import() {
750 let wat = r#"
751 (module
752 (import "env" "memory" (memory 1))
753 (import "env" "memory2" (memory 2))
754 (export "init" (func $init))
755 (func $init)
756 )
757 "#;
758
759 let res = Code::try_new(
760 wat2wasm_with_validate(wat, false),
761 1,
762 |_| CustomConstantCostRules::default(),
763 None,
764 None,
765 );
766
767 assert_code_err!(res, CodeError::Validation(_));
768 }
769
770 #[test]
771 fn global_import() {
772 let wat = r#"
773 (module
774 (import "env" "memory" (memory 1))
775 (import "env" "unknown" (global $unknown i32))
776 (export "init" (func $init))
777 (func $init)
778 )
779 "#;
780
781 assert_code_err!(
782 try_new_code_from_wat(wat, None),
783 CodeError::Import(ImportError::UnexpectedImportKind {
784 kind: &"Global",
785 index: 1
786 })
787 );
788 }
789
790 #[test]
791 fn table_import() {
792 let wat = r#"
793 (module
794 (import "env" "memory" (memory 1))
795 (import "env" "unknown" (table $unknown 10 20 funcref))
796 (export "init" (func $init))
797 (func $init)
798 )
799 "#;
800
801 assert_code_err!(
802 try_new_code_from_wat(wat, None),
803 CodeError::Import(ImportError::UnexpectedImportKind {
804 kind: &"Table",
805 index: 1
806 })
807 );
808 }
809
810 #[test]
811 fn data_segments_amount_limit() {
812 const DATA_SEGMENTS_AMOUNT_LIMIT: u32 = 1024;
813
814 let segment = r#"(data (i32.const 0x0) "gear")"#;
815
816 let wat = format!(
817 r#"
818 (module
819 (import "env" "memory" (memory 1))
820 (func $init)
821 (export "init" (func $init))
822 {}
823 )
824 "#,
825 segment.repeat(1025)
826 );
827
828 assert_code_err!(
829 try_new_code_from_wat_with_params(
830 wat.as_str(),
831 None,
832 DATA_SEGMENTS_AMOUNT_LIMIT.into(),
833 true,
834 ),
835 CodeError::DataSection(DataSectionError::DataSegmentsAmountLimit {
836 limit: DATA_SEGMENTS_AMOUNT_LIMIT,
837 actual: 1025
838 })
839 );
840 }
841
842 #[test]
843 fn data_section_bytes() {
844 let wat = r#"
846 (module
847 (import "env" "memory" (memory 3))
848 (func $init)
849 (export "init" (func $init))
850 (data (i32.const 0x20000) "gear")
851 )
852 "#;
853
854 assert_eq!(
855 try_new_code_from_wat(wat, Some(1024))
856 .unwrap()
857 .instantiated_section_sizes
858 .data_section,
859 GENERIC_OS_PAGE_SIZE,
860 );
861
862 let wat = r#"
864 (module
865 (import "env" "memory" (memory 3))
866 (func $init)
867 (export "init" (func $init))
868 (data (i32.const 0x0000) "gear")
869 (data (i32.const 0x1000) "gear")
870 )
871 "#;
872
873 assert_eq!(
874 try_new_code_from_wat(wat, Some(1024))
875 .unwrap()
876 .instantiated_section_sizes
877 .data_section,
878 GENERIC_OS_PAGE_SIZE * 2,
879 );
880
881 let wat = r#"
883 (module
884 (import "env" "memory" (memory 3))
885 (func $init)
886 (export "init" (func $init))
887 (data (i32.const 0x0000) "gear")
888 (data (i32.const 0x10000) "gear")
889 )
890 "#;
891
892 assert_eq!(
893 try_new_code_from_wat(wat, Some(1024))
894 .unwrap()
895 .instantiated_section_sizes
896 .data_section,
897 GENERIC_OS_PAGE_SIZE * 2,
898 );
899
900 let wat = r#"
902 (module
903 (import "env" "memory" (memory 3))
904 (func $init)
905 (export "init" (func $init))
906 (data (i32.const 0x0) "")
907 (data (i32.const 0x0) "")
908 )
909 "#;
910
911 assert_eq!(
912 try_new_code_from_wat(wat, Some(1024))
913 .unwrap()
914 .instantiated_section_sizes
915 .data_section,
916 0,
917 );
918
919 let wat = r#"
921 (module
922 (import "env" "memory" (memory 3))
923 (func $init)
924 (export "init" (func $init))
925 (data (i32.const 0x20000) "gear")
926 (data (i32.const 0x20001) "gear")
927 )
928 "#;
929
930 assert_eq!(
931 try_new_code_from_wat(wat, Some(1024))
932 .unwrap()
933 .instantiated_section_sizes
934 .data_section,
935 GENERIC_OS_PAGE_SIZE,
936 );
937
938 let wat = format!(
940 r#"
941 (module
942 (import "env" "memory" (memory 3))
943 (func $init)
944 (export "init" (func $init))
945 (data (i32.const 0x20000) "{}")
946 )
947 "#,
948 "a".repeat((GENERIC_OS_PAGE_SIZE + 1) as usize)
949 );
950
951 assert_eq!(
952 try_new_code_from_wat(&wat, Some(1024))
953 .unwrap()
954 .instantiated_section_sizes
955 .data_section,
956 GENERIC_OS_PAGE_SIZE * 2,
957 );
958
959 let wat = format!(
961 r#"
962 (module
963 (import "env" "memory" (memory 3))
964 (func $init)
965 (export "init" (func $init))
966 (data (i32.const 0x20000) "{0}")
967 (data (i32.const 0x23000) "{1}")
968 )
969 "#,
970 "a".repeat((GENERIC_OS_PAGE_SIZE * 3) as usize),
971 "b".repeat((GENERIC_OS_PAGE_SIZE) as usize)
972 );
973
974 assert_eq!(
975 try_new_code_from_wat(&wat, Some(1024))
976 .unwrap()
977 .instantiated_section_sizes
978 .data_section,
979 GENERIC_OS_PAGE_SIZE * 4,
980 );
981
982 let wat = format!(
984 r#"
985 (module
986 (import "env" "memory" (memory 3))
987 (func $init)
988 (export "init" (func $init))
989 (data (i32.const 0x20000) "{0}")
990 (data (i32.const 0x21000) "{1}")
991 )
992 "#,
993 "a".repeat((GENERIC_OS_PAGE_SIZE * 2 + 1) as usize),
994 "b".repeat((GENERIC_OS_PAGE_SIZE * 2 + 1) as usize)
995 );
996
997 assert_eq!(
998 try_new_code_from_wat(&wat, Some(1024))
999 .unwrap()
1000 .instantiated_section_sizes
1001 .data_section,
1002 GENERIC_OS_PAGE_SIZE * 4,
1003 );
1004 }
1005
1006 #[test]
1007 fn code_section_bytes() {
1008 const INSTRUMENTATION_CODE_SIZE: u32 = 74;
1009
1010 let wat = r#"
1011 (module
1012 (import "env" "memory" (memory 3))
1013 (func $init)
1014 (export "init" (func $init))
1015 (func $sum (param i32 i32) (result i32)
1016 local.get 0
1017 local.get 1
1018 i32.add
1019 )
1020 )
1021 "#;
1022
1023 assert_eq!(
1024 try_new_code_from_wat(wat, Some(1024))
1025 .unwrap()
1026 .instantiated_section_sizes
1027 .code_section,
1028 INSTRUMENTATION_CODE_SIZE + 11,
1029 );
1030 }
1031
1032 #[test]
1033 fn global_section_bytes() {
1034 const INSTRUMENTATION_GLOBALS_SIZE: usize = size_of::<i32>() + size_of::<i64>();
1035
1036 let wat = r#"
1037 (module
1038 (import "env" "memory" (memory 3))
1039 (func $init)
1040 (export "init" (func $init))
1041 (global (mut i32) (i32.const 0))
1042 (global (mut i32) (i32.const 0))
1043 (global (mut i64) (i64.const 0))
1044 )
1045 "#;
1046
1047 assert_eq!(
1048 try_new_code_from_wat(wat, Some(1024))
1049 .unwrap()
1050 .instantiated_section_sizes
1051 .global_section,
1052 (INSTRUMENTATION_GLOBALS_SIZE + size_of::<i32>() * 2 + size_of::<i64>()) as u32,
1053 );
1054 }
1055
1056 #[test]
1057 fn element_section_bytes() {
1058 let wat = r#"
1059 (module
1060 (import "env" "memory" (memory 3))
1061 (func $init)
1062 (export "init" (func $init))
1063 (table 10 10 funcref)
1064 (elem (i32.const 1) 0 0 0 0)
1065 )
1066 "#;
1067
1068 assert_eq!(
1069 try_new_code_from_wat(wat, Some(1024))
1070 .unwrap()
1071 .instantiated_section_sizes
1072 .table_section,
1073 10 * REF_TYPE_SIZE,
1074 );
1075
1076 assert_eq!(
1077 try_new_code_from_wat(wat, Some(1024))
1078 .unwrap()
1079 .instantiated_section_sizes
1080 .element_section,
1081 REF_TYPE_SIZE * 4,
1082 );
1083 }
1084
1085 #[test]
1086 fn type_section_bytes() {
1087 let wat = r#"
1088 (module
1089 (import "env" "memory" (memory 3))
1090 (type (;35;) (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)))
1091 (type (;36;) (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)))
1092 (func $init)
1093 (export "init" (func $init))
1094 )
1095 "#;
1096
1097 assert_eq!(
1098 try_new_code_from_wat(wat, Some(1024))
1099 .unwrap()
1100 .instantiated_section_sizes
1101 .type_section,
1102 50,
1103 );
1104 }
1105
1106 #[test]
1107 fn unsupported_instruction() {
1108 let res = try_new_code_from_wat_with_params(
1110 r#"
1111 (module
1112 (import "env" "memory" (memory 0 1))
1113 (func (result f64)
1114 f64.const 10
1115 f64.const 3
1116 f64.div)
1117 (global i32 (i32.const 42))
1118 (func $init)
1119 (export "init" (func $init))
1120 )
1121 "#,
1122 Some(1024),
1123 None,
1124 false,
1126 );
1127
1128 assert!(matches!(
1129 res,
1130 Err(CodeError::Module(ModuleError::UnsupportedInstruction(_))),
1131 ));
1132
1133 let res = try_new_code_from_wat(
1135 r#"
1136 (module
1137 (import "env" "memory" (memory 0 1))
1138 (func (result i32)
1139 global.get 0
1140 memory.grow
1141 )
1142 (global i32 (i32.const 42))
1143 (func $init)
1144 (export "init" (func $init))
1145 )"#,
1146 Some(1024),
1147 );
1148
1149 assert!(matches!(
1150 res,
1151 Err(CodeError::Instrumentation(
1152 InstrumentationError::GasInjection
1153 ))
1154 ));
1155 }
1156}