From b800758a461451ee8207269ec1d88b8e635599f2 Mon Sep 17 00:00:00 2001 From: mohanson Date: Fri, 17 Jan 2025 14:44:03 +0800 Subject: [PATCH] Backport #450 --- .github/workflows/develop.yml | 6 +-- benches/vm_benchmark.rs | 42 +++++++++--------- examples/check_real_memory.rs | 4 +- examples/ckb-vm-runner.rs | 4 +- src/lib.rs | 4 +- src/machine/asm/mod.rs | 8 +++- src/machine/mod.rs | 80 +++++++++++++++++++++++++++++++---- src/machine/trace.rs | 8 +++- src/memory/mod.rs | 17 ++++++++ tests/machine_build.rs | 16 ++++--- tests/test_asm.rs | 50 +++++++++++----------- tests/test_auipc_fusion.rs | 4 +- tests/test_dy_memory.rs | 4 +- tests/test_misc.rs | 10 ++--- tests/test_reset.rs | 8 ++-- tests/test_resume.rs | 18 +++++--- tests/test_resume2.rs | 61 +++++++++++++++++--------- tests/test_simple.rs | 8 ++-- tests/test_versions.rs | 16 +++---- 19 files changed, 244 insertions(+), 124 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index cf404dca..3d879bac 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -69,7 +69,7 @@ jobs: ln -snf .. ckb-vm-test-suite/ckb-vm docker run --rm -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20210804 cp -r /riscv /code/riscv cd ckb-vm-test-suite - git checkout 441e0f2149c097ccad133b040544dca13caeb01e + git checkout 898edc351eeb4de974ca4f0ff8d1e4943a95aecb git submodule update --init --recursive RISCV=`pwd`/../riscv ./test.sh @@ -136,13 +136,13 @@ jobs: ln -snf .. ckb-vm-test-suite/ckb-vm docker run --rm -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20210804 cp -r /riscv /code/riscv cd ckb-vm-test-suite - git checkout 441e0f2149c097ccad133b040544dca13caeb01e + git checkout 898edc351eeb4de974ca4f0ff8d1e4943a95aecb git submodule update --init --recursive RISCV=`pwd`/../riscv ./test.sh --build-only cd .. - name: Run test suite run: | - sudo apt install -y qemu binfmt-support qemu-user-static + sudo apt install -y qemu-system binfmt-support qemu-user-static sudo apt install -y gcc-multilib sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu clang docker run --rm --privileged multiarch/qemu-user-static --reset -p yes diff --git a/benches/vm_benchmark.rs b/benches/vm_benchmark.rs index 7a80ed5b..36675fb5 100644 --- a/benches/vm_benchmark.rs +++ b/benches/vm_benchmark.rs @@ -17,12 +17,13 @@ use std::fs; fn interpret_benchmark(c: &mut Criterion) { c.bench_function("interpret secp256k1_bench", |b| { let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into(); - let args: Vec = vec!["secp256k1_bench", - "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", - "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", - "foo", - "bar"].into_iter().map(|a| a.into()).collect(); - + let args: Vec = vec![ + "secp256k1_bench", + "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", + "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", + "foo", + "bar" + ].into_iter().map(|a| a.into()).collect(); b.iter(|| run::>(&buffer, &args[..], RISCV_MAX_MEMORY).unwrap()); }); } @@ -31,17 +32,18 @@ fn interpret_benchmark(c: &mut Criterion) { fn asm_benchmark(c: &mut Criterion) { c.bench_function("interpret secp256k1_bench via assembly", |b| { let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into(); - let args: Vec = vec!["secp256k1_bench", - "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", - "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", - "foo", - "bar"].into_iter().map(|a| a.into()).collect(); - + let args = [ + "secp256k1_bench", + "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", + "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", + "foo", + "bar", + ].into_iter().map(|a| Ok(a.into())); b.iter(|| { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::max_value()); let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); - machine.load_program(&buffer, &args[..]).unwrap(); + machine.load_program(&buffer, args.clone()).unwrap(); machine.run().unwrap() }); }); @@ -51,17 +53,19 @@ fn asm_benchmark(c: &mut Criterion) { fn mop_benchmark(c: &mut Criterion) { c.bench_function("interpret secp256k1_bench via assembly mop", |b| { let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into(); - let args: Vec = vec!["secp256k1_bench", - "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", - "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", - "foo", - "bar"].into_iter().map(|a| a.into()).collect(); + let args = [ + "secp256k1_bench", + "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", + "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", + "foo", + "bar", + ].into_iter().map(|a| Ok(a.into())); b.iter(|| { let asm_core = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, u64::max_value()); let core = DefaultMachineBuilder::>::new(asm_core) .build(); let mut machine = AsmMachine::new(core); - machine.load_program(&buffer, &args).unwrap(); + machine.load_program(&buffer, args.clone()).unwrap(); machine.run().unwrap() }); }); diff --git a/examples/check_real_memory.rs b/examples/check_real_memory.rs index 99720f38..87d22a9a 100644 --- a/examples/check_real_memory.rs +++ b/examples/check_real_memory.rs @@ -173,7 +173,7 @@ fn check_asm(memory_size: usize) -> Result<(), ()> { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&BIN_PATH_BUFFER, &vec![BIN_NAME.clone().into()]) + .load_program(&BIN_PATH_BUFFER, [Ok(BIN_NAME.clone().into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -198,7 +198,7 @@ fn check_asm_in_thread(memory_size: usize) -> Result<(), ()> { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&BIN_PATH_BUFFER, &vec![BIN_NAME.clone().into()]) + .load_program(&BIN_PATH_BUFFER, [Ok(BIN_NAME.clone().into())].into_iter()) .unwrap(); let thread_join_handle = thread::spawn(move || { let result = machine.run(); diff --git a/examples/ckb-vm-runner.rs b/examples/ckb-vm-runner.rs index 960fb3fa..f299ae9d 100644 --- a/examples/ckb-vm-runner.rs +++ b/examples/ckb-vm-runner.rs @@ -49,7 +49,7 @@ fn main_asm(code: Bytes, args: Vec) -> Result<(), Box) -> Result<(), Box>( memory_size, ); let mut machine = TraceMachine::new(DefaultMachineBuilder::new(core_machine).build()); - machine.load_program(program, args)?; + machine.load_program(program, args.iter().map(|e| Ok(e.clone())))?; machine.run() } diff --git a/src/machine/asm/mod.rs b/src/machine/asm/mod.rs index b062c9ab..6556326d 100644 --- a/src/machine/asm/mod.rs +++ b/src/machine/asm/mod.rs @@ -482,7 +482,11 @@ impl AsmMachine { self.machine.inner.max_cycles = cycles; } - pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { + pub fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { self.machine.load_program(program, args) } @@ -490,7 +494,7 @@ impl AsmMachine { &mut self, program: &Bytes, metadata: &ProgramMetadata, - args: &[Bytes], + args: impl ExactSizeIterator>, ) -> Result { self.machine .load_program_with_metadata(program, metadata, args) diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 6ee98df1..8f4cb1d5 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -12,7 +12,7 @@ use super::debugger::Debugger; use super::decoder::{build_decoder, Decoder}; use super::elf::{parse_elf, LoadingAction, ProgramMetadata}; use super::instructions::{execute, Instruction, Register}; -use super::memory::Memory; +use super::memory::{load_c_string_byte_by_byte, Memory}; use super::syscalls::Syscalls; use super::{ registers::{A0, A7, REGISTER_ABI_NAMES, SP}, @@ -171,7 +171,7 @@ pub trait SupportMachine: CoreMachine { fn initialize_stack( &mut self, - args: &[Bytes], + args: impl ExactSizeIterator>, stack_start: u64, stack_size: u64, ) -> Result { @@ -183,7 +183,7 @@ pub trait SupportMachine: CoreMachine { // reading "argc" will return an unexpected data. This situation is not very common. // // See https://github.com/nervosnetwork/ckb-vm/issues/106 for more details. - if self.version() >= VERSION1 && args.is_empty() { + if self.version() >= VERSION1 && args.len() == 0 { let argc_size = u64::from(Self::REG::BITS / 8); let origin_sp = stack_start + stack_size; let unaligned_sp_address = origin_sp - argc_size; @@ -200,15 +200,21 @@ pub trait SupportMachine: CoreMachine { // of each argv object. let mut values = vec![Self::REG::from_u64(args.len() as u64)]; for arg in args { + let arg = arg?; let len = Self::REG::from_u64(arg.len() as u64 + 1); let address = self.registers()[SP].overflowing_sub(&len); - self.memory_mut().store_bytes(address.to_u64(), arg)?; + self.memory_mut().store_bytes(address.to_u64(), &arg)?; self.memory_mut() .store_byte(address.to_u64() + arg.len() as u64, 1, 0)?; values.push(address.clone()); - self.set_register(SP, address); + self.set_register(SP, address.clone()); + + if self.version() >= VERSION2 && address.to_u64() < stack_start { + // Provides an early exit to large argv array. + return Err(Error::MemOutOfStack); + } } if self.version() >= VERSION1 { // There are 2 standard requirements of the initialized stack: @@ -246,7 +252,7 @@ pub trait SupportMachine: CoreMachine { self.set_register(SP, address); } if self.registers()[SP].to_u64() < stack_start { - // args exceed stack size + // Args exceed stack size. return Err(Error::MemOutOfStack); } Ok(stack_start + stack_size - self.registers()[SP].to_u64()) @@ -572,7 +578,11 @@ impl Display for DefaultMachine { } impl DefaultMachine { - pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { + pub fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { let elf_bytes = self.load_elf(program, true)?; let stack_bytes = self.initialize(args)?; let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| { @@ -587,7 +597,7 @@ impl DefaultMachine { &mut self, program: &Bytes, metadata: &ProgramMetadata, - args: &[Bytes], + args: impl ExactSizeIterator>, ) -> Result { let elf_bytes = self.load_binary(program, metadata, true)?; let stack_bytes = self.initialize(args)?; @@ -599,7 +609,10 @@ impl DefaultMachine { Ok(bytes) } - fn initialize(&mut self, args: &[Bytes]) -> Result { + fn initialize( + &mut self, + args: impl ExactSizeIterator>, + ) -> Result { for syscall in &mut self.syscalls { syscall.initialize(&mut self.inner)?; } @@ -759,6 +772,55 @@ impl Pause { } } +pub struct FlattenedArgsReader<'a, M: Memory> { + memory: &'a mut M, + argc: M::REG, + argv: M::REG, + cidx: M::REG, +} +impl<'a, M: Memory> FlattenedArgsReader<'a, M> { + pub fn new(memory: &'a mut M, argc: M::REG, argv: M::REG) -> Self { + Self { + memory, + argc, + argv, + cidx: M::REG::zero(), + } + } +} +impl<'a, M: Memory> Iterator for FlattenedArgsReader<'a, M> { + type Item = Result; + fn next(&mut self) -> Option { + if self.cidx.ge(&self.argc).to_u8() == 1 { + return None; + } + let addr = match M::REG::BITS { + 32 => self.memory.load32(&self.argv), + 64 => self.memory.load64(&self.argv), + _ => unreachable!(), + }; + if let Err(err) = addr { + return Some(Err(err)); + }; + let addr = addr.unwrap(); + let cstr = load_c_string_byte_by_byte(self.memory, &addr); + if let Err(err) = cstr { + return Some(Err(err)); + }; + let cstr = cstr.unwrap(); + self.cidx = self.cidx.overflowing_add(&M::REG::from_u8(1)); + self.argv = self + .argv + .overflowing_add(&M::REG::from_u8(M::REG::BITS / 8)); + Some(Ok(cstr)) + } +} +impl<'a, M: Memory> ExactSizeIterator for FlattenedArgsReader<'a, M> { + fn len(&self) -> usize { + self.argc.to_u64() as usize + } +} + #[cfg(test)] mod tests { use std::sync::atomic::AtomicU8; diff --git a/src/machine/trace.rs b/src/machine/trace.rs index ca3904eb..bf3dc919 100644 --- a/src/machine/trace.rs +++ b/src/machine/trace.rs @@ -113,7 +113,11 @@ impl TraceMachine { } } - pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { + pub fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { self.machine.load_program(program, args) } @@ -121,7 +125,7 @@ impl TraceMachine { &mut self, program: &Bytes, metadata: &ProgramMetadata, - args: &[Bytes], + args: impl ExactSizeIterator>, ) -> Result { self.machine .load_program_with_metadata(program, metadata, args) diff --git a/src/memory/mod.rs b/src/memory/mod.rs index aed0a131..964bbc8a 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -144,3 +144,20 @@ pub fn memset(slice: &mut [u8], value: u8) { ptr::write_bytes(p, value, slice.len()); } } + +pub fn load_c_string_byte_by_byte( + memory: &mut M, + addr: &M::REG, +) -> Result { + let mut buffer = Vec::new(); + let mut addr = addr.clone(); + loop { + let byte = memory.load8(&addr)?.to_u8(); + if byte == 0 { + break; + } + buffer.push(byte); + addr = addr.overflowing_add(&M::REG::from_u8(1)); + } + Ok(Bytes::from(buffer)) +} diff --git a/tests/machine_build.rs b/tests/machine_build.rs index 9ae2ad51..462c3355 100644 --- a/tests/machine_build.rs +++ b/tests/machine_build.rs @@ -39,7 +39,7 @@ pub fn asm_v1_imcb(path: &str) -> AsmMachine { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec![Bytes::from("main")]) + .load_program(&buffer, [Ok(Bytes::from("main"))].into_iter()) .unwrap(); machine } @@ -60,7 +60,7 @@ pub fn int_v1_imcb( .build(), ); machine - .load_program(&buffer, &vec![Bytes::from("main")]) + .load_program(&buffer, [Ok(Bytes::from("main"))].into_iter()) .unwrap(); machine } @@ -81,7 +81,9 @@ pub fn asm_mop(path: &str, args: Vec, version: u32) -> AsmMachine { let mut machine = AsmMachine::new(core); let mut argv = vec![Bytes::from("main")]; argv.extend_from_slice(&args); - machine.load_program(&buffer, &argv).unwrap(); + machine + .load_program(&buffer, argv.into_iter().map(Ok)) + .unwrap(); machine } @@ -111,7 +113,9 @@ pub fn int_mop( ); let mut argv = vec![Bytes::from("main")]; argv.extend_from_slice(&args); - machine.load_program(&buffer, &argv).unwrap(); + machine + .load_program(&buffer, argv.into_iter().map(Ok)) + .unwrap(); machine } @@ -125,7 +129,7 @@ pub fn asm_v2_imacb(path: &str) -> AsmMachine { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec![Bytes::from("main")]) + .load_program(&buffer, [Ok(Bytes::from("main"))].into_iter()) .unwrap(); machine } @@ -146,7 +150,7 @@ pub fn int_v2_imacb( .build(), ); machine - .load_program(&buffer, &vec![Bytes::from("main")]) + .load_program(&buffer, [Ok(Bytes::from("main"))].into_iter()) .unwrap(); machine } diff --git a/tests/test_asm.rs b/tests/test_asm.rs index b114b62b..e5e8b58e 100644 --- a/tests/test_asm.rs +++ b/tests/test_asm.rs @@ -19,7 +19,7 @@ pub fn test_asm_simple64() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -58,7 +58,7 @@ pub fn test_asm_with_custom_syscall() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, [Ok("syscall".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -94,7 +94,7 @@ pub fn test_asm_ebreak() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["ebreak".into()]) + .load_program(&buffer, [Ok("ebreak".into())].into_iter()) .unwrap(); assert_eq!(value.load(Ordering::Relaxed), 1); let result = machine.run(); @@ -111,7 +111,7 @@ pub fn test_asm_simple_cycles() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, [Ok("syscall".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -130,7 +130,7 @@ pub fn test_asm_simple_max_cycles_reached() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, [Ok("syscall".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -144,7 +144,7 @@ pub fn test_asm_trace() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -158,7 +158,7 @@ pub fn test_asm_jump0() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["jump0_64".into()]) + .load_program(&buffer, [Ok("jump0_64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -174,7 +174,7 @@ pub fn test_asm_write_large_address() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["write_large_address64".into()]) + .load_program(&buffer, [Ok("write_large_address64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -188,7 +188,7 @@ pub fn test_misaligned_jump64() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["misaligned_jump64".into()]) + .load_program(&buffer, [Ok("misaligned_jump64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -201,7 +201,7 @@ pub fn test_mulw64() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["mulw64".into()]) + .load_program(&buffer, [Ok("mulw64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -215,7 +215,7 @@ pub fn test_invalid_read64() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["invalid_read64".into()]) + .load_program(&buffer, [Ok("invalid_read64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -229,7 +229,7 @@ pub fn test_asm_load_elf_crash_64() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["load_elf_crash_64".into()]) + .load_program(&buffer, [Ok("load_elf_crash_64".into())].into_iter()) .unwrap(); let result = machine.run(); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage)); @@ -242,7 +242,7 @@ pub fn test_asm_wxorx_crash_64() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["wxorx_crash_64".into()]) + .load_program(&buffer, [Ok("wxorx_crash_64".into())].into_iter()) .unwrap(); let result = machine.run(); assert_eq!(result.err(), Some(Error::MemOutOfBound)); @@ -255,7 +255,7 @@ pub fn test_asm_alloc_many() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result = machine.run(); assert_eq!(result.unwrap(), 0); @@ -270,7 +270,7 @@ pub fn test_asm_chaos_seed() { let core1 = DefaultMachineBuilder::>::new(asm_core1).build(); let mut machine1 = AsmMachine::new(core1); machine1 - .load_program(&buffer, &vec!["read_memory".into()]) + .load_program(&buffer, [Ok("read_memory".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let exit1 = result1.unwrap(); @@ -281,7 +281,7 @@ pub fn test_asm_chaos_seed() { let core2 = DefaultMachineBuilder::>::new(asm_core2).build(); let mut machine2 = AsmMachine::new(core2); machine2 - .load_program(&buffer, &vec!["read_memory".into()]) + .load_program(&buffer, [Ok("read_memory".into())].into_iter()) .unwrap(); let result2 = machine2.run(); let exit2 = result2.unwrap(); @@ -299,7 +299,7 @@ pub fn test_asm_rvc_pageend() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["rvc_pageend".into()]) + .load_program(&buffer, [Ok("rvc_pageend".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -340,7 +340,7 @@ pub fn test_asm_outofcycles_in_syscall() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, [Ok("syscall".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -359,7 +359,7 @@ pub fn test_asm_cycles_overflow() { let mut machine = AsmMachine::new(core); machine.machine.set_cycles(u64::MAX - 10); machine - .load_program(&buffer, &vec!["simple64".into()]) + .load_program(&buffer, [Ok("simple64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -378,7 +378,7 @@ pub fn test_decoder_instructions_cache_pc_out_of_bound_timeout() { let mut machine = AsmMachine::new(core); machine.machine.set_cycles(u64::MAX - 10); machine - .load_program(&buffer, &vec!["simple64".into()]) + .load_program(&buffer, [Ok("simple64".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -391,7 +391,7 @@ pub fn test_asm_step() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["simple64".into()]) + .load_program(&buffer, [Ok("simple64".into())].into_iter()) .unwrap(); let result = || -> Result { @@ -414,7 +414,7 @@ fn test_asm_thread_safe() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["mulw64".into()]) + .load_program(&buffer, [Ok("mulw64".into())].into_iter()) .unwrap(); let thread_join_handle = thread::spawn(move || { let result = machine.run(); @@ -430,7 +430,9 @@ fn test_zero_address() { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION1, u64::max_value()); let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); - machine.load_program(&buffer, &vec!["zero".into()]).unwrap(); + machine + .load_program(&buffer, [Ok("zero".into())].into_iter()) + .unwrap(); let result = machine.run(); assert!(result.is_ok()); assert_eq!(result.unwrap(), 0); @@ -442,6 +444,6 @@ pub fn test_big_binary() { let asm_core = AsmCoreMachine::new_with_memory(ISA_IMC, VERSION2, u64::max_value(), 1024 * 512); let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); - let result = machine.load_program(&buffer, &vec!["simple".into()]); + let result = machine.load_program(&buffer, [Ok("simple".into())].into_iter()); assert_eq!(result, Err(Error::MemOutOfBound)); } diff --git a/tests/test_auipc_fusion.rs b/tests/test_auipc_fusion.rs index b179d85e..2cafd79e 100644 --- a/tests/test_auipc_fusion.rs +++ b/tests/test_auipc_fusion.rs @@ -58,7 +58,7 @@ pub fn test_rust_auipc_fusion() { DefaultCoreMachine::>::new(ISA_IMC, VERSION1, u64::max_value()); let mut machine = DefaultMachineBuilder::new(core_machine).build(); machine - .load_program(&buffer, &vec!["auipc_no_sign_extend".into()]) + .load_program(&buffer, [Ok("auipc_no_sign_extend".into())].into_iter()) .unwrap(); let mut decoder = AuxDecoder::new(build_decoder::(machine.isa(), machine.version())); @@ -89,7 +89,7 @@ pub fn test_asm_auipc_fusion() { let core = DefaultMachineBuilder::>::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["auipc_no_sign_extend".into()]) + .load_program(&buffer, [Ok("auipc_no_sign_extend".into())].into_iter()) .unwrap(); let mut decoder = AuxDecoder::new(build_decoder::( diff --git a/tests/test_dy_memory.rs b/tests/test_dy_memory.rs index 1652010c..12ba3e76 100644 --- a/tests/test_dy_memory.rs +++ b/tests/test_dy_memory.rs @@ -27,7 +27,7 @@ fn run_memory_suc(memory_size: usize, bin_path: String, bin_name: String) { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec![bin_name.into()]) + .load_program(&buffer, [Ok(bin_name.into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -63,7 +63,7 @@ fn test_memory_out_of_bounds() { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); diff --git a/tests/test_misc.rs b/tests/test_misc.rs index 5bab12e6..dd259435 100644 --- a/tests/test_misc.rs +++ b/tests/test_misc.rs @@ -61,7 +61,7 @@ pub fn test_custom_syscall() { .syscall(Box::new(CustomSyscall {})) .build(); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, [Ok("syscall".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -96,7 +96,7 @@ pub fn test_ebreak() { })) .build(); machine - .load_program(&buffer, &vec!["ebreak".into()]) + .load_program(&buffer, [Ok("ebreak".into())].into_iter()) .unwrap(); assert_eq!(value.load(Ordering::Relaxed), 1); let result = machine.run(); @@ -212,7 +212,7 @@ pub fn test_flat_crash_64() { let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::max_value()); let mut machine = DefaultMachineBuilder::new(core_machine).build(); - let result = machine.load_program(&buffer, &vec!["flat_crash_64".into()]); + let result = machine.load_program(&buffer, [Ok("flat_crash_64".into())].into_iter()); assert_eq!(result.err(), Some(Error::MemOutOfBound)); } @@ -363,7 +363,7 @@ pub fn test_rvc_pageend() { DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::max_value()); let mut machine = DefaultMachineBuilder::new(core_machine).build(); machine - .load_program(&buffer, &vec!["rvc_end".into()]) + .load_program(&buffer, [Ok("rvc_end".into())].into_iter()) .unwrap(); let anchor_pc: u64 = 69630; @@ -417,7 +417,7 @@ pub fn test_outofcycles_in_syscall() { .syscall(Box::new(OutOfCyclesSyscall {})) .build(); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, [Ok("syscall".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); diff --git a/tests/test_reset.rs b/tests/test_reset.rs index 11f00e2b..b9c1e557 100644 --- a/tests/test_reset.rs +++ b/tests/test_reset.rs @@ -30,7 +30,7 @@ impl Syscalls for CustomSyscall { let code = Bytes::from(code_data); machine.load_elf(&code, true).unwrap(); machine.initialize_stack( - &[], + [].into_iter(), (RISCV_MAX_MEMORY - DEFAULT_STACK_SIZE) as u64, DEFAULT_STACK_SIZE as u64, )?; @@ -52,7 +52,7 @@ fn test_reset_int() { .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(CustomSyscall {})) .build(); - machine.load_program(&code, &vec![]).unwrap(); + machine.load_program(&code, [].into_iter()).unwrap(); let result = machine.run(); let cycles = machine.cycles(); assert!(result.is_ok()); @@ -76,7 +76,7 @@ fn test_reset_int_with_trace() { .syscall(Box::new(CustomSyscall {})) .build(), ); - machine.load_program(&code, &vec![]).unwrap(); + machine.load_program(&code, [].into_iter()).unwrap(); let result = machine.run(); let cycles = machine.machine.cycles(); assert!(result.is_ok()); @@ -96,7 +96,7 @@ fn test_reset_asm() { .syscall(Box::new(CustomSyscall {})) .build(); let mut machine = AsmMachine::new(core); - machine.load_program(&code, &vec![]).unwrap(); + machine.load_program(&code, [].into_iter()).unwrap(); let result = machine.run(); let cycles = machine.machine.cycles(); diff --git a/tests/test_resume.rs b/tests/test_resume.rs index 0d589abd..825bae60 100644 --- a/tests/test_resume.rs +++ b/tests/test_resume.rs @@ -55,7 +55,7 @@ pub fn resume_asm_2_asm(version: u32, except_cycles: u64) { // The cycles required for complete execution is 4194622 let mut machine1 = MachineTy::Asm.build(version, except_cycles - 30); machine1 - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -77,7 +77,7 @@ pub fn resume_asm_2_asm_2_asm(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Asm.build(version, 1000000); machine1 - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -107,7 +107,7 @@ pub fn resume_asm_2_interpreter(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Asm.build(version, except_cycles - 30); machine1 - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -130,7 +130,7 @@ pub fn resume_interpreter_2_interpreter(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Interpreter.build(version, except_cycles - 30); machine1 - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -152,7 +152,7 @@ pub fn resume_interpreter_2_asm(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Interpreter.build(version, except_cycles - 30); machine1 - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -174,7 +174,7 @@ pub fn resume_interpreter_with_trace_2_asm_inner(version: u32, except_cycles: u6 let mut machine1 = MachineTy::InterpreterWithTrace.build(version, except_cycles - 30); machine1 - .load_program(&buffer, &vec!["alloc_many".into()]) + .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -251,7 +251,11 @@ enum Machine { } impl Machine { - fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { + fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { use Machine::*; match self { Asm(inner) => inner.load_program(program, args), diff --git a/tests/test_resume2.rs b/tests/test_resume2.rs index be79b280..24a17fe4 100644 --- a/tests/test_resume2.rs +++ b/tests/test_resume2.rs @@ -62,15 +62,13 @@ fn test_resume2_secp256k1_asm_2_interpreter_2_asm() { let mut machine1 = MachineTy::Asm.build(data_source.clone(), version); machine1.set_max_cycles(100000); - machine1 - .load_program(&vec![ - "secp256k1_bench".into(), - "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f".into(), - "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3".into(), - "foo".into(), - "bar".into(), - ]) - .unwrap(); + machine1.load_program([ + "secp256k1_bench", + "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", + "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", + "foo", + "bar", + ].into_iter().map(|e| Ok(e.into()))).unwrap(); let result1 = machine1.run(); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); let snapshot1 = machine1.snapshot().unwrap(); @@ -115,7 +113,7 @@ fn test_resume2_load_data_asm_2_interpreter() { let mut machine1 = MachineTy::Asm.build(data_source.clone(), version); machine1.set_max_cycles(300000); machine1 - .load_program(&vec!["resume2_load_data".into()]) + .load_program([Ok("resume2_load_data".into())].into_iter()) .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); @@ -149,7 +147,7 @@ fn test_resume2_load_data_interpreter_2_asm() { let mut machine1 = MachineTy::Interpreter.build(data_source.clone(), version); machine1.set_max_cycles(300000); machine1 - .load_program(&vec!["resume2_load_data".into()]) + .load_program([Ok("resume2_load_data".into())].into_iter()) .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); @@ -179,7 +177,9 @@ pub fn resume_asm_2_asm(version: u32, except_cycles: u64) { // The cycles required for complete execution is 4194622 let mut machine1 = MachineTy::Asm.build(data_source.clone(), version); machine1.set_max_cycles(except_cycles - 30); - machine1.load_program(&vec!["alloc_many".into()]).unwrap(); + machine1 + .load_program([Ok("alloc_many".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -199,7 +199,9 @@ pub fn resume_asm_2_asm_2_asm(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Asm.build(data_source.clone(), version); machine1.set_max_cycles(1000000); - machine1.load_program(&vec!["alloc_many".into()]).unwrap(); + machine1 + .load_program([Ok("alloc_many".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -227,7 +229,9 @@ pub fn resume_asm_2_interpreter(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Asm.build(data_source.clone(), version); machine1.set_max_cycles(except_cycles - 30); - machine1.load_program(&vec!["alloc_many".into()]).unwrap(); + machine1 + .load_program([Ok("alloc_many".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -248,7 +252,9 @@ pub fn resume_interpreter_2_interpreter(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Interpreter.build(data_source.clone(), version); machine1.set_max_cycles(except_cycles - 30); - machine1.load_program(&vec!["alloc_many".into()]).unwrap(); + machine1 + .load_program([Ok("alloc_many".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -268,7 +274,9 @@ pub fn resume_interpreter_2_asm(version: u32, except_cycles: u64) { let mut machine1 = MachineTy::Interpreter.build(data_source.clone(), version); machine1.set_max_cycles(except_cycles - 30); - machine1.load_program(&vec!["alloc_many".into()]).unwrap(); + machine1 + .load_program([Ok("alloc_many".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -288,7 +296,9 @@ pub fn resume_interpreter_with_trace_2_asm_inner(version: u32, except_cycles: u6 let mut machine1 = MachineTy::InterpreterWithTrace.build(data_source.clone(), version); machine1.set_max_cycles(except_cycles - 30); - machine1.load_program(&vec!["alloc_many".into()]).unwrap(); + machine1 + .load_program([Ok("alloc_many".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -442,7 +452,10 @@ enum Machine { } impl Machine { - fn load_program(&mut self, args: &[Bytes]) -> Result { + fn load_program( + &mut self, + args: impl ExactSizeIterator>, + ) -> Result { use Machine::*; match self { Asm(inner, context) => { @@ -607,7 +620,9 @@ pub fn test_sc_after_snapshot2() { let mut machine1 = MachineTy::Interpreter.build(data_source.clone(), VERSION2); machine1.set_max_cycles(5); - machine1.load_program(&vec!["main".into()]).unwrap(); + machine1 + .load_program([Ok("main".into())].into_iter()) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -628,7 +643,9 @@ pub fn test_store_bytes_twice() { let mut machine = MachineTy::Asm.build(data_source.clone(), VERSION2); machine.set_max_cycles(u64::MAX); - machine.load_program(&vec!["main".into()]).unwrap(); + machine + .load_program([Ok("main".into())].into_iter()) + .unwrap(); match machine { Machine::Asm(ref mut inner, ref ctx) => { @@ -661,7 +678,9 @@ pub fn test_mixing_snapshot2_writes_with_machine_raw_writes() { let mut machine = MachineTy::Asm.build(data_source.clone(), VERSION2); machine.set_max_cycles(u64::MAX); - machine.load_program(&vec!["main".into()]).unwrap(); + machine + .load_program([Ok("main".into())].into_iter()) + .unwrap(); match machine { Machine::Asm(ref mut inner, ref ctx) => { diff --git a/tests/test_simple.rs b/tests/test_simple.rs index 1c9f6bc9..5c6d3cd1 100644 --- a/tests/test_simple.rs +++ b/tests/test_simple.rs @@ -42,7 +42,7 @@ pub fn test_simple_cycles() { .instruction_cycle_func(Box::new(dummy_cycle_func)) .build(); machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -61,7 +61,7 @@ pub fn test_simple_max_cycles_reached() { .instruction_cycle_func(Box::new(dummy_cycle_func)) .build(); machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -83,7 +83,7 @@ pub fn test_simple_loaded_bytes() { DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::max_value()); let mut machine = DefaultMachineBuilder::new(core_machine).build(); let bytes = machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); assert_eq!(bytes, 3831); } @@ -99,7 +99,7 @@ pub fn test_simple_cycles_overflow() { .build(); machine.set_cycles(u64::MAX - 10); machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); let result = machine.run(); assert!(result.is_err()); diff --git a/tests/test_versions.rs b/tests/test_versions.rs index 40921bcd..160accb4 100644 --- a/tests/test_versions.rs +++ b/tests/test_versions.rs @@ -21,7 +21,7 @@ fn create_rust_machine( let mut machine = DefaultMachineBuilder::>::new(core_machine).build(); machine - .load_program(&buffer, &vec![program.into()]) + .load_program(&buffer, [Ok(program.into())].into_iter()) .unwrap(); machine } @@ -33,7 +33,7 @@ fn create_asm_machine(program: String, version: u32) -> AsmMachine { let core = DefaultMachineBuilder::>::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec![program.into()]) + .load_program(&buffer, [Ok(program.into())].into_iter()) .unwrap(); machine } @@ -239,7 +239,7 @@ pub fn test_rust_version0_unaligned64() { let core_machine = DefaultCoreMachine::::new(ISA_IMC, VERSION0, u64::max_value()); let mut machine = DefaultMachineBuilder::>::new(core_machine).build(); - let result = machine.load_program(&buffer, &vec![program.into()]); + let result = machine.load_program(&buffer, [Ok(program.into())].into_iter()); assert!(result.is_err()); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage)); } @@ -261,7 +261,7 @@ pub fn test_asm_version0_unaligned64() { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::max_value()); let core = DefaultMachineBuilder::>::new(asm_core).build(); let mut machine = AsmMachine::new(core); - let result = machine.load_program(&buffer, &vec![program.into()]); + let result = machine.load_program(&buffer, [Ok(program.into())].into_iter()); assert!(result.is_err()); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage)); } @@ -344,7 +344,7 @@ pub fn test_asm_version1_asm_trace_bug() { .build(); AsmMachine::new(machine) }; - machine.load_program(&buffer, &[]).unwrap(); + machine.load_program(&buffer, [].into_iter()).unwrap(); let result = machine.run(); assert_eq!(result, Err(Error::CyclesExceeded)); @@ -361,7 +361,7 @@ pub fn test_asm_version2_asm_trace_bug() { .build(); AsmMachine::new(machine) }; - machine.load_program(&buffer, &[]).unwrap(); + machine.load_program(&buffer, [].into_iter()).unwrap(); let result = machine.run(); assert_eq!(result, Err(Error::MemOutOfBound)); @@ -383,7 +383,7 @@ pub fn test_trace_version1_asm_trace_bug() { .build(), ) }; - machine.load_program(&buffer, &[]).unwrap(); + machine.load_program(&buffer, [].into_iter()).unwrap(); let result = machine.run(); assert_eq!(result, Err(Error::CyclesExceeded)); @@ -405,7 +405,7 @@ pub fn test_trace_version2_asm_trace_bug() { .build(), ) }; - machine.load_program(&buffer, &[]).unwrap(); + machine.load_program(&buffer, [].into_iter()).unwrap(); let result = machine.run(); assert_eq!(result, Err(Error::MemOutOfBound));