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