@@ -42,6 +42,9 @@ pub struct EvalContext<'a, 'tcx: 'a> {
42
42
43
43
/// The virtual call stack.
44
44
stack : Vec < Frame < ' a , ' tcx > > ,
45
+
46
+ /// The maximum number of stack frames allowed
47
+ stack_limit : usize ,
45
48
}
46
49
47
50
/// A stack frame.
@@ -133,24 +136,25 @@ enum ConstantKind {
133
136
}
134
137
135
138
impl < ' a , ' tcx > EvalContext < ' a , ' tcx > {
136
- pub fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , mir_map : & ' a MirMap < ' tcx > ) -> Self {
139
+ pub fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , mir_map : & ' a MirMap < ' tcx > , memory_size : usize , stack_limit : usize ) -> Self {
137
140
EvalContext {
138
141
tcx : tcx,
139
142
mir_map : mir_map,
140
143
mir_cache : RefCell :: new ( DefIdMap ( ) ) ,
141
- memory : Memory :: new ( & tcx. data_layout ) ,
144
+ memory : Memory :: new ( & tcx. data_layout , memory_size ) ,
142
145
statics : HashMap :: new ( ) ,
143
146
stack : Vec :: new ( ) ,
147
+ stack_limit : stack_limit,
144
148
}
145
149
}
146
150
147
- pub fn alloc_ret_ptr ( & mut self , output_ty : ty:: FnOutput < ' tcx > , substs : & ' tcx Substs < ' tcx > ) -> Option < Pointer > {
151
+ pub fn alloc_ret_ptr ( & mut self , output_ty : ty:: FnOutput < ' tcx > , substs : & ' tcx Substs < ' tcx > ) -> EvalResult < ' tcx , Option < Pointer > > {
148
152
match output_ty {
149
153
ty:: FnConverging ( ty) => {
150
154
let size = self . type_size_with_substs ( ty, substs) ;
151
- Some ( self . memory . allocate ( size) )
155
+ self . memory . allocate ( size) . map ( Some )
152
156
}
153
- ty:: FnDiverging => None ,
157
+ ty:: FnDiverging => Ok ( None ) ,
154
158
}
155
159
}
156
160
@@ -172,19 +176,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
172
176
use rustc_const_math:: { ConstInt , ConstIsize , ConstUsize , ConstFloat } ;
173
177
macro_rules! i2p {
174
178
( $i: ident, $n: expr) => { {
175
- let ptr = self . memory. allocate( $n) ;
179
+ let ptr = self . memory. allocate( $n) ? ;
176
180
self . memory. write_int( ptr, $i as i64 , $n) ?;
177
181
Ok ( ptr)
178
182
} }
179
183
}
180
184
match * const_val {
181
185
Float ( ConstFloat :: F32 ( f) ) => {
182
- let ptr = self . memory . allocate ( 4 ) ;
186
+ let ptr = self . memory . allocate ( 4 ) ? ;
183
187
self . memory . write_f32 ( ptr, f) ?;
184
188
Ok ( ptr)
185
189
} ,
186
190
Float ( ConstFloat :: F64 ( f) ) => {
187
- let ptr = self . memory . allocate ( 8 ) ;
191
+ let ptr = self . memory . allocate ( 8 ) ? ;
188
192
self . memory . write_f64 ( ptr, f) ?;
189
193
Ok ( ptr)
190
194
} ,
@@ -207,28 +211,28 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
207
211
Integral ( ConstInt :: Usize ( ConstUsize :: Us64 ( i) ) ) => i2p ! ( i, 8 ) ,
208
212
Str ( ref s) => {
209
213
let psize = self . memory . pointer_size ( ) ;
210
- let static_ptr = self . memory . allocate ( s. len ( ) ) ;
211
- let ptr = self . memory . allocate ( psize * 2 ) ;
214
+ let static_ptr = self . memory . allocate ( s. len ( ) ) ? ;
215
+ let ptr = self . memory . allocate ( psize * 2 ) ? ;
212
216
self . memory . write_bytes ( static_ptr, s. as_bytes ( ) ) ?;
213
217
self . memory . write_ptr ( ptr, static_ptr) ?;
214
218
self . memory . write_usize ( ptr. offset ( psize as isize ) , s. len ( ) as u64 ) ?;
215
219
Ok ( ptr)
216
220
}
217
221
ByteStr ( ref bs) => {
218
222
let psize = self . memory . pointer_size ( ) ;
219
- let static_ptr = self . memory . allocate ( bs. len ( ) ) ;
220
- let ptr = self . memory . allocate ( psize) ;
223
+ let static_ptr = self . memory . allocate ( bs. len ( ) ) ? ;
224
+ let ptr = self . memory . allocate ( psize) ? ;
221
225
self . memory . write_bytes ( static_ptr, bs) ?;
222
226
self . memory . write_ptr ( ptr, static_ptr) ?;
223
227
Ok ( ptr)
224
228
}
225
229
Bool ( b) => {
226
- let ptr = self . memory . allocate ( 1 ) ;
230
+ let ptr = self . memory . allocate ( 1 ) ? ;
227
231
self . memory . write_bool ( ptr, b) ?;
228
232
Ok ( ptr)
229
233
}
230
234
Char ( c) => {
231
- let ptr = self . memory . allocate ( 4 ) ;
235
+ let ptr = self . memory . allocate ( 4 ) ? ;
232
236
self . memory . write_uint ( ptr, c as u64 , 4 ) ?;
233
237
Ok ( ptr)
234
238
} ,
@@ -292,9 +296,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
292
296
} )
293
297
}
294
298
295
- pub fn push_stack_frame ( & mut self , def_id : DefId , span : codemap:: Span , mir : CachedMir < ' a , ' tcx > , substs : & ' tcx Substs < ' tcx > ,
296
- return_ptr : Option < Pointer > )
297
- {
299
+ pub fn push_stack_frame (
300
+ & mut self ,
301
+ def_id : DefId ,
302
+ span : codemap:: Span ,
303
+ mir : CachedMir < ' a , ' tcx > ,
304
+ substs : & ' tcx Substs < ' tcx > ,
305
+ return_ptr : Option < Pointer > ,
306
+ ) -> EvalResult < ' tcx , ( ) > {
298
307
let arg_tys = mir. arg_decls . iter ( ) . map ( |a| a. ty ) ;
299
308
let var_tys = mir. var_decls . iter ( ) . map ( |v| v. ty ) ;
300
309
let temp_tys = mir. temp_decls . iter ( ) . map ( |t| t. ty ) ;
@@ -304,7 +313,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
304
313
305
314
:: log_settings:: settings ( ) . indentation += 1 ;
306
315
307
- let locals: Vec < Pointer > = arg_tys. chain ( var_tys) . chain ( temp_tys) . map ( |ty| {
316
+ let locals: EvalResult < ' tcx , Vec < Pointer > > = arg_tys. chain ( var_tys) . chain ( temp_tys) . map ( |ty| {
308
317
let size = self . type_size_with_substs ( ty, substs) ;
309
318
self . memory . allocate ( size)
310
319
} ) . collect ( ) ;
@@ -313,14 +322,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
313
322
mir : mir. clone ( ) ,
314
323
block : mir:: START_BLOCK ,
315
324
return_ptr : return_ptr,
316
- locals : locals,
325
+ locals : locals? ,
317
326
var_offset : num_args,
318
327
temp_offset : num_args + num_vars,
319
328
span : span,
320
329
def_id : def_id,
321
330
substs : substs,
322
331
stmt : 0 ,
323
332
} ) ;
333
+ if self . stack . len ( ) > self . stack_limit {
334
+ Err ( EvalError :: StackFrameLimitReached )
335
+ } else {
336
+ Ok ( ( ) )
337
+ }
324
338
}
325
339
326
340
fn pop_stack_frame ( & mut self ) {
@@ -548,7 +562,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
548
562
549
563
Box ( ty) => {
550
564
let size = self . type_size ( ty) ;
551
- let ptr = self . memory . allocate ( size) ;
565
+ let ptr = self . memory . allocate ( size) ? ;
552
566
self . memory . write_ptr ( dest, ptr) ?;
553
567
}
554
568
@@ -696,7 +710,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
696
710
Item { def_id, substs } => {
697
711
if let ty:: TyFnDef ( ..) = ty. sty {
698
712
// function items are zero sized
699
- Ok ( self . memory . allocate ( 0 ) )
713
+ Ok ( self . memory . allocate ( 0 ) ? )
700
714
} else {
701
715
let cid = ConstantId {
702
716
def_id : def_id,
@@ -935,37 +949,44 @@ pub fn eval_main<'a, 'tcx: 'a>(
935
949
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
936
950
mir_map : & ' a MirMap < ' tcx > ,
937
951
node_id : ast:: NodeId ,
952
+ memory_size : usize ,
953
+ step_limit : u64 ,
954
+ stack_limit : usize ,
938
955
) {
939
956
let mir = mir_map. map . get ( & node_id) . expect ( "no mir for main function" ) ;
940
957
let def_id = tcx. map . local_def_id ( node_id) ;
941
- let mut ecx = EvalContext :: new ( tcx, mir_map) ;
958
+ let mut ecx = EvalContext :: new ( tcx, mir_map, memory_size , stack_limit ) ;
942
959
let substs = tcx. mk_substs ( subst:: Substs :: empty ( ) ) ;
943
- let return_ptr = ecx. alloc_ret_ptr ( mir. return_ty , substs) . expect ( "main function should not be diverging" ) ;
960
+ let return_ptr = ecx. alloc_ret_ptr ( mir. return_ty , substs)
961
+ . expect ( "should at least be able to allocate space for the main function's return value" )
962
+ . expect ( "main function should not be diverging" ) ;
944
963
945
- ecx. push_stack_frame ( def_id, mir. span , CachedMir :: Ref ( mir) , substs, Some ( return_ptr) ) ;
964
+ ecx. push_stack_frame ( def_id, mir. span , CachedMir :: Ref ( mir) , substs, Some ( return_ptr) )
965
+ . expect ( "could not allocate first stack frame" ) ;
946
966
947
967
if mir. arg_decls . len ( ) == 2 {
948
968
// start function
949
969
let ptr_size = ecx. memory ( ) . pointer_size ( ) ;
950
- let nargs = ecx. memory_mut ( ) . allocate ( ptr_size) ;
970
+ let nargs = ecx. memory_mut ( ) . allocate ( ptr_size) . expect ( "can't allocate memory for nargs" ) ;
951
971
ecx. memory_mut ( ) . write_usize ( nargs, 0 ) . unwrap ( ) ;
952
- let args = ecx. memory_mut ( ) . allocate ( ptr_size) ;
972
+ let args = ecx. memory_mut ( ) . allocate ( ptr_size) . expect ( "can't allocate memory for arg pointer" ) ;
953
973
ecx. memory_mut ( ) . write_usize ( args, 0 ) . unwrap ( ) ;
954
974
ecx. frame_mut ( ) . locals [ 0 ] = nargs;
955
975
ecx. frame_mut ( ) . locals [ 1 ] = args;
956
976
}
957
977
958
- loop {
978
+ for _ in 0 ..step_limit {
959
979
match ecx. step ( ) {
960
980
Ok ( true ) => { }
961
- Ok ( false ) => break ,
981
+ Ok ( false ) => return ,
962
982
// FIXME: diverging functions can end up here in some future miri
963
983
Err ( e) => {
964
984
report ( tcx, & ecx, e) ;
965
- break ;
985
+ return ;
966
986
}
967
987
}
968
988
}
989
+ report ( tcx, & ecx, EvalError :: ExecutionTimeLimitReached ) ;
969
990
}
970
991
971
992
fn report ( tcx : TyCtxt , ecx : & EvalContext , e : EvalError ) {
0 commit comments