diff --git a/definitions/src/asm.rs b/definitions/src/asm.rs index 7a99e5c3..5bf040df 100644 --- a/definitions/src/asm.rs +++ b/definitions/src/asm.rs @@ -105,6 +105,36 @@ pub struct AsmCoreMachine { pub frames_ptr: u64, } +impl Clone for AsmCoreMachine { + fn clone(&self) -> Self { + let mut r = Self { ..*self }; + let memory_layout = Layout::array::(r.memory_size as usize).unwrap(); + let flags_layout = Layout::array::(r.flags_size as usize).unwrap(); + let frames_layout = Layout::array::(r.frames_size as usize).unwrap(); + unsafe { + r.memory_ptr = alloc(memory_layout) as u64; + std::ptr::copy_nonoverlapping( + self.memory_ptr as *const u8, + r.memory_ptr as *mut u8, + r.memory_size as usize, + ); + r.flags_ptr = alloc_zeroed(flags_layout) as u64; + std::ptr::copy_nonoverlapping( + self.flags_ptr as *const u8, + r.flags_ptr as *mut u8, + r.flags_size as usize, + ); + r.frames_ptr = alloc_zeroed(frames_layout) as u64; + std::ptr::copy_nonoverlapping( + self.frames_ptr as *const u8, + r.frames_ptr as *mut u8, + r.frames_size as usize, + ); + } + r + } +} + impl Drop for AsmCoreMachine { fn drop(&mut self) { let memory_layout = Layout::array::(self.memory_size as usize).unwrap(); diff --git a/definitions/src/lib.rs b/definitions/src/lib.rs index 69b979a9..176cbbd1 100644 --- a/definitions/src/lib.rs +++ b/definitions/src/lib.rs @@ -11,6 +11,7 @@ pub const MEMORY_FRAMESIZE: usize = 1 << MEMORY_FRAME_SHIFTS; // 256 KB pub const MEMORY_FRAME_PAGE_SHIFTS: usize = MEMORY_FRAME_SHIFTS - RISCV_PAGE_SHIFTS; pub const DEFAULT_MEMORY_SIZE: usize = 4 << 20; // 4 MB +pub const DEFAULT_STACK_SIZE: usize = 1 << 20; // 1 MB pub const ISA_IMC: u8 = 0b0000_0000; pub const ISA_B: u8 = 0b0000_0001; diff --git a/examples/check_real_memory.rs b/examples/check_real_memory.rs index c0735ec7..1071ca04 100644 --- a/examples/check_real_memory.rs +++ b/examples/check_real_memory.rs @@ -8,7 +8,7 @@ use std::process::{id, Command}; use ckb_vm::{ machine::{ asm::{AsmCoreMachine, AsmMachine}, - DefaultMachineBuilder, VERSION0, + ArgsIterStatic, DefaultMachineBuilder, VERSION0, }, ISA_IMC, }; @@ -168,7 +168,11 @@ fn check_asm(memory_size: usize) -> Result<(), ()> { let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine - .load_program(&Bytes::from(BIN_PATH_BUFFER), &vec![Bytes::from(BIN_NAME)]) + .load_program( + &Bytes::from(BIN_PATH_BUFFER), + 1, + ArgsIterStatic::new(vec![Bytes::from(BIN_NAME)]), + ) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -192,7 +196,11 @@ 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(&Bytes::from(BIN_PATH_BUFFER), &vec![Bytes::from(BIN_NAME)]) + .load_program( + &Bytes::from(BIN_PATH_BUFFER), + 1, + ArgsIterStatic::new(vec![Bytes::from(BIN_NAME)]), + ) .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 b183d4f2..5994629a 100644 --- a/examples/ckb_vm_runner.rs +++ b/examples/ckb_vm_runner.rs @@ -1,6 +1,6 @@ use ckb_vm::cost_model::estimate_cycles; use ckb_vm::registers::{A0, A7}; -use ckb_vm::{Bytes, CoreMachine, Memory, Register, SupportMachine, Syscalls}; +use ckb_vm::{ArgsIterStatic, Bytes, CoreMachine, Memory, Register, SupportMachine, Syscalls}; pub struct DebugSyscall {} @@ -49,7 +49,7 @@ fn main_asm(code: Bytes, args: Vec) -> Result<(), Box) -> Result<(), Box + Default>( WXorXMemory::new(M::default()), ); let mut machine = TraceMachine::new(DefaultMachineBuilder::new(core_machine).build()); - machine.load_program(program, args)?; + machine.load_program(program, args.len(), ArgsIterStatic::new(args.to_vec()))?; machine.run() } @@ -63,7 +64,7 @@ pub fn run_with_memory>( WXorXMemory::new(memory), ); let mut machine = TraceMachine::new(DefaultMachineBuilder::new(core_machine).build()); - machine.load_program(program, args)?; + machine.load_program(program, args.len(), ArgsIterStatic::new(args.to_vec()))?; machine.run() } diff --git a/src/machine/asm/mod.rs b/src/machine/asm/mod.rs index a5ede118..bfe44d3c 100644 --- a/src/machine/asm/mod.rs +++ b/src/machine/asm/mod.rs @@ -248,6 +248,12 @@ impl<'a> FastMemory<'a> { } } +impl<'a> Clone for FastMemory<'a> { + fn clone(&self) -> Self { + unimplemented!() + } +} + impl<'a> Memory for FastMemory<'a> { type REG = u64; @@ -666,18 +672,24 @@ impl AsmMachine { self.machine.inner.max_cycles = cycles; } - pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { - self.machine.load_program(program, args) + pub fn load_program( + &mut self, + program: &Bytes, + argc: usize, + args: impl Iterator>, + ) -> Result { + self.machine.load_program(program, argc, args) } pub fn load_program_with_metadata( &mut self, program: &Bytes, metadata: &ProgramMetadata, - args: &[Bytes], + argc: usize, + args: impl Iterator>, ) -> Result { self.machine - .load_program_with_metadata(program, metadata, args) + .load_program_with_metadata(program, metadata, argc, args) } pub fn run(&mut self) -> Result { diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 8babb792..66707aaa 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -171,7 +171,8 @@ pub trait SupportMachine: CoreMachine { fn initialize_stack( &mut self, - args: &[Bytes], + argc: usize, + args: impl Iterator>, stack_start: u64, stack_size: u64, ) -> Result { @@ -183,7 +184,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 && argc == 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; @@ -198,18 +199,24 @@ pub trait SupportMachine: CoreMachine { self.set_register(SP, Self::REG::from_u64(stack_start + stack_size)); // First value in this array is argc, then it contains the address(pointer) // of each argv object. - let mut values = vec![Self::REG::from_u64(args.len() as u64)]; + let mut values = vec![Self::REG::from_u64(argc 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); } + if values.len() != argc + 1 { + return Err(Error::Unexpected(String::from( + "argc and argc do not match", + ))); + } if self.version() >= VERSION1 { // There are 2 standard requirements of the initialized stack: // 1. argv[argc] should contain a null pointer here, hence we are @@ -575,9 +582,14 @@ 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, + argc: usize, + args: impl Iterator>, + ) -> Result { let elf_bytes = self.load_elf(program, true)?; - let stack_bytes = self.initialize(args)?; + let stack_bytes = self.initialize(argc, args)?; let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| { Error::Unexpected(String::from( "The bytes count overflowed on loading program", @@ -590,10 +602,11 @@ impl DefaultMachine { &mut self, program: &Bytes, metadata: &ProgramMetadata, - args: &[Bytes], + argc: usize, + args: impl Iterator>, ) -> Result { let elf_bytes = self.load_binary(program, metadata, true)?; - let stack_bytes = self.initialize(args)?; + let stack_bytes = self.initialize(argc, args)?; let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| { Error::Unexpected(String::from( "The bytes count overflowed on loading program", @@ -602,7 +615,11 @@ impl DefaultMachine { Ok(bytes) } - fn initialize(&mut self, args: &[Bytes]) -> Result { + fn initialize( + &mut self, + argc: usize, + args: impl Iterator>, + ) -> Result { for syscall in &mut self.syscalls { syscall.initialize(&mut self.inner)?; } @@ -611,8 +628,12 @@ impl DefaultMachine { } let memory_size = self.memory().memory_size(); let stack_size = memory_size / 4; - let stack_bytes = - self.initialize_stack(args, (memory_size - stack_size) as u64, stack_size as u64)?; + let stack_bytes = self.initialize_stack( + argc, + args, + (memory_size - stack_size) as u64, + stack_size as u64, + )?; // Make sure SP is 16 byte aligned if self.inner.version() >= VERSION1 { debug_assert!(self.registers()[SP].to_u64() % 16 == 0); @@ -766,6 +787,77 @@ impl Pause { } } +pub struct ArgsIterStream<'a, M: Memory> { + memory: &'a mut M, + argc: M::REG, + argp: M::REG, + cidx: M::REG, +} + +impl<'a, M: Memory> ArgsIterStream<'a, M> { + pub fn new(memory: &'a mut M, argc: M::REG, argp: M::REG) -> Self { + Self { + memory, + argc, + argp, + cidx: M::REG::zero(), + } + } +} + +impl<'a, M: Memory> Iterator for ArgsIterStream<'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.argp), + 64 => self.memory.load64(&self.argp), + _ => unreachable!(), + }; + if let Err(err) = addr { + return Some(Err(err)); + }; + let addr = addr.unwrap(); + let cstr = self.memory.load_c_string(&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.argp = self + .argp + .overflowing_add(&M::REG::from_u8(M::REG::BITS / 8)); + Some(Ok(cstr)) + } +} + +pub struct ArgsIterStatic { + argv: Vec, + cidx: usize, +} + +impl ArgsIterStatic { + pub fn new(argv: Vec) -> Self { + Self { argv, cidx: 0 } + } +} + +impl Iterator for ArgsIterStatic { + type Item = Result; + + fn next(&mut self) -> Option { + if self.cidx >= self.argv.len() { + return None; + } + let cstr = self.argv[self.cidx].clone(); + self.cidx += 1; + return Some(Ok(cstr)); + } +} + #[cfg(test)] mod tests { use std::sync::atomic::AtomicU8; diff --git a/src/machine/trace.rs b/src/machine/trace.rs index 9b500f23..eb870dce 100644 --- a/src/machine/trace.rs +++ b/src/machine/trace.rs @@ -113,18 +113,24 @@ impl TraceMachine { } } - pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { - self.machine.load_program(program, args) + pub fn load_program( + &mut self, + program: &Bytes, + argc: usize, + args: impl Iterator>, + ) -> Result { + self.machine.load_program(program, argc, args) } pub fn load_program_with_metadata( &mut self, program: &Bytes, metadata: &ProgramMetadata, - args: &[Bytes], + argc: usize, + args: impl Iterator>, ) -> Result { self.machine - .load_program_with_metadata(program, metadata, args) + .load_program_with_metadata(program, metadata, argc, args) } pub fn set_max_cycles(&mut self, cycles: u64) { diff --git a/src/memory/flat.rs b/src/memory/flat.rs index 07160584..b475c350 100644 --- a/src/memory/flat.rs +++ b/src/memory/flat.rs @@ -9,6 +9,7 @@ use std::io::{Cursor, Seek, SeekFrom}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; +#[derive(Clone)] pub struct FlatMemory { data: Vec, flags: Vec, diff --git a/src/memory/mod.rs b/src/memory/mod.rs index bde9e784..c417d5a7 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -28,7 +28,7 @@ pub fn round_page_up(x: u64) -> u64 { pub type Page = [u8; RISCV_PAGESIZE]; -pub trait Memory { +pub trait Memory: Clone { type REG: Register; fn reset_memory(&mut self) -> Result<(), Error>; @@ -63,6 +63,19 @@ pub trait Memory { fn load16(&mut self, addr: &Self::REG) -> Result; fn load32(&mut self, addr: &Self::REG) -> Result; fn load64(&mut self, addr: &Self::REG) -> Result; + fn load_c_string(&mut self, addr: &Self::REG) -> Result { + let mut buffer = Vec::new(); + let mut addr = addr.clone(); + loop { + let byte = self.load8(&addr)?.to_u8(); + if byte == 0 { + break; + } + buffer.push(byte); + addr = addr.overflowing_add(&Self::REG::from_u8(1)); + } + Ok(Bytes::from(buffer)) + } fn store8(&mut self, addr: &Self::REG, value: &Self::REG) -> Result<(), Error>; fn store16(&mut self, addr: &Self::REG, value: &Self::REG) -> Result<(), Error>; diff --git a/src/memory/sparse.rs b/src/memory/sparse.rs index 09cf9178..c8005ef7 100644 --- a/src/memory/sparse.rs +++ b/src/memory/sparse.rs @@ -11,6 +11,7 @@ const INVALID_PAGE_INDEX: u16 = 0xFFFF; /// A sparse flat memory implementation, it allocates pages only when requested, /// but besides that, it does not permission checking. +#[derive(Clone)] pub struct SparseMemory { // Stores the indices of each page in pages data structure, if a page hasn't // been initialized, the corresponding position will be filled with diff --git a/src/memory/wxorx.rs b/src/memory/wxorx.rs index 8d773852..565c2100 100644 --- a/src/memory/wxorx.rs +++ b/src/memory/wxorx.rs @@ -6,6 +6,7 @@ use super::{ use bytes::Bytes; +#[derive(Clone)] pub struct WXorXMemory { inner: M, } diff --git a/tests/machine_build.rs b/tests/machine_build.rs index cb4fcc57..d3f9c898 100644 --- a/tests/machine_build.rs +++ b/tests/machine_build.rs @@ -2,7 +2,7 @@ use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; #[cfg(has_asm)] use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; -use ckb_vm::machine::{trace::TraceMachine, DefaultCoreMachine}; +use ckb_vm::machine::{trace::TraceMachine, ArgsIterStatic, DefaultCoreMachine}; use ckb_vm::registers::{A0, A7}; use ckb_vm::{ DefaultMachineBuilder, Error, Register, SparseMemory, SupportMachine, Syscalls, WXorXMemory, @@ -39,7 +39,9 @@ pub fn asm(path: &str, args: Vec, version: u32, isa: u8) -> 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.len(), ArgsIterStatic::new(argv)) + .unwrap(); machine } @@ -60,6 +62,8 @@ pub fn int( ); let mut argv = vec![Bytes::from("main")]; argv.extend_from_slice(&args); - machine.load_program(&buffer, &argv).unwrap(); + machine + .load_program(&buffer, argv.len(), ArgsIterStatic::new(argv)) + .unwrap(); machine } diff --git a/tests/test_asm.rs b/tests/test_asm.rs index 14e0e2b7..56feb514 100644 --- a/tests/test_asm.rs +++ b/tests/test_asm.rs @@ -8,7 +8,10 @@ use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; use ckb_vm::machine::{CoreMachine, VERSION0, VERSION1, VERSION2}; use ckb_vm::memory::Memory; use ckb_vm::registers::{A0, A1, A2, A3, A4, A5, A7}; -use ckb_vm::{Debugger, DefaultMachineBuilder, Error, Register, SupportMachine, Syscalls, ISA_IMC}; +use ckb_vm::{ + ArgsIterStatic, Debugger, DefaultMachineBuilder, Error, Register, SupportMachine, Syscalls, + ISA_IMC, +}; use std::fs; use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::Arc; @@ -22,7 +25,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, 1, ArgsIterStatic::new(vec!["simple".into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -61,7 +64,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, 1, ArgsIterStatic::new(vec!["syscall".into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -97,7 +100,7 @@ pub fn test_asm_ebreak() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["ebreak".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["ebreak".into()])) .unwrap(); assert_eq!(value.load(Ordering::Relaxed), 1); let result = machine.run(); @@ -114,7 +117,7 @@ pub fn test_asm_simple_cycles() { .build(); let mut machine = AsmMachine::new(core); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["syscall".into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -133,7 +136,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, 1, ArgsIterStatic::new(vec!["syscall".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -147,7 +150,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, 1, ArgsIterStatic::new(vec!["simple".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -161,7 +164,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, 1, ArgsIterStatic::new(vec!["jump0_64".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -177,7 +180,11 @@ 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, + 1, + ArgsIterStatic::new(vec!["write_large_address64".into()]), + ) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -194,7 +201,11 @@ 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, + 1, + ArgsIterStatic::new(vec!["misaligned_jump64".into()]), + ) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -207,7 +218,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, 1, ArgsIterStatic::new(vec!["mulw64".into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -221,7 +232,11 @@ 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, + 1, + ArgsIterStatic::new(vec!["invalid_read64".into()]), + ) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -241,7 +256,11 @@ 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, + 1, + ArgsIterStatic::new(vec!["load_elf_crash_64".into()]), + ) .unwrap(); let result = machine.run(); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage(16))); @@ -254,7 +273,11 @@ 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, + 1, + ArgsIterStatic::new(vec!["wxorx_crash_64".into()]), + ) .unwrap(); let result = machine.run(); assert_eq!( @@ -273,7 +296,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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .unwrap(); let result = machine.run(); assert_eq!(result.unwrap(), 0); @@ -288,7 +311,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, 1, ArgsIterStatic::new(vec!["read_memory".into()])) .unwrap(); let result1 = machine1.run(); let exit1 = result1.unwrap(); @@ -299,7 +322,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, 1, ArgsIterStatic::new(vec!["read_memory".into()])) .unwrap(); let result2 = machine2.run(); let exit2 = result2.unwrap(); @@ -317,7 +340,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, 1, ArgsIterStatic::new(vec!["rvc_pageend".into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -358,7 +381,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, 1, ArgsIterStatic::new(vec!["syscall".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -377,7 +400,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, 1, ArgsIterStatic::new(vec!["simple64".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -396,7 +419,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, 1, ArgsIterStatic::new(vec!["simple64".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); @@ -413,7 +436,7 @@ 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, 1, ArgsIterStatic::new(vec!["simple64".into()])) .unwrap(); let result = || -> Result { @@ -436,7 +459,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, 1, ArgsIterStatic::new(vec!["mulw64".into()])) .unwrap(); let thread_join_handle = thread::spawn(move || { let result = machine.run(); @@ -452,7 +475,9 @@ fn test_zero_address() { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION1, u64::MAX); 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, 1, ArgsIterStatic::new(vec!["zero".into()])) + .unwrap(); let result = machine.run(); assert!(result.is_ok()); assert_eq!(result.unwrap(), 0); @@ -471,7 +496,9 @@ fn test_memoized_secp256k1() { "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", "foo", "bar"].into_iter().map(|a| a.into()).collect(); - machine.load_program(&buffer, &args).unwrap(); + machine + .load_program(&buffer, args.len(), ArgsIterStatic::new(args)) + .unwrap(); let mut decoder = MemoizedFixedTraceDecoder::new(build_decoder::(isa, version)); let result = machine.run_with_decoder(&mut decoder); assert_eq!(result.unwrap(), 0); @@ -490,7 +517,9 @@ fn test_memoized_dynamic_secp256k1() { "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3", "foo", "bar"].into_iter().map(|a| a.into()).collect(); - machine.load_program(&buffer, &args).unwrap(); + machine + .load_program(&buffer, args.len(), ArgsIterStatic::new(args)) + .unwrap(); let mut decoder = MemoizedDynamicTraceDecoder::new(build_decoder::(isa, version)); let result = machine.run_with_decoder(&mut decoder); assert_eq!(result.unwrap(), 0); @@ -502,7 +531,7 @@ pub fn test_big_binary() { let asm_core = AsmCoreMachine::new_with_memory(ISA_IMC, VERSION2, u64::MAX, 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, 1, ArgsIterStatic::new(vec!["simple".into()])); assert_eq!( result, Err(Error::MemOutOfBound(0x111000, OutOfBoundKind::Memory)) @@ -522,7 +551,9 @@ fn test_fast_memory_initialization_bug() { let memory = machine.machine.inner_mut().memory_ptr as *mut u8; memory.write(0x01); } - machine.load_program(&buffer, &[]).unwrap(); + machine + .load_program(&buffer, 0, ArgsIterStatic::new(vec![])) + .unwrap(); assert_eq!(machine.machine.memory_mut().load8(&0).unwrap(), 0); } @@ -532,6 +563,6 @@ pub fn test_memory_load_crash() { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); let core = DefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); - let result = machine.load_program(&buffer, &vec!["memory_crash".into()]); + let result = machine.load_program(&buffer, 1, ArgsIterStatic::new(vec!["memory_crash".into()])); assert_eq!(result.unwrap_err(), Error::MemWriteOnExecutablePage(1023)); } diff --git a/tests/test_auipc_fusion.rs b/tests/test_auipc_fusion.rs index 4a0b6396..bccabed2 100644 --- a/tests/test_auipc_fusion.rs +++ b/tests/test_auipc_fusion.rs @@ -4,7 +4,7 @@ use ckb_vm::instructions::{ }; #[cfg(has_asm)] use ckb_vm::machine::asm::{traces::SimpleFixedTraceDecoder, AsmCoreMachine, AsmMachine}; -use ckb_vm::machine::VERSION1; +use ckb_vm::machine::{ArgsIterStatic, VERSION1}; use ckb_vm::{ CoreMachine, DefaultCoreMachine, DefaultMachineBuilder, Error, Memory, SparseMemory, ISA_IMC, }; @@ -58,7 +58,11 @@ pub fn test_rust_auipc_fusion() { DefaultCoreMachine::>::new(ISA_IMC, VERSION1, u64::MAX); let mut machine = DefaultMachineBuilder::new(core_machine).build(); machine - .load_program(&buffer, &vec!["auipc_no_sign_extend".into()]) + .load_program( + &buffer, + 1, + ArgsIterStatic::new(vec!["auipc_no_sign_extend".into()]), + ) .unwrap(); let mut decoder = AuxDecoder::new(build_decoder::(machine.isa(), machine.version())); @@ -77,7 +81,11 @@ 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, + 1, + ArgsIterStatic::new(vec!["auipc_no_sign_extend".into()]), + ) .unwrap(); let decoder = AuxDecoder::new(build_decoder::( diff --git a/tests/test_dy_memory.rs b/tests/test_dy_memory.rs index 732f60ac..8c45fa50 100644 --- a/tests/test_dy_memory.rs +++ b/tests/test_dy_memory.rs @@ -3,7 +3,7 @@ use ckb_vm::{error::OutOfBoundKind, run_with_memory, FlatMemory, SparseMemory}; use ckb_vm::{ machine::{ asm::{AsmCoreMachine, AsmMachine}, - DefaultMachineBuilder, VERSION0, VERSION2, + ArgsIterStatic, DefaultMachineBuilder, VERSION0, VERSION2, }, ISA_B, ISA_IMC, ISA_MOP, }; @@ -33,7 +33,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, 1, ArgsIterStatic::new(vec![bin_name.into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -87,7 +87,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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); diff --git a/tests/test_misc.rs b/tests/test_misc.rs index bfc855ab..87fc8dd3 100644 --- a/tests/test_misc.rs +++ b/tests/test_misc.rs @@ -1,6 +1,6 @@ use ckb_vm::cost_model::constant_cycles; use ckb_vm::error::OutOfBoundKind; -use ckb_vm::machine::{VERSION0, VERSION1, VERSION2}; +use ckb_vm::machine::{ArgsIterStatic, VERSION0, VERSION1, VERSION2}; use ckb_vm::registers::{A0, A1, A2, A3, A4, A5, A7}; use ckb_vm::{ run, CoreMachine, Debugger, DefaultCoreMachine, DefaultMachineBuilder, Error, FlatMemory, @@ -63,7 +63,7 @@ pub fn test_custom_syscall() { .syscall(Box::new(CustomSyscall {})) .build(); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["syscall".into()])) .unwrap(); let result = machine.run(); assert!(result.is_ok()); @@ -98,7 +98,7 @@ pub fn test_ebreak() { })) .build(); machine - .load_program(&buffer, &vec!["ebreak".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["ebreak".into()])) .unwrap(); assert_eq!(value.load(Ordering::Relaxed), 1); let result = machine.run(); @@ -203,7 +203,11 @@ pub fn test_flat_crash_64() { let buffer = fs::read("tests/programs/flat_crash_64").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); 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, + 1, + ArgsIterStatic::new(vec!["flat_crash_64".into()]), + ); assert_eq!( result.err(), Some(Error::MemOutOfBound(0x1100000000, OutOfBoundKind::Memory)) @@ -369,7 +373,7 @@ pub fn test_rvc_pageend() { DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); let mut machine = DefaultMachineBuilder::new(core_machine).build(); machine - .load_program(&buffer, &vec!["rvc_end".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["rvc_end".into()])) .unwrap(); let anchor_pc: u64 = 69630; @@ -423,7 +427,7 @@ pub fn test_outofcycles_in_syscall() { .syscall(Box::new(OutOfCyclesSyscall {})) .build(); machine - .load_program(&buffer, &vec!["syscall".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["syscall".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); diff --git a/tests/test_reset.rs b/tests/test_reset.rs index 442d6e70..27719623 100644 --- a/tests/test_reset.rs +++ b/tests/test_reset.rs @@ -2,7 +2,7 @@ use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; #[cfg(has_asm)] use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; -use ckb_vm::machine::{DefaultCoreMachine, DefaultMachineBuilder, VERSION1}; +use ckb_vm::machine::{ArgsIterStatic, DefaultCoreMachine, DefaultMachineBuilder, VERSION1}; use ckb_vm::{ registers::A7, Error, Register, SparseMemory, SupportMachine, Syscalls, TraceMachine, WXorXMemory, DEFAULT_MEMORY_SIZE, ISA_IMC, ISA_MOP, @@ -30,7 +30,8 @@ impl Syscalls for CustomSyscall { let code = Bytes::from(code_data); machine.load_elf(&code, true).unwrap(); machine.initialize_stack( - &[], + 0, + ArgsIterStatic::new(vec![]), (DEFAULT_MEMORY_SIZE - DEFAULT_MEMORY_SIZE / 4) as u64, (DEFAULT_MEMORY_SIZE / 4) as u64, )?; @@ -52,7 +53,9 @@ 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, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); let cycles = machine.cycles(); assert!(result.is_ok()); @@ -76,7 +79,9 @@ fn test_reset_int_with_trace() { .syscall(Box::new(CustomSyscall {})) .build(), ); - machine.load_program(&code, &vec![]).unwrap(); + machine + .load_program(&code, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); let cycles = machine.machine.cycles(); assert!(result.is_ok()); @@ -96,7 +101,9 @@ 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, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); let cycles = machine.machine.cycles(); diff --git a/tests/test_resume.rs b/tests/test_resume.rs index b42c95dd..330453ed 100644 --- a/tests/test_resume.rs +++ b/tests/test_resume.rs @@ -9,7 +9,7 @@ use ckb_vm::machine::{ }; use ckb_vm::memory::{sparse::SparseMemory, wxorx::WXorXMemory}; use ckb_vm::snapshot::{make_snapshot, resume, Snapshot}; -use ckb_vm::{DefaultMachineBuilder, Error, ISA_A, ISA_IMC}; +use ckb_vm::{ArgsIterStatic, DefaultMachineBuilder, Error, ISA_A, ISA_IMC}; use std::fs::File; use std::io::Read; @@ -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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .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, 1, ArgsIterStatic::new(vec!["alloc_many".into()])) .unwrap(); let result1 = machine1.run(); let cycles1 = machine1.cycles(); @@ -251,12 +251,17 @@ enum Machine { } impl Machine { - fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result { + fn load_program( + &mut self, + program: &Bytes, + argc: usize, + args: impl Iterator>, + ) -> Result { use Machine::*; match self { - Asm(inner) => inner.load_program(program, args), - Interpreter(inner) => inner.load_program(program, args), - InterpreterWithTrace(inner) => inner.load_program(program, args), + Asm(inner) => inner.load_program(program, argc, args), + Interpreter(inner) => inner.load_program(program, argc, args), + InterpreterWithTrace(inner) => inner.load_program(program, argc, args), } } diff --git a/tests/test_resume2.rs b/tests/test_resume2.rs index d1078cb9..7d693d47 100644 --- a/tests/test_resume2.rs +++ b/tests/test_resume2.rs @@ -6,7 +6,8 @@ use ckb_vm::elf::parse_elf; use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; use ckb_vm::machine::trace::TraceMachine; use ckb_vm::machine::{ - CoreMachine, DefaultCoreMachine, DefaultMachine, SupportMachine, VERSION0, VERSION1, VERSION2, + ArgsIterStatic, CoreMachine, DefaultCoreMachine, DefaultMachine, SupportMachine, VERSION0, + VERSION1, VERSION2, }; use ckb_vm::memory::{sparse::SparseMemory, wxorx::WXorXMemory}; use ckb_vm::registers::{A0, A1, A7}; @@ -65,13 +66,14 @@ 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![ + .load_program( + 5, ArgsIterStatic::new(vec![ "secp256k1_bench".into(), "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f".into(), "304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3".into(), "foo".into(), "bar".into(), - ]) + ])) .unwrap(); let result1 = machine1.run(); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -117,7 +119,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(1, ArgsIterStatic::new(vec!["resume2_load_data".into()])) .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); @@ -151,7 +153,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(1, ArgsIterStatic::new(vec!["resume2_load_data".into()])) .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); @@ -181,7 +183,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(1, ArgsIterStatic::new(vec!["alloc_many".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -201,7 +205,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(1, ArgsIterStatic::new(vec!["alloc_many".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -229,7 +235,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(1, ArgsIterStatic::new(vec!["alloc_many".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -250,7 +258,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(1, ArgsIterStatic::new(vec!["alloc_many".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -270,7 +280,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(1, ArgsIterStatic::new(vec!["alloc_many".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -290,7 +302,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(1, ArgsIterStatic::new(vec!["alloc_many".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -444,7 +458,11 @@ enum Machine { } impl Machine { - fn load_program(&mut self, args: &[Bytes]) -> Result { + fn load_program( + &mut self, + argc: usize, + args: impl Iterator>, + ) -> Result { use Machine::*; match self { Asm(inner, context) => { @@ -454,7 +472,7 @@ impl Machine { .load_data(&PROGRAM_ID, 0, 0) .unwrap(); let metadata = parse_elf::(&program, inner.machine.version())?; - let bytes = inner.load_program_with_metadata(&program, &metadata, args)?; + let bytes = inner.load_program_with_metadata(&program, &metadata, argc, args)?; context.lock().unwrap().mark_program( inner.machine.inner_mut(), &metadata, @@ -470,7 +488,7 @@ impl Machine { .load_data(&PROGRAM_ID, 0, 0) .unwrap(); let metadata = parse_elf::(&program, inner.version())?; - let bytes = inner.load_program_with_metadata(&program, &metadata, args)?; + let bytes = inner.load_program_with_metadata(&program, &metadata, argc, args)?; context.lock().unwrap().mark_program( inner.inner_mut(), &metadata, @@ -486,7 +504,7 @@ impl Machine { .load_data(&PROGRAM_ID, 0, 0) .unwrap(); let metadata = parse_elf::(&program, inner.machine.version())?; - let bytes = inner.load_program_with_metadata(&program, &metadata, args)?; + let bytes = inner.load_program_with_metadata(&program, &metadata, argc, args)?; context.lock().unwrap().mark_program( inner.machine.inner_mut(), &metadata, @@ -609,7 +627,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(1, ArgsIterStatic::new(vec!["main".into()])) + .unwrap(); let result1 = machine1.run(); assert!(result1.is_err()); assert_eq!(result1.unwrap_err(), Error::CyclesExceeded); @@ -630,7 +650,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(1, ArgsIterStatic::new(vec!["main".into()])) + .unwrap(); match machine { Machine::Asm(ref mut inner, ref ctx) => { @@ -663,7 +685,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(1, ArgsIterStatic::new(vec!["main".into()])) + .unwrap(); match machine { Machine::Asm(ref mut inner, ref ctx) => { diff --git a/tests/test_simple.rs b/tests/test_simple.rs index f11daf57..9016503b 100644 --- a/tests/test_simple.rs +++ b/tests/test_simple.rs @@ -1,7 +1,7 @@ use ckb_vm::machine::VERSION0; use ckb_vm::{ - run, DefaultCoreMachine, DefaultMachineBuilder, Error, FlatMemory, Instruction, SparseMemory, - SupportMachine, ISA_IMC, + run, ArgsIterStatic, DefaultCoreMachine, DefaultMachineBuilder, Error, FlatMemory, Instruction, + SparseMemory, SupportMachine, ISA_IMC, }; use std::fs; @@ -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, 1, ArgsIterStatic::new(vec!["simple".into()])) .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, 1, ArgsIterStatic::new(vec!["simple".into()])) .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); let mut machine = DefaultMachineBuilder::new(core_machine).build(); let bytes = machine - .load_program(&buffer, &vec!["simple".into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["simple".into()])) .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, 1, ArgsIterStatic::new(vec!["simple".into()])) .unwrap(); let result = machine.run(); assert!(result.is_err()); diff --git a/tests/test_spawn.rs b/tests/test_spawn.rs index 4909275f..466520ec 100644 --- a/tests/test_spawn.rs +++ b/tests/test_spawn.rs @@ -5,32 +5,13 @@ use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; use ckb_vm::machine::{trace::TraceMachine, DefaultCoreMachine, VERSION2}; use ckb_vm::registers::{A0, A1, A2, A7}; use ckb_vm::{ - DefaultMachineBuilder, Error, Memory, Register, SparseMemory, SupportMachine, Syscalls, - WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, + ArgsIterStatic, ArgsIterStream, DefaultMachineBuilder, Error, Memory, Register, SparseMemory, + SupportMachine, Syscalls, WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, }; use std::sync::{Arc, Mutex}; // There is a spawn system call in ckb, we must ensure that in the worst case, ckb will not crashed by stack overflow. -pub fn load_c_string(machine: &mut Mac, addr: u64) -> Result { - let mut buffer = Vec::new(); - let mut addr = addr; - - loop { - let byte = machine - .memory_mut() - .load8(&Mac::REG::from_u64(addr))? - .to_u8(); - if byte == 0 { - break; - } - buffer.push(byte); - addr += 1; - } - - Ok(Bytes::from(buffer)) -} - fn stack_depth() -> u64 { let x = 0; unsafe { @@ -62,22 +43,12 @@ impl Syscalls for IntSpawnSyscall { } } - let addr = &machine.registers()[A0]; - let path_byte = load_c_string(machine, addr.to_u64()).unwrap(); + let addr = machine.registers()[A0].clone(); + let path_byte = machine.memory_mut().load_c_string(&addr).unwrap(); let path = std::str::from_utf8(&path_byte).unwrap(); - let argc = &machine.registers()[A1]; - let argv = &machine.registers()[A2]; - let mut addr = argv.to_u64(); - let mut argv_vec = Vec::new(); - for _ in 0..argc.to_u64() { - let target_addr = machine - .memory_mut() - .load64(&Mac::REG::from_u64(addr))? - .to_u64(); - let cstr = load_c_string(machine, target_addr)?; - argv_vec.push(cstr); - addr += 8; - } + let argc = machine.registers()[A1].clone(); + let argv = machine.registers()[A2].clone(); + let args_iter = ArgsIterStream::new(machine.memory_mut(), argc.clone(), argv); let buffer: Bytes = std::fs::read(path).unwrap().into(); let machine_core = DefaultCoreMachine::>>::new( ISA_IMC | ISA_B | ISA_MOP, @@ -92,7 +63,9 @@ impl Syscalls for IntSpawnSyscall { })) .build(), ); - machine_child.load_program(&buffer, &argv_vec).unwrap(); + machine_child + .load_program(&buffer, argc.to_u64() as usize, args_iter) + .unwrap(); let exit = machine_child.run().unwrap(); machine.set_register(A0, Mac::REG::from_i8(exit)); Ok(true) @@ -124,22 +97,12 @@ impl Syscalls for AsmSpawnSyscall { } } - let addr = &machine.registers()[A0]; - let path_byte = load_c_string(machine, addr.to_u64()).unwrap(); + let addr = machine.registers()[A0].clone(); + let path_byte = machine.memory_mut().load_c_string(&addr).unwrap(); let path = std::str::from_utf8(&path_byte).unwrap(); - let argc = &machine.registers()[A1]; - let argv = &machine.registers()[A2]; - let mut addr = argv.to_u64(); - let mut argv_vec = Vec::new(); - for _ in 0..argc.to_u64() { - let target_addr = machine - .memory_mut() - .load64(&Mac::REG::from_u64(addr))? - .to_u64(); - let cstr = load_c_string(machine, target_addr)?; - argv_vec.push(cstr); - addr += 8; - } + let argc = machine.registers()[A1].clone(); + let argv = machine.registers()[A2].clone(); + let args_iter = ArgsIterStream::new(machine.memory_mut(), argc.clone(), argv); let buffer: Bytes = std::fs::read(path).unwrap().into(); let machine_core_asm = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, u64::MAX); let machine_core = DefaultMachineBuilder::>::new(machine_core_asm) @@ -149,7 +112,9 @@ impl Syscalls for AsmSpawnSyscall { })) .build(); let mut machine_child = AsmMachine::new(machine_core); - machine_child.load_program(&buffer, &argv_vec).unwrap(); + machine_child + .load_program(&buffer, argc.to_u64() as usize, args_iter) + .unwrap(); let exit = machine_child.run().unwrap(); machine.set_register(A0, Mac::REG::from_i8(exit)); Ok(true) @@ -174,7 +139,9 @@ pub fn test_spawn_int() { })) .build(), ); - machine.load_program(&buffer, &["main".into()]).unwrap(); + machine + .load_program(&buffer, 1, ArgsIterStatic::new(vec!["main".into()])) + .unwrap(); let result = machine.run(); assert!(result.is_ok()); assert!(result.unwrap() == 0); @@ -197,7 +164,9 @@ pub fn test_spawn_asm() { })) .build(); let mut machine = AsmMachine::new(machine_core); - machine.load_program(&buffer, &["main".into()]).unwrap(); + machine + .load_program(&buffer, 0, ArgsIterStatic::new(vec!["main".into()])) + .unwrap(); let result = machine.run(); assert!(result.is_ok()); assert!(result.unwrap() == 0); diff --git a/tests/test_versions.rs b/tests/test_versions.rs index cdc8b040..0aa6ec7d 100644 --- a/tests/test_versions.rs +++ b/tests/test_versions.rs @@ -5,8 +5,8 @@ use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; use ckb_vm::machine::{VERSION0, VERSION1, VERSION2}; use ckb_vm::memory::{FLAG_DIRTY, FLAG_FREEZED}; use ckb_vm::{ - CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineBuilder, Error, Memory, - SparseMemory, TraceMachine, WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, RISCV_PAGESIZE, + ArgsIterStatic, CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineBuilder, Error, + Memory, SparseMemory, TraceMachine, WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, RISCV_PAGESIZE, }; use std::fs; @@ -22,7 +22,7 @@ fn create_rust_machine( let mut machine = DefaultMachineBuilder::>::new(core_machine).build(); machine - .load_program(&buffer, &vec![program.into()]) + .load_program(&buffer, 1, ArgsIterStatic::new(vec![program.into()])) .unwrap(); machine } @@ -34,7 +34,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, 1, ArgsIterStatic::new(vec![program.into()])) .unwrap(); machine } @@ -246,7 +246,7 @@ pub fn test_rust_version0_unaligned64() { let core_machine = DefaultCoreMachine::::new(ISA_IMC, VERSION0, u64::MAX); let mut machine = DefaultMachineBuilder::>::new(core_machine).build(); - let result = machine.load_program(&buffer, &vec![program.into()]); + let result = machine.load_program(&buffer, 1, ArgsIterStatic::new(vec![program.into()])); assert!(result.is_err()); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage(16))); } @@ -268,7 +268,7 @@ pub fn test_asm_version0_unaligned64() { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); 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, 1, ArgsIterStatic::new(vec![program.into()])); assert!(result.is_err()); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage(16))); } @@ -351,7 +351,9 @@ pub fn test_asm_version1_asm_trace_bug() { .build(); AsmMachine::new(machine) }; - machine.load_program(&buffer, &[]).unwrap(); + machine + .load_program(&buffer, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); assert_eq!(result, Err(Error::CyclesExceeded)); @@ -368,7 +370,9 @@ pub fn test_asm_version2_asm_trace_bug() { .build(); AsmMachine::new(machine) }; - machine.load_program(&buffer, &[]).unwrap(); + machine + .load_program(&buffer, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); assert_eq!( @@ -393,7 +397,9 @@ pub fn test_trace_version1_asm_trace_bug() { .build(), ) }; - machine.load_program(&buffer, &[]).unwrap(); + machine + .load_program(&buffer, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); assert_eq!(result, Err(Error::CyclesExceeded)); @@ -415,7 +421,9 @@ pub fn test_trace_version2_asm_trace_bug() { .build(), ) }; - machine.load_program(&buffer, &[]).unwrap(); + machine + .load_program(&buffer, 0, ArgsIterStatic::new(vec![])) + .unwrap(); let result = machine.run(); assert_eq!(