@@ -12,7 +12,7 @@ use super::debugger::Debugger;
1212use super :: decoder:: { build_decoder, Decoder } ;
1313use super :: elf:: { parse_elf, LoadingAction , ProgramMetadata } ;
1414use super :: instructions:: { execute, Instruction , Register } ;
15- use super :: memory:: Memory ;
15+ use super :: memory:: { load_c_string_byte_by_byte , Memory } ;
1616use super :: syscalls:: Syscalls ;
1717use super :: {
1818 registers:: { A0 , A7 , REGISTER_ABI_NAMES , SP } ,
@@ -171,7 +171,7 @@ pub trait SupportMachine: CoreMachine {
171171
172172 fn initialize_stack (
173173 & mut self ,
174- args : & [ Bytes ] ,
174+ args : impl ExactSizeIterator < Item = Result < Bytes , Error > > ,
175175 stack_start : u64 ,
176176 stack_size : u64 ,
177177 ) -> Result < u64 , Error > {
@@ -183,7 +183,7 @@ pub trait SupportMachine: CoreMachine {
183183 // reading "argc" will return an unexpected data. This situation is not very common.
184184 //
185185 // See https://github.com/nervosnetwork/ckb-vm/issues/106 for more details.
186- if self . version ( ) >= VERSION1 && args. is_empty ( ) {
186+ if self . version ( ) >= VERSION1 && args. len ( ) == 0 {
187187 let argc_size = u64:: from ( Self :: REG :: BITS / 8 ) ;
188188 let origin_sp = stack_start + stack_size;
189189 let unaligned_sp_address = origin_sp - argc_size;
@@ -200,15 +200,21 @@ pub trait SupportMachine: CoreMachine {
200200 // of each argv object.
201201 let mut values = vec ! [ Self :: REG :: from_u64( args. len( ) as u64 ) ] ;
202202 for arg in args {
203+ let arg = arg?;
203204 let len = Self :: REG :: from_u64 ( arg. len ( ) as u64 + 1 ) ;
204205 let address = self . registers ( ) [ SP ] . overflowing_sub ( & len) ;
205206
206- self . memory_mut ( ) . store_bytes ( address. to_u64 ( ) , arg) ?;
207+ self . memory_mut ( ) . store_bytes ( address. to_u64 ( ) , & arg) ?;
207208 self . memory_mut ( )
208209 . store_byte ( address. to_u64 ( ) + arg. len ( ) as u64 , 1 , 0 ) ?;
209210
210211 values. push ( address. clone ( ) ) ;
211- self . set_register ( SP , address) ;
212+ self . set_register ( SP , address. clone ( ) ) ;
213+
214+ if self . version ( ) >= VERSION2 && address. to_u64 ( ) < stack_start {
215+ // Provides an early exit to large argv array.
216+ return Err ( Error :: MemOutOfStack ) ;
217+ }
212218 }
213219 if self . version ( ) >= VERSION1 {
214220 // There are 2 standard requirements of the initialized stack:
@@ -246,7 +252,7 @@ pub trait SupportMachine: CoreMachine {
246252 self . set_register ( SP , address) ;
247253 }
248254 if self . registers ( ) [ SP ] . to_u64 ( ) < stack_start {
249- // args exceed stack size
255+ // Args exceed stack size.
250256 return Err ( Error :: MemOutOfStack ) ;
251257 }
252258 Ok ( stack_start + stack_size - self . registers ( ) [ SP ] . to_u64 ( ) )
@@ -572,7 +578,11 @@ impl<Inner: CoreMachine> Display for DefaultMachine<Inner> {
572578}
573579
574580impl < Inner : SupportMachine > DefaultMachine < Inner > {
575- pub fn load_program ( & mut self , program : & Bytes , args : & [ Bytes ] ) -> Result < u64 , Error > {
581+ pub fn load_program (
582+ & mut self ,
583+ program : & Bytes ,
584+ args : impl ExactSizeIterator < Item = Result < Bytes , Error > > ,
585+ ) -> Result < u64 , Error > {
576586 let elf_bytes = self . load_elf ( program, true ) ?;
577587 let stack_bytes = self . initialize ( args) ?;
578588 let bytes = elf_bytes. checked_add ( stack_bytes) . ok_or_else ( || {
@@ -587,7 +597,7 @@ impl<Inner: SupportMachine> DefaultMachine<Inner> {
587597 & mut self ,
588598 program : & Bytes ,
589599 metadata : & ProgramMetadata ,
590- args : & [ Bytes ] ,
600+ args : impl ExactSizeIterator < Item = Result < Bytes , Error > > ,
591601 ) -> Result < u64 , Error > {
592602 let elf_bytes = self . load_binary ( program, metadata, true ) ?;
593603 let stack_bytes = self . initialize ( args) ?;
@@ -599,7 +609,10 @@ impl<Inner: SupportMachine> DefaultMachine<Inner> {
599609 Ok ( bytes)
600610 }
601611
602- fn initialize ( & mut self , args : & [ Bytes ] ) -> Result < u64 , Error > {
612+ fn initialize (
613+ & mut self ,
614+ args : impl ExactSizeIterator < Item = Result < Bytes , Error > > ,
615+ ) -> Result < u64 , Error > {
603616 for syscall in & mut self . syscalls {
604617 syscall. initialize ( & mut self . inner ) ?;
605618 }
@@ -759,6 +772,55 @@ impl Pause {
759772 }
760773}
761774
775+ pub struct FlattenedArgsReader < ' a , M : Memory > {
776+ memory : & ' a mut M ,
777+ argc : M :: REG ,
778+ argv : M :: REG ,
779+ cidx : M :: REG ,
780+ }
781+ impl < ' a , M : Memory > FlattenedArgsReader < ' a , M > {
782+ pub fn new ( memory : & ' a mut M , argc : M :: REG , argv : M :: REG ) -> Self {
783+ Self {
784+ memory,
785+ argc,
786+ argv,
787+ cidx : M :: REG :: zero ( ) ,
788+ }
789+ }
790+ }
791+ impl < ' a , M : Memory > Iterator for FlattenedArgsReader < ' a , M > {
792+ type Item = Result < Bytes , Error > ;
793+ fn next ( & mut self ) -> Option < Self :: Item > {
794+ if self . cidx . ge ( & self . argc ) . to_u8 ( ) == 1 {
795+ return None ;
796+ }
797+ let addr = match M :: REG :: BITS {
798+ 32 => self . memory . load32 ( & self . argv ) ,
799+ 64 => self . memory . load64 ( & self . argv ) ,
800+ _ => unreachable ! ( ) ,
801+ } ;
802+ if let Err ( err) = addr {
803+ return Some ( Err ( err) ) ;
804+ } ;
805+ let addr = addr. unwrap ( ) ;
806+ let cstr = load_c_string_byte_by_byte ( self . memory , & addr) ;
807+ if let Err ( err) = cstr {
808+ return Some ( Err ( err) ) ;
809+ } ;
810+ let cstr = cstr. unwrap ( ) ;
811+ self . cidx = self . cidx . overflowing_add ( & M :: REG :: from_u8 ( 1 ) ) ;
812+ self . argv = self
813+ . argv
814+ . overflowing_add ( & M :: REG :: from_u8 ( M :: REG :: BITS / 8 ) ) ;
815+ Some ( Ok ( cstr) )
816+ }
817+ }
818+ impl < ' a , M : Memory > ExactSizeIterator for FlattenedArgsReader < ' a , M > {
819+ fn len ( & self ) -> usize {
820+ self . argc . to_u64 ( ) as usize
821+ }
822+ }
823+
762824#[ cfg( test) ]
763825mod tests {
764826 use std:: sync:: atomic:: AtomicU8 ;
0 commit comments