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