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