17a37e313SNick Fitzgerald //! Oracles related to memory.
27a37e313SNick Fitzgerald 
37a37e313SNick Fitzgerald use crate::generators::{HeapImage, MemoryAccesses};
47a37e313SNick Fitzgerald use wasmtime::*;
57a37e313SNick Fitzgerald 
67a37e313SNick Fitzgerald /// Oracle to perform the described memory accesses and check that they are all
77a37e313SNick Fitzgerald /// in- or out-of-bounds as expected
check_memory_accesses(input: MemoryAccesses)87a37e313SNick Fitzgerald pub fn check_memory_accesses(input: MemoryAccesses) {
97a37e313SNick Fitzgerald     crate::init_fuzzing();
107a37e313SNick Fitzgerald     log::info!("Testing memory accesses: {input:#x?}");
117a37e313SNick Fitzgerald 
127a37e313SNick Fitzgerald     let offset = input.offset;
137a37e313SNick Fitzgerald     let growth = input.growth;
147a37e313SNick Fitzgerald     let wasm = build_wasm(&input.image, offset);
157a37e313SNick Fitzgerald     crate::oracles::log_wasm(&wasm);
167a37e313SNick Fitzgerald     let offset = u64::from(offset);
177a37e313SNick Fitzgerald 
187a37e313SNick Fitzgerald     let mut config = input.config.to_wasmtime();
197a37e313SNick Fitzgerald 
20bdd78422SNick Fitzgerald     // Force-enable proposals if the heap image needs them.
217a37e313SNick Fitzgerald     if input.image.memory64 {
227a37e313SNick Fitzgerald         config.wasm_memory64(true);
237a37e313SNick Fitzgerald     }
24bdd78422SNick Fitzgerald     if input.image.page_size_log2.is_some() {
25bdd78422SNick Fitzgerald         config.wasm_custom_page_sizes(true);
26bdd78422SNick Fitzgerald     }
277a37e313SNick Fitzgerald 
287a37e313SNick Fitzgerald     let engine = Engine::new(&config).unwrap();
297a37e313SNick Fitzgerald     let module = match Module::new(&engine, &wasm) {
307a37e313SNick Fitzgerald         Ok(m) => m,
317a37e313SNick Fitzgerald         Err(e) => {
327a37e313SNick Fitzgerald             let e = format!("{e:?}");
337a37e313SNick Fitzgerald             log::info!("Failed to create `Module`: {e}");
347a37e313SNick Fitzgerald             assert!(
357a37e313SNick Fitzgerald                 e.contains("bytes which exceeds the configured maximum of")
36d72b14a4SAlex Crichton                     || e.contains("exceeds the limit of"),
37d72b14a4SAlex Crichton                 "bad module compilation error: {e:?}",
387a37e313SNick Fitzgerald             );
397a37e313SNick Fitzgerald             return;
407a37e313SNick Fitzgerald         }
417a37e313SNick Fitzgerald     };
427a37e313SNick Fitzgerald 
437a37e313SNick Fitzgerald     let limits = super::StoreLimits::new();
447a37e313SNick Fitzgerald     let mut store = Store::new(&engine, limits);
457a37e313SNick Fitzgerald     input.config.configure_store(&mut store);
467a37e313SNick Fitzgerald 
477a37e313SNick Fitzgerald     // If we are using fuel, make sure we add enough that we won't ever run out.
487a37e313SNick Fitzgerald     if input.config.wasmtime.consume_fuel {
497a37e313SNick Fitzgerald         store.set_fuel(u64::MAX).unwrap();
507a37e313SNick Fitzgerald     }
517a37e313SNick Fitzgerald 
527a37e313SNick Fitzgerald     let instance = match Instance::new(&mut store, &module, &[]) {
537a37e313SNick Fitzgerald         Ok(x) => x,
547a37e313SNick Fitzgerald         Err(e) => {
557a37e313SNick Fitzgerald             log::info!("Failed to instantiate: {e:?}");
56d3132c9dSAlex Crichton             assert!(
57d3132c9dSAlex Crichton                 format!("{e:?}").contains("Cannot allocate memory"),
58d3132c9dSAlex Crichton                 "bad error: {e:?}",
59d3132c9dSAlex Crichton             );
607a37e313SNick Fitzgerald             return;
617a37e313SNick Fitzgerald         }
627a37e313SNick Fitzgerald     };
637a37e313SNick Fitzgerald 
647a37e313SNick Fitzgerald     let memory = instance.get_memory(&mut store, "memory").unwrap();
657a37e313SNick Fitzgerald     let load8 = instance
667a37e313SNick Fitzgerald         .get_typed_func::<u64, u32>(&mut store, "load8")
677a37e313SNick Fitzgerald         .unwrap();
687a37e313SNick Fitzgerald     let load16 = instance
697a37e313SNick Fitzgerald         .get_typed_func::<u64, u32>(&mut store, "load16")
707a37e313SNick Fitzgerald         .unwrap();
717a37e313SNick Fitzgerald     let load32 = instance
727a37e313SNick Fitzgerald         .get_typed_func::<u64, u32>(&mut store, "load32")
737a37e313SNick Fitzgerald         .unwrap();
747a37e313SNick Fitzgerald     let load64 = instance
757a37e313SNick Fitzgerald         .get_typed_func::<u64, u64>(&mut store, "load64")
767a37e313SNick Fitzgerald         .unwrap();
777a37e313SNick Fitzgerald 
787a37e313SNick Fitzgerald     let do_accesses = |store: &mut Store<_>, msg: &str| {
797a37e313SNick Fitzgerald         let len = memory.data_size(&mut *store);
807a37e313SNick Fitzgerald         let len = u64::try_from(len).unwrap();
817a37e313SNick Fitzgerald 
827a37e313SNick Fitzgerald         if let Some(n) = len.checked_sub(8).and_then(|n| n.checked_sub(offset)) {
837a37e313SNick Fitzgerald             // Test various in-bounds accesses near the bound.
847a37e313SNick Fitzgerald             for i in 0..=7 {
857a37e313SNick Fitzgerald                 let addr = n + i;
867a37e313SNick Fitzgerald                 assert!(addr + offset + 1 <= len);
877a37e313SNick Fitzgerald                 let result = load8.call(&mut *store, addr);
887a37e313SNick Fitzgerald                 assert!(
897a37e313SNick Fitzgerald                     result.is_ok(),
907a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load8({n:#x} + {i:#x} = {addr:#x}) \
917a37e313SNick Fitzgerald                      should be in bounds, got {result:?}"
927a37e313SNick Fitzgerald                 );
937a37e313SNick Fitzgerald             }
947a37e313SNick Fitzgerald             for i in 0..=6 {
957a37e313SNick Fitzgerald                 let addr = n + offset + i;
967a37e313SNick Fitzgerald                 assert!(addr + 2 <= len);
977a37e313SNick Fitzgerald                 let result = load16.call(&mut *store, n + i);
987a37e313SNick Fitzgerald                 assert!(
997a37e313SNick Fitzgerald                     result.is_ok(),
1007a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load16({n:#x} + {i:#x} = {addr:#x}) \
1017a37e313SNick Fitzgerald                      should be in bounds, got {result:?}"
1027a37e313SNick Fitzgerald                 );
1037a37e313SNick Fitzgerald             }
1047a37e313SNick Fitzgerald             for i in 0..=4 {
1057a37e313SNick Fitzgerald                 let addr = n + offset + i;
1067a37e313SNick Fitzgerald                 assert!(addr + 4 <= len);
1077a37e313SNick Fitzgerald                 let result = load32.call(&mut *store, n + i);
1087a37e313SNick Fitzgerald                 assert!(
1097a37e313SNick Fitzgerald                     result.is_ok(),
1107a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load32({n:#x} + {i:#x} = {addr:#x}) \
1117a37e313SNick Fitzgerald                      should be in bounds, got {result:?}"
1127a37e313SNick Fitzgerald                 );
1137a37e313SNick Fitzgerald             }
1147a37e313SNick Fitzgerald             assert!(n + offset + 8 <= len);
1157a37e313SNick Fitzgerald             let result = load64.call(&mut *store, n);
1167a37e313SNick Fitzgerald             assert!(
1177a37e313SNick Fitzgerald                 result.is_ok(),
1187a37e313SNick Fitzgerald                 "{msg}: len={len:#x}, offset={offset:#x}, load64({n:#x}) should be in bounds, \
1197a37e313SNick Fitzgerald                  got {result:?}"
1207a37e313SNick Fitzgerald             );
1217a37e313SNick Fitzgerald 
1227a37e313SNick Fitzgerald             // Test various out-of-bounds accesses overlapping the memory bound.
1237a37e313SNick Fitzgerald             for i in 1..2 {
1247a37e313SNick Fitzgerald                 let addr = len - i;
1257a37e313SNick Fitzgerald                 assert!(addr + offset + 2 > len);
1267a37e313SNick Fitzgerald                 let result = load16.call(&mut *store, addr);
1277a37e313SNick Fitzgerald                 assert!(
1287a37e313SNick Fitzgerald                     result.is_err(),
1297a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load16({len:#x} - {i:#x} = {addr:#x}) \
1307a37e313SNick Fitzgerald                      should trap, got {result:?}"
1317a37e313SNick Fitzgerald                 );
1327a37e313SNick Fitzgerald             }
1337a37e313SNick Fitzgerald             for i in 1..4 {
1347a37e313SNick Fitzgerald                 let addr = len - i;
1357a37e313SNick Fitzgerald                 assert!(addr + offset + 4 > len);
1367a37e313SNick Fitzgerald                 let result = load32.call(&mut *store, addr);
1377a37e313SNick Fitzgerald                 assert!(
1387a37e313SNick Fitzgerald                     result.is_err(),
1397a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load32({len:#x} - {i:#x} = {addr:#x}) \
1407a37e313SNick Fitzgerald                      should trap, got {result:?}"
1417a37e313SNick Fitzgerald                 );
1427a37e313SNick Fitzgerald             }
1437a37e313SNick Fitzgerald             for i in 1..8 {
1447a37e313SNick Fitzgerald                 let addr = len - i;
1457a37e313SNick Fitzgerald                 assert!(addr + offset + 8 > len);
1467a37e313SNick Fitzgerald                 let result = load64.call(&mut *store, addr);
1477a37e313SNick Fitzgerald                 assert!(
1487a37e313SNick Fitzgerald                     result.is_err(),
1497a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load64({len:#x} - {i:#x} = {addr:#x}) \
1507a37e313SNick Fitzgerald                      should trap, got {result:?}"
1517a37e313SNick Fitzgerald                 );
1527a37e313SNick Fitzgerald             }
1537a37e313SNick Fitzgerald         }
1547a37e313SNick Fitzgerald 
1557a37e313SNick Fitzgerald         // Test that out-of-bounds accesses just after the memory bound trap.
1567a37e313SNick Fitzgerald         if let Some(n) = len.checked_sub(offset) {
1577a37e313SNick Fitzgerald             for i in 0..=1 {
1587a37e313SNick Fitzgerald                 let addr = n + i;
1597a37e313SNick Fitzgerald                 assert!(addr + offset + 1 > len);
1607a37e313SNick Fitzgerald                 let result = load8.call(&mut *store, addr);
1617a37e313SNick Fitzgerald                 assert!(
1627a37e313SNick Fitzgerald                     result.is_err(),
1637a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load8({n:#x} + {i:#x} = {addr:#x}) \
1647a37e313SNick Fitzgerald                      should trap, got {result:?}"
1657a37e313SNick Fitzgerald                 );
1667a37e313SNick Fitzgerald                 assert!(addr + offset + 2 > len);
1677a37e313SNick Fitzgerald                 let result = load16.call(&mut *store, addr);
1687a37e313SNick Fitzgerald                 assert!(
1697a37e313SNick Fitzgerald                     result.is_err(),
1707a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load16({n:#x} + {i:#x} = {addr:#x}) \
1717a37e313SNick Fitzgerald                      should trap, got {result:?}"
1727a37e313SNick Fitzgerald                 );
1737a37e313SNick Fitzgerald                 assert!(addr + offset + 4 > len);
1747a37e313SNick Fitzgerald                 let result = load32.call(&mut *store, addr);
1757a37e313SNick Fitzgerald                 assert!(
1767a37e313SNick Fitzgerald                     result.is_err(),
1777a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load32({n:#x} + {i:#x} = {addr:#x}) \
1787a37e313SNick Fitzgerald                      should trap, got {result:?}"
1797a37e313SNick Fitzgerald                 );
1807a37e313SNick Fitzgerald                 assert!(addr + offset + 8 > len);
1817a37e313SNick Fitzgerald                 let result = load64.call(&mut *store, addr);
1827a37e313SNick Fitzgerald                 assert!(
1837a37e313SNick Fitzgerald                     result.is_err(),
1847a37e313SNick Fitzgerald                     "{msg}: len={len:#x}, offset={offset:#x}, load64({n:#x} + {i:#x} = {addr:#x}) \
1857a37e313SNick Fitzgerald                      should trap, got {result:?}"
1867a37e313SNick Fitzgerald                 );
1877a37e313SNick Fitzgerald             }
1887a37e313SNick Fitzgerald         }
1897a37e313SNick Fitzgerald 
1907a37e313SNick Fitzgerald         // Test out-of-bounds accesses near the end of the index type's range to
1917a37e313SNick Fitzgerald         // double check our overflow handling inside the bounds checks.
1927a37e313SNick Fitzgerald         let len_is_4gib = len == u64::from(u32::MAX) + 1;
1937a37e313SNick Fitzgerald         let end_delta = (input.image.memory64 && len_is_4gib) as u64;
1947a37e313SNick Fitzgerald         let max = if input.image.memory64 {
1957a37e313SNick Fitzgerald             u64::MAX
1967a37e313SNick Fitzgerald         } else {
1977a37e313SNick Fitzgerald             u64::from(u32::MAX)
1987a37e313SNick Fitzgerald         };
1997a37e313SNick Fitzgerald         for i in 0..(1 - end_delta) {
2007a37e313SNick Fitzgerald             let addr = max - i;
2017a37e313SNick Fitzgerald             let result = load8.call(&mut *store, addr);
2027a37e313SNick Fitzgerald             assert!(
2037a37e313SNick Fitzgerald                 result.is_err(),
2047a37e313SNick Fitzgerald                 "{msg}: len={len:#x}, offset={offset:#x}, load8({max:#x} - {i:#x} = {addr:#x}) \
2057a37e313SNick Fitzgerald                  should trap, got {result:?}"
2067a37e313SNick Fitzgerald             );
2077a37e313SNick Fitzgerald         }
2087a37e313SNick Fitzgerald         for i in 0..(2 - end_delta) {
2097a37e313SNick Fitzgerald             let addr = max - i;
2107a37e313SNick Fitzgerald             let result = load16.call(&mut *store, addr);
2117a37e313SNick Fitzgerald             assert!(
2127a37e313SNick Fitzgerald                 result.is_err(),
2137a37e313SNick Fitzgerald                 "{msg}: len={len:#x}, offset={offset:#x}, load16({max:#x} - {i:#x} = {addr:#x}) \
2147a37e313SNick Fitzgerald                  should trap, got {result:?}"
2157a37e313SNick Fitzgerald             );
2167a37e313SNick Fitzgerald         }
2177a37e313SNick Fitzgerald         for i in 0..(4 - end_delta) {
2187a37e313SNick Fitzgerald             let addr = max - i;
2197a37e313SNick Fitzgerald             let result = load32.call(&mut *store, addr);
2207a37e313SNick Fitzgerald             assert!(
2217a37e313SNick Fitzgerald                 result.is_err(),
2227a37e313SNick Fitzgerald                 "{msg}: len={len:#x}, offset={offset:#x}, load32({max:#x} - {i:#x} = {addr:#x}) \
2237a37e313SNick Fitzgerald                  should trap, got {result:?}"
2247a37e313SNick Fitzgerald             );
2257a37e313SNick Fitzgerald         }
2267a37e313SNick Fitzgerald         for i in 0..(8 - end_delta) {
2277a37e313SNick Fitzgerald             let addr = max - i;
2287a37e313SNick Fitzgerald             let result = load64.call(&mut *store, addr);
2297a37e313SNick Fitzgerald             assert!(
2307a37e313SNick Fitzgerald                 result.is_err(),
2317a37e313SNick Fitzgerald                 "{msg}: len={len:#x}, offset={offset:#x}, load64({max:#x} - {i:#x} = {addr:#x}) \
2327a37e313SNick Fitzgerald                  should trap, got {result:?}"
2337a37e313SNick Fitzgerald             );
2347a37e313SNick Fitzgerald         }
2357a37e313SNick Fitzgerald     };
2367a37e313SNick Fitzgerald 
2377a37e313SNick Fitzgerald     do_accesses(&mut store, "initial size");
238925a4f48SAlex Crichton     let res = memory.grow(&mut store, u64::from(growth));
239925a4f48SAlex Crichton     log::debug!("grow {growth} -> {res:?}");
2407a37e313SNick Fitzgerald     do_accesses(&mut store, "after growing");
2417a37e313SNick Fitzgerald }
2427a37e313SNick Fitzgerald 
2437a37e313SNick Fitzgerald /// Build a Wasm module with a single memory in the shape of the given heap
2447a37e313SNick Fitzgerald /// image, exports that memory, and also exports four functions:
2457a37e313SNick Fitzgerald /// `load{8,16,32,64}`. Each of these functions takes an `i64` address,
2467a37e313SNick Fitzgerald /// truncates it to `i32` if the memory is not 64-bit, and loads its associated
2477a37e313SNick Fitzgerald /// number of bits from memory at `address + offset`.
2487a37e313SNick Fitzgerald ///
2497a37e313SNick Fitzgerald /// ```wat
2507a37e313SNick Fitzgerald /// (module
2517a37e313SNick Fitzgerald ///   (memory (export "memory") ...)
2527a37e313SNick Fitzgerald ///   (func (export "load8") (param i64) (result i32)
2537a37e313SNick Fitzgerald ///     (i32.load8_u offset=${offset} (local.get 0))
2547a37e313SNick Fitzgerald ///   )
2557a37e313SNick Fitzgerald ///   ...
2567a37e313SNick Fitzgerald /// )
2577a37e313SNick Fitzgerald /// ```
build_wasm(image: &HeapImage, offset: u32) -> Vec<u8>2587a37e313SNick Fitzgerald fn build_wasm(image: &HeapImage, offset: u32) -> Vec<u8> {
2597a37e313SNick Fitzgerald     let mut module = wasm_encoder::Module::new();
2607a37e313SNick Fitzgerald 
2617a37e313SNick Fitzgerald     {
2627a37e313SNick Fitzgerald         let mut types = wasm_encoder::TypeSection::new();
2636844ed1aSAlex Crichton         types
2646844ed1aSAlex Crichton             .ty()
2656844ed1aSAlex Crichton             .function([wasm_encoder::ValType::I64], [wasm_encoder::ValType::I32]);
2666844ed1aSAlex Crichton         types
2676844ed1aSAlex Crichton             .ty()
2686844ed1aSAlex Crichton             .function([wasm_encoder::ValType::I64], [wasm_encoder::ValType::I64]);
2697a37e313SNick Fitzgerald         module.section(&types);
2707a37e313SNick Fitzgerald     }
2717a37e313SNick Fitzgerald 
2727a37e313SNick Fitzgerald     {
2737a37e313SNick Fitzgerald         let mut funcs = wasm_encoder::FunctionSection::new();
2747a37e313SNick Fitzgerald         funcs.function(0);
2757a37e313SNick Fitzgerald         funcs.function(0);
2767a37e313SNick Fitzgerald         funcs.function(0);
2777a37e313SNick Fitzgerald         funcs.function(1);
2787a37e313SNick Fitzgerald         module.section(&funcs);
2797a37e313SNick Fitzgerald     }
2807a37e313SNick Fitzgerald 
2817a37e313SNick Fitzgerald     {
2827a37e313SNick Fitzgerald         let mut memories = wasm_encoder::MemorySection::new();
2837a37e313SNick Fitzgerald         memories.memory(wasm_encoder::MemoryType {
2847a37e313SNick Fitzgerald             minimum: u64::from(image.minimum),
2857a37e313SNick Fitzgerald             maximum: image.maximum.map(Into::into),
2867a37e313SNick Fitzgerald             memory64: image.memory64,
2877a37e313SNick Fitzgerald             shared: false,
288bdd78422SNick Fitzgerald             page_size_log2: image.page_size_log2,
2897a37e313SNick Fitzgerald         });
2907a37e313SNick Fitzgerald         module.section(&memories);
2917a37e313SNick Fitzgerald     }
2927a37e313SNick Fitzgerald 
2937a37e313SNick Fitzgerald     {
2947a37e313SNick Fitzgerald         let mut exports = wasm_encoder::ExportSection::new();
2957a37e313SNick Fitzgerald         exports.export("memory", wasm_encoder::ExportKind::Memory, 0);
2967a37e313SNick Fitzgerald         exports.export("load8", wasm_encoder::ExportKind::Func, 0);
2977a37e313SNick Fitzgerald         exports.export("load16", wasm_encoder::ExportKind::Func, 1);
2987a37e313SNick Fitzgerald         exports.export("load32", wasm_encoder::ExportKind::Func, 2);
2997a37e313SNick Fitzgerald         exports.export("load64", wasm_encoder::ExportKind::Func, 3);
3007a37e313SNick Fitzgerald         module.section(&exports);
3017a37e313SNick Fitzgerald     }
3027a37e313SNick Fitzgerald 
3037a37e313SNick Fitzgerald     {
3047a37e313SNick Fitzgerald         let mut code = wasm_encoder::CodeSection::new();
3057a37e313SNick Fitzgerald         {
3067a37e313SNick Fitzgerald             let mut func = wasm_encoder::Function::new([]);
3077a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::LocalGet(0));
3087a37e313SNick Fitzgerald             if !image.memory64 {
3097a37e313SNick Fitzgerald                 func.instruction(&wasm_encoder::Instruction::I32WrapI64);
3107a37e313SNick Fitzgerald             }
3117a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::I32Load8U(
3127a37e313SNick Fitzgerald                 wasm_encoder::MemArg {
3137a37e313SNick Fitzgerald                     offset: u64::from(offset),
3147a37e313SNick Fitzgerald                     align: 0,
3157a37e313SNick Fitzgerald                     memory_index: 0,
3167a37e313SNick Fitzgerald                 },
3177a37e313SNick Fitzgerald             ));
3187a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::End);
3197a37e313SNick Fitzgerald             code.function(&func);
3207a37e313SNick Fitzgerald         }
3217a37e313SNick Fitzgerald         {
3227a37e313SNick Fitzgerald             let mut func = wasm_encoder::Function::new([]);
3237a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::LocalGet(0));
3247a37e313SNick Fitzgerald             if !image.memory64 {
3257a37e313SNick Fitzgerald                 func.instruction(&wasm_encoder::Instruction::I32WrapI64);
3267a37e313SNick Fitzgerald             }
3277a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::I32Load16U(
3287a37e313SNick Fitzgerald                 wasm_encoder::MemArg {
3297a37e313SNick Fitzgerald                     offset: u64::from(offset),
3307a37e313SNick Fitzgerald                     align: 0,
3317a37e313SNick Fitzgerald                     memory_index: 0,
3327a37e313SNick Fitzgerald                 },
3337a37e313SNick Fitzgerald             ));
3347a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::End);
3357a37e313SNick Fitzgerald             code.function(&func);
3367a37e313SNick Fitzgerald         }
3377a37e313SNick Fitzgerald         {
3387a37e313SNick Fitzgerald             let mut func = wasm_encoder::Function::new([]);
3397a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::LocalGet(0));
3407a37e313SNick Fitzgerald             if !image.memory64 {
3417a37e313SNick Fitzgerald                 func.instruction(&wasm_encoder::Instruction::I32WrapI64);
3427a37e313SNick Fitzgerald             }
3437a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::I32Load(wasm_encoder::MemArg {
3447a37e313SNick Fitzgerald                 offset: u64::from(offset),
3457a37e313SNick Fitzgerald                 align: 0,
3467a37e313SNick Fitzgerald                 memory_index: 0,
3477a37e313SNick Fitzgerald             }));
3487a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::End);
3497a37e313SNick Fitzgerald             code.function(&func);
3507a37e313SNick Fitzgerald         }
3517a37e313SNick Fitzgerald         {
3527a37e313SNick Fitzgerald             let mut func = wasm_encoder::Function::new([]);
3537a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::LocalGet(0));
3547a37e313SNick Fitzgerald             if !image.memory64 {
3557a37e313SNick Fitzgerald                 func.instruction(&wasm_encoder::Instruction::I32WrapI64);
3567a37e313SNick Fitzgerald             }
3577a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::I64Load(wasm_encoder::MemArg {
3587a37e313SNick Fitzgerald                 offset: u64::from(offset),
3597a37e313SNick Fitzgerald                 align: 0,
3607a37e313SNick Fitzgerald                 memory_index: 0,
3617a37e313SNick Fitzgerald             }));
3627a37e313SNick Fitzgerald             func.instruction(&wasm_encoder::Instruction::End);
3637a37e313SNick Fitzgerald             code.function(&func);
3647a37e313SNick Fitzgerald         }
3657a37e313SNick Fitzgerald         module.section(&code);
3667a37e313SNick Fitzgerald     }
3677a37e313SNick Fitzgerald 
3687a37e313SNick Fitzgerald     {
3697a37e313SNick Fitzgerald         let mut datas = wasm_encoder::DataSection::new();
3707a37e313SNick Fitzgerald         for (offset, data) in image.segments.iter() {
3717a37e313SNick Fitzgerald             datas.segment(wasm_encoder::DataSegment {
3727a37e313SNick Fitzgerald                 mode: wasm_encoder::DataSegmentMode::Active {
3737a37e313SNick Fitzgerald                     memory_index: 0,
3747a37e313SNick Fitzgerald                     offset: &if image.memory64 {
3757a37e313SNick Fitzgerald                         wasm_encoder::ConstExpr::i64_const(*offset as i64)
3767a37e313SNick Fitzgerald                     } else {
3777a37e313SNick Fitzgerald                         wasm_encoder::ConstExpr::i32_const(*offset as i32)
3787a37e313SNick Fitzgerald                     },
3797a37e313SNick Fitzgerald                 },
3807a37e313SNick Fitzgerald                 data: data.iter().copied(),
3817a37e313SNick Fitzgerald             });
3827a37e313SNick Fitzgerald         }
3837a37e313SNick Fitzgerald         module.section(&datas);
3847a37e313SNick Fitzgerald     }
3857a37e313SNick Fitzgerald 
3867a37e313SNick Fitzgerald     module.finish()
3877a37e313SNick Fitzgerald }
3887a37e313SNick Fitzgerald 
3897a37e313SNick Fitzgerald #[cfg(test)]
3907a37e313SNick Fitzgerald mod tests {
3917a37e313SNick Fitzgerald     use super::*;
392*882f22a7SAlex Crichton     use crate::test::test_n_times;
3937a37e313SNick Fitzgerald 
3947a37e313SNick Fitzgerald     #[test]
smoke_test_memory_access()3957a37e313SNick Fitzgerald     fn smoke_test_memory_access() {
396*882f22a7SAlex Crichton         test_n_times(50, |input: MemoryAccesses, _u| {
3977a37e313SNick Fitzgerald             check_memory_accesses(input);
398*882f22a7SAlex Crichton             Ok(())
399*882f22a7SAlex Crichton         })
4007a37e313SNick Fitzgerald     }
4017a37e313SNick Fitzgerald }
402