@@ -10,8 +10,9 @@ use crate::{
1010 gc:: { self , CloneUnrooted , CopyUnrooted , GcPtr , Trace } ,
1111 types:: VmIndex ,
1212 value:: { ClosureData , DataStruct , ExternFunction , Value , ValueRepr } ,
13- Variants ,
13+ Error , Result , Variants ,
1414} ;
15+ use gc:: Borrow ;
1516
1617pub trait StackPrimitive {
1718 fn push_to ( & self , stack : & mut Stack ) ;
@@ -199,6 +200,7 @@ pub trait StackState: CopyUnrooted + Sized {
199200 fn from_state ( state : & State ) -> & Self ;
200201 fn from_state_mut ( state : & mut State ) -> & mut Self ;
201202 fn to_state ( & self ) -> gc:: Borrow < State > ;
203+ fn max_stack_size ( & self ) -> VmIndex ;
202204}
203205
204206impl StackState for State {
@@ -211,6 +213,14 @@ impl StackState for State {
211213 fn to_state ( & self ) -> gc:: Borrow < State > {
212214 gc:: Borrow :: new ( self )
213215 }
216+
217+ fn max_stack_size ( & self ) -> VmIndex {
218+ match self {
219+ State :: Unknown => 0 ,
220+ State :: Closure ( closure) => closure. max_stack_size ( ) ,
221+ State :: Extern ( ext) => ext. max_stack_size ( ) ,
222+ }
223+ }
214224}
215225
216226impl StackState for ClosureState {
@@ -229,6 +239,9 @@ impl StackState for ClosureState {
229239 fn to_state ( & self ) -> gc:: Borrow < State > {
230240 construct_gc ! ( State :: Closure ( @ gc:: Borrow :: new( self ) ) )
231241 }
242+ fn max_stack_size ( & self ) -> VmIndex {
243+ self . closure . function . max_stack_size
244+ }
232245}
233246
234247impl StackState for ExternState {
@@ -247,6 +260,9 @@ impl StackState for ExternState {
247260 fn to_state ( & self ) -> gc:: Borrow < State > {
248261 construct_gc ! ( State :: Extern ( @ gc:: Borrow :: new( self ) ) )
249262 }
263+ fn max_stack_size ( & self ) -> VmIndex {
264+ 0
265+ }
250266}
251267
252268#[ derive( Debug , PartialEq ) ]
@@ -408,6 +424,7 @@ pub struct Stack {
408424 values : Vec < Value > ,
409425 #[ cfg_attr( feature = "serde_derive" , serde( state) ) ]
410426 frames : Vec < Frame < State > > ,
427+ max_stack_size : VmIndex ,
411428}
412429
413430unsafe impl Trace for Stack {
@@ -419,9 +436,14 @@ impl Stack {
419436 Stack {
420437 values : Vec :: new ( ) ,
421438 frames : Vec :: new ( ) ,
439+ max_stack_size : VmIndex :: MAX ,
422440 }
423441 }
424442
443+ pub fn set_max_stack_size ( & mut self , max_stack_size : VmIndex ) {
444+ self . max_stack_size = max_stack_size;
445+ }
446+
425447 fn assert_pop ( & self , count : VmIndex ) {
426448 let frame = self . frames . last ( ) . unwrap ( ) ;
427449 let args = if let State :: Extern ( ExternState {
@@ -656,9 +678,9 @@ impl<'a: 'b, 'b> StackFrame<'b, State> {
656678 }
657679 }
658680
659- pub fn new_frame ( stack : & ' b mut Stack , args : VmIndex , state : State ) -> StackFrame < ' b > {
660- let frame = unsafe { Self :: add_new_frame ( stack, args, & state, false ) . unrooted ( ) } ;
661- StackFrame { stack, frame }
681+ pub fn new_frame ( stack : & ' b mut Stack , args : VmIndex , state : State ) -> Result < StackFrame < ' b > > {
682+ let frame = unsafe { Self :: add_new_frame ( stack, args, & state, false ) ? . unrooted ( ) } ;
683+ Ok ( StackFrame { stack, frame } )
662684 }
663685}
664686
@@ -825,7 +847,7 @@ where
825847 }
826848 }
827849
828- pub ( crate ) fn enter_scope < T > ( self , args : VmIndex , state : & T ) -> StackFrame < ' b , T >
850+ pub ( crate ) fn enter_scope < T > ( self , args : VmIndex , state : & T ) -> Result < StackFrame < ' b , T > >
829851 where
830852 T : StackState ,
831853 {
@@ -837,16 +859,16 @@ where
837859 args : VmIndex ,
838860 state : & T ,
839861 excess : bool ,
840- ) -> StackFrame < ' b , T >
862+ ) -> Result < StackFrame < ' b , T > >
841863 where
842864 T : StackState ,
843865 {
844866 let stack = self . stack ;
845- let frame = unsafe { Self :: add_new_frame ( stack, args, state, excess) . unrooted ( ) } ;
846- StackFrame { stack, frame }
867+ let frame = unsafe { Self :: add_new_frame ( stack, args, state, excess) ? . unrooted ( ) } ;
868+ Ok ( StackFrame { stack, frame } )
847869 }
848870
849- pub ( crate ) fn exit_scope ( self ) -> Result < StackFrame < ' b , State > , & ' b mut Stack >
871+ pub ( crate ) fn exit_scope ( self ) -> std :: result :: Result < StackFrame < ' b , State > , & ' b mut Stack >
850872 where
851873 S : StackState ,
852874 {
@@ -886,7 +908,7 @@ where
886908 args : VmIndex ,
887909 state : & ' gc T ,
888910 excess : bool ,
889- ) -> gc :: Borrow < ' gc , Frame < T > >
911+ ) -> Result < Borrow < ' gc , Frame < T > > >
890912 where
891913 T : StackState ,
892914 {
@@ -911,13 +933,18 @@ where
911933 ) ;
912934 }
913935 }
936+ // Before entering a function check that the stack cannot exceed `max_stack_size`
937+ if stack. len ( ) + frame. state . max_stack_size ( ) > stack. max_stack_size {
938+ return Err ( Error :: StackOverflow ( stack. max_stack_size ) ) ;
939+ }
940+
914941 // SAFETY The frame's gc pointers are scanned the `Stack::trace` since they are on
915942 // the stack
916943 unsafe {
917944 stack. frames . push ( frame. to_state ( ) . clone_unrooted ( ) ) ;
918945 }
919946 debug ! ( "----> Store {} {:?}" , stack. frames. len( ) , frame. to_state( ) ) ;
920- frame
947+ Ok ( frame)
921948 }
922949}
923950
@@ -1158,15 +1185,15 @@ mod tests {
11581185 let _ = :: env_logger:: try_init ( ) ;
11591186
11601187 let mut stack = Stack :: new ( ) ;
1161- let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) ;
1188+ let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) . unwrap ( ) ;
11621189 frame. push ( Int ( 0 ) ) ;
11631190 frame. push ( Int ( 1 ) ) ;
11641191
1165- frame = frame. enter_scope ( 2 , & State :: Unknown ) ;
1192+ frame = frame. enter_scope ( 2 , & State :: Unknown ) . unwrap ( ) ;
11661193 frame. push ( Int ( 2 ) ) ;
11671194 frame. push ( Int ( 3 ) ) ;
11681195
1169- frame = frame. enter_scope ( 1 , & State :: Unknown ) ;
1196+ frame = frame. enter_scope ( 1 , & State :: Unknown ) . unwrap ( ) ;
11701197 frame. push ( Int ( 4 ) ) ;
11711198 frame. push ( Int ( 5 ) ) ;
11721199 frame. push ( Int ( 6 ) ) ;
@@ -1193,14 +1220,14 @@ mod tests {
11931220
11941221 let mut stack = Stack :: new ( ) ;
11951222 {
1196- let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) ;
1223+ let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) . unwrap ( ) ;
11971224 frame. push ( Int ( 0 ) ) ;
11981225 frame. push ( Int ( 1 ) ) ;
1199- let frame = frame. enter_scope ( 2 , & * ExternState :: new ( & ext) ) ;
1226+ let frame = frame. enter_scope ( 2 , & * ExternState :: new ( & ext) ) . unwrap ( ) ;
12001227 let _lock = frame. into_lock ( ) ;
12011228 }
12021229 // Panic as it attempts to access past the lock
1203- StackFrame :: new_frame ( & mut stack, 1 , State :: Unknown ) ;
1230+ StackFrame :: new_frame ( & mut stack, 1 , State :: Unknown ) . unwrap ( ) ;
12041231
12051232 unsafe { gc. clear ( ) }
12061233 }
@@ -1215,9 +1242,9 @@ mod tests {
12151242
12161243 let mut stack = Stack :: new ( ) ;
12171244 {
1218- let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) ;
1245+ let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) . unwrap ( ) ;
12191246 frame. push ( Int ( 0 ) ) ;
1220- let frame = frame. enter_scope ( 1 , & * ExternState :: new ( & ext) ) ;
1247+ let frame = frame. enter_scope ( 1 , & * ExternState :: new ( & ext) ) . unwrap ( ) ;
12211248 let _lock = frame. into_lock ( ) ;
12221249 }
12231250 // Panic as it attempts to pop a locked value
@@ -1235,14 +1262,14 @@ mod tests {
12351262
12361263 let mut stack = Stack :: new ( ) ;
12371264 let lock = {
1238- let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) ;
1265+ let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) . unwrap ( ) ;
12391266 frame. push ( Int ( 0 ) ) ;
12401267 frame. push ( Int ( 1 ) ) ;
1241- let frame = frame. enter_scope ( 2 , & * ExternState :: new ( & ext) ) ;
1268+ let frame = frame. enter_scope ( 2 , & * ExternState :: new ( & ext) ) . unwrap ( ) ;
12421269 frame. into_lock ( )
12431270 } ;
12441271 {
1245- let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) ;
1272+ let mut frame = StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) . unwrap ( ) ;
12461273 frame. push ( Int ( 2 ) ) ;
12471274 frame = frame. exit_scope ( ) . unwrap ( ) ;
12481275 frame. exit_scope ( ) . unwrap_err ( ) ;
@@ -1259,12 +1286,12 @@ mod tests {
12591286 let _ = :: env_logger:: try_init ( ) ;
12601287
12611288 let mut stack = Stack :: new ( ) ;
1262- StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) ;
1289+ StackFrame :: new_frame ( & mut stack, 0 , State :: Unknown ) . unwrap ( ) ;
12631290 let mut stack = StackFrame :: < State > :: current ( & mut stack) ;
12641291 stack. push ( Int ( 0 ) ) ;
12651292 stack. insert_slice ( 0 , & [ Int ( 2 ) . into ( ) , Int ( 1 ) . into ( ) ] ) ;
12661293 assert_eq ! ( & stack[ ..] , [ Int ( 2 ) . into( ) , Int ( 1 ) . into( ) , Int ( 0 ) . into( ) ] ) ;
1267- stack = stack. enter_scope ( 2 , & State :: Unknown ) ;
1294+ stack = stack. enter_scope ( 2 , & State :: Unknown ) . unwrap ( ) ;
12681295 stack. insert_slice ( 1 , & [ Int ( 10 ) . into ( ) ] ) ;
12691296 assert_eq ! ( & stack[ ..] , [ Int ( 1 ) . into( ) , Int ( 10 ) . into( ) , Int ( 0 ) . into( ) ] ) ;
12701297 stack. insert_slice ( 1 , & [ ] ) ;
0 commit comments