@@ -8,6 +8,8 @@ use std::rc::Rc;
8
8
use rand:: rngs:: StdRng ;
9
9
10
10
use rustc:: hir:: def_id:: DefId ;
11
+ use rustc:: ty:: { self , Ty , TyCtxt , layout:: { Size , LayoutOf , TyLayout } } ;
12
+ use rustc:: ty:: { ExistentialPredicate , ExistentialTraitRef , RegionKind , List , ParamEnv , TyCtxt } ;
11
13
use rustc:: mir;
12
14
use rustc:: ty:: {
13
15
self ,
@@ -25,6 +27,25 @@ pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but
25
27
pub const STACK_SIZE : u64 = 16 * PAGE_SIZE ; // whatever
26
28
pub const NUM_CPUS : u64 = 1 ;
27
29
30
+ pub struct FrameData < ' tcx > {
31
+ pub call_id : stacked_borrows:: CallId ,
32
+ pub catch_panic : Option < UnwindData < ' tcx > > ,
33
+ pub is_box_me_frame : bool
34
+ }
35
+
36
+ /// Hold all of the relevant data for a call to
37
+ /// __rust_maybe_catch_panic
38
+ ///
39
+ /// If a panic occurs, we update this data with
40
+ /// the information from the panic site
41
+ pub struct UnwindData < ' tcx > {
42
+ pub data : Pointer < Tag > ,
43
+ pub data_ptr : MPlaceTy < ' tcx , Tag > ,
44
+ pub vtable_ptr : MPlaceTy < ' tcx , Tag > ,
45
+ pub dest : PlaceTy < ' tcx , Tag > ,
46
+ pub ret : mir:: BasicBlock ,
47
+ }
48
+
28
49
/// Extra memory kinds
29
50
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
30
51
pub enum MiriMemoryKind {
@@ -38,6 +59,8 @@ pub enum MiriMemoryKind {
38
59
Env ,
39
60
/// Statics.
40
61
Static ,
62
+ /// Temporary storage for implementing unwinding
63
+ UnwindHelper ,
41
64
}
42
65
43
66
impl Into < MemoryKind < MiriMemoryKind > > for MiriMemoryKind {
@@ -78,6 +101,36 @@ impl MemoryExtra {
78
101
}
79
102
}
80
103
104
+ pub struct CachedTypes < ' tcx > {
105
+ /// The layout of the type '*mut &mut dyn core::panic::BoxMeUp'
106
+ pub box_me_up_layout : TyLayout < ' tcx > ,
107
+ }
108
+
109
+ impl < ' tcx > CachedTypes < ' tcx > {
110
+ pub fn new ( tcx : TyCtxt < ' tcx > ) -> InterpResult < ' tcx , CachedTypes < ' tcx > > {
111
+ // We build up the layout of '*mut &mut dyn core::panic::BoxMeUp'
112
+ let box_me_up_did = helpers:: resolve_did ( tcx, & [ "core" , "panic" , "BoxMeUp" ] ) ?;
113
+ let traits = & [ ExistentialPredicate :: Trait ( ExistentialTraitRef {
114
+ def_id : box_me_up_did,
115
+ substs : List :: empty ( )
116
+ } ) ] ;
117
+
118
+ let me_mut_dyn = tcx. mk_dynamic (
119
+ ty:: Binder :: dummy ( tcx. intern_existential_predicates ( traits) ) ,
120
+ & RegionKind :: ReErased
121
+ ) ;
122
+
123
+ let me_mut_ref = tcx. mk_mut_ref ( & RegionKind :: ReErased , me_mut_dyn) ;
124
+ let me_mut_raw = tcx. mk_mut_ptr ( me_mut_ref) ;
125
+ let box_me_up_layout = tcx. layout_of ( ParamEnv :: empty ( ) . and ( me_mut_raw) )
126
+ . map_err ( |layout| InterpError :: Layout ( layout) ) ?;
127
+
128
+ Ok ( CachedTypes {
129
+ box_me_up_layout
130
+ } )
131
+ }
132
+ }
133
+
81
134
/// The machine itself.
82
135
pub struct Evaluator < ' tcx > {
83
136
/// Environment variables set by `setenv`.
@@ -102,10 +155,21 @@ pub struct Evaluator<'tcx> {
102
155
pub ( crate ) communicate : bool ,
103
156
104
157
pub ( crate ) file_handler : FileHandler ,
158
+
159
+ /// Extra information needed for unwinding
160
+ /// We create this even in abort mode, so
161
+ /// that we can perform some basic validation
162
+ /// during panics
163
+ pub ( crate ) cached_data : CachedTypes < ' tcx > ,
164
+
165
+ /// Whether or not we are currently unwinding from
166
+ /// a panic
167
+ pub ( crate ) unwinding : bool ,
168
+ pub ( crate ) box_me_up_tmp_ptr : Option < MPlaceTy < ' tcx , Tag > >
105
169
}
106
170
107
171
impl < ' tcx > Evaluator < ' tcx > {
108
- pub ( crate ) fn new ( communicate : bool ) -> Self {
172
+ pub ( crate ) fn new ( communicate : bool , cached_data : CachedTypes < ' tcx > ) -> Self {
109
173
Evaluator {
110
174
// `env_vars` could be initialized properly here if `Memory` were available before
111
175
// calling this method.
@@ -117,6 +181,9 @@ impl<'tcx> Evaluator<'tcx> {
117
181
tls : TlsData :: default ( ) ,
118
182
communicate,
119
183
file_handler : Default :: default ( ) ,
184
+ cached_data,
185
+ unwinding : false ,
186
+ box_me_up_tmp_ptr : None
120
187
}
121
188
}
122
189
}
@@ -144,7 +211,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx>
144
211
impl < ' mir , ' tcx > Machine < ' mir , ' tcx > for Evaluator < ' tcx > {
145
212
type MemoryKinds = MiriMemoryKind ;
146
213
147
- type FrameExtra = stacked_borrows :: CallId ;
214
+ type FrameExtra = FrameData < ' tcx > ;
148
215
type MemoryExtra = MemoryExtra ;
149
216
type AllocExtra = AllocExtra ;
150
217
type PointerTag = Tag ;
@@ -174,8 +241,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
174
241
args : & [ OpTy < ' tcx , Tag > ] ,
175
242
dest : Option < PlaceTy < ' tcx , Tag > > ,
176
243
ret : Option < mir:: BasicBlock > ,
244
+ unwind : Option < mir:: BasicBlock > ,
177
245
) -> InterpResult < ' tcx , Option < & ' mir mir:: Body < ' tcx > > > {
178
- ecx. find_fn ( instance, args, dest, ret)
246
+ ecx. find_fn ( instance, args, dest, ret, unwind )
179
247
}
180
248
181
249
#[ inline( always) ]
@@ -348,21 +416,66 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
348
416
#[ inline( always) ]
349
417
fn stack_push (
350
418
ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
351
- ) -> InterpResult < ' tcx , stacked_borrows:: CallId > {
352
- Ok ( ecx. memory ( ) . extra . stacked_borrows . borrow_mut ( ) . new_call ( ) )
419
+ ) -> InterpResult < ' tcx , FrameData < ' tcx > > {
420
+ Ok ( FrameData {
421
+ call_id : ecx. memory ( ) . extra . stacked_borrows . borrow_mut ( ) . new_call ( ) ,
422
+ catch_panic : None ,
423
+ is_box_me_frame : false
424
+ } )
353
425
}
354
426
355
427
#[ inline( always) ]
356
428
fn stack_pop (
357
429
ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
358
- extra : stacked_borrows:: CallId ,
359
- ) -> InterpResult < ' tcx > {
360
- Ok ( ecx
361
- . memory ( )
362
- . extra
363
- . stacked_borrows
364
- . borrow_mut ( )
365
- . end_call ( extra) )
430
+ extra : FrameData < ' tcx > ,
431
+ ) -> InterpResult < ' tcx , StackPopInfo > {
432
+ if extra. is_box_me_frame {
433
+ trace ! ( "unwinding: found box_me_frame" ) ;
434
+ ecx. machine . unwinding = true ;
435
+ }
436
+ if ecx. machine . unwinding {
437
+ trace ! ( "Popping during unwind!" ) ;
438
+ if let Some ( unwind_data) = ecx. frame_mut ( ) . extra . catch_panic . take ( ) {
439
+ // We've just popped the frame that was immediately above
440
+ // our target frame on the stack.
441
+ //
442
+ trace ! ( "unwinding: found target frame: {:?}" , ecx. frame( ) . span) ;
443
+
444
+ // 'box_me_up' has finished. 'temp_ptr' now holds
445
+ // a '*mut (dyn Any + Send)'
446
+ // We want to split this into its consituient parts -
447
+ // the data and vtable pointers - and store them back
448
+ // into the panic handler frame
449
+ let tmp_ptr = ecx. machine . box_me_up_tmp_ptr . take ( ) . unwrap ( ) ;
450
+ let real_ret = ecx. read_immediate ( tmp_ptr. into ( ) ) ?;
451
+ let payload_data_ptr = real_ret. to_scalar_ptr ( ) ?;
452
+ let payload_vtable_ptr = real_ret. to_meta ( ) ?. expect ( "Expected fat pointer" ) ;
453
+
454
+
455
+ let data_ptr = unwind_data. data_ptr . clone ( ) ;
456
+ let vtable_ptr = unwind_data. vtable_ptr . clone ( ) ;
457
+ let dest = unwind_data. dest . clone ( ) ;
458
+ drop ( unwind_data) ;
459
+
460
+
461
+ // Here, we write directly into the frame of the function
462
+ // that called '__rust_maybe_catch_panic'.
463
+ // (NOT the function that called '__rust_start_panic')
464
+
465
+ ecx. write_scalar ( payload_data_ptr, data_ptr. into ( ) ) ?;
466
+ ecx. write_scalar ( payload_vtable_ptr, vtable_ptr. into ( ) ) ?;
467
+
468
+ // We 'return' the value 1 from __rust_maybe_catch_panic,
469
+ // since there was a panic
470
+ ecx. write_scalar ( Scalar :: from_int ( 1 , dest. layout . size ) , dest) ?;
471
+ ecx. machine . unwinding = false ;
472
+
473
+ ecx. memory_mut ( ) . deallocate ( tmp_ptr. to_ptr ( ) ?, None , MiriMemoryKind :: UnwindHelper . into ( ) ) ?;
474
+ }
475
+ }
476
+ ecx. memory ( ) . extra . stacked_borrows . borrow_mut ( ) . end_call ( extra. call_id ) ;
477
+ Ok ( StackPopInfo { unwinding : ecx. machine . unwinding } )
478
+ >>>>>>> Support unwinding after a panic
366
479
}
367
480
368
481
#[ inline( always) ]
@@ -428,7 +541,7 @@ impl MayLeak for MiriMemoryKind {
428
541
fn may_leak ( self ) -> bool {
429
542
use self :: MiriMemoryKind :: * ;
430
543
match self {
431
- Rust | C | WinHeap => false ,
544
+ Rust | C | WinHeap | UnwindHelper => false ,
432
545
Env | Static => true ,
433
546
}
434
547
}
0 commit comments