@@ -135,21 +135,38 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
135
135
// If there is a cleanup block and the function we're calling can unwind, then
136
136
// do an invoke, otherwise do a call.
137
137
let fn_ty = bx. fn_decl_backend_type ( & fn_abi) ;
138
- if let Some ( cleanup) = cleanup. filter ( |_| fn_abi. can_unwind ) {
138
+
139
+ let unwind_block = if let Some ( cleanup) = cleanup. filter ( |_| fn_abi. can_unwind ) {
140
+ Some ( self . llblock ( fx, cleanup) )
141
+ } else if fx. mir [ self . bb ] . is_cleanup
142
+ && fn_abi. can_unwind
143
+ && !base:: wants_msvc_seh ( fx. cx . tcx ( ) . sess )
144
+ {
145
+ // Exception must not propagate out of the execution of a cleanup (doing so
146
+ // can cause undefined behaviour). We insert a double unwind guard for
147
+ // functions that can potentially unwind to protect against this.
148
+ //
149
+ // This is not necessary for SEH which does not use successive unwinding
150
+ // like Itanium EH. EH frames in SEH are different from normal function
151
+ // frames and SEH will abort automatically if an exception tries to
152
+ // propagate out from cleanup.
153
+ Some ( fx. double_unwind_guard ( ) )
154
+ } else {
155
+ None
156
+ } ;
157
+
158
+ if let Some ( unwind_block) = unwind_block {
139
159
let ret_llbb = if let Some ( ( _, target) ) = destination {
140
160
fx. llbb ( target)
141
161
} else {
142
162
fx. unreachable_block ( )
143
163
} ;
144
- let invokeret = bx. invoke (
145
- fn_ty,
146
- fn_ptr,
147
- & llargs,
148
- ret_llbb,
149
- self . llblock ( fx, cleanup) ,
150
- self . funclet ( fx) ,
151
- ) ;
164
+ let invokeret =
165
+ bx. invoke ( fn_ty, fn_ptr, & llargs, ret_llbb, unwind_block, self . funclet ( fx) ) ;
152
166
bx. apply_attrs_callsite ( & fn_abi, invokeret) ;
167
+ if fx. mir [ self . bb ] . is_cleanup {
168
+ bx. apply_attrs_to_cleanup_callsite ( invokeret) ;
169
+ }
153
170
154
171
if let Some ( ( ret_dest, target) ) = destination {
155
172
let mut ret_bx = fx. build_block ( target) ;
@@ -486,17 +503,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
486
503
let span = terminator. source_info . span ;
487
504
self . set_debug_loc ( & mut bx, terminator. source_info ) ;
488
505
489
- // Get the location information.
490
- let location = self . get_caller_location ( & mut bx, terminator. source_info ) . immediate ( ) ;
491
-
492
506
// Obtain the panic entry point.
493
507
let def_id = common:: langcall ( bx. tcx ( ) , Some ( span) , "" , LangItem :: PanicNoUnwind ) ;
494
508
let instance = ty:: Instance :: mono ( bx. tcx ( ) , def_id) ;
495
509
let fn_abi = bx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
496
510
let llfn = bx. get_fn_addr ( instance) ;
497
511
498
512
// Codegen the actual panic invoke/call.
499
- helper. do_call ( self , & mut bx, fn_abi, llfn, & [ location ] , None , None ) ;
513
+ helper. do_call ( self , & mut bx, fn_abi, llfn, & [ ] , None , None ) ;
500
514
}
501
515
502
516
/// Returns `true` if this is indeed a panic intrinsic and codegen is done.
@@ -1398,6 +1412,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1398
1412
} )
1399
1413
}
1400
1414
1415
+ fn double_unwind_guard ( & mut self ) -> Bx :: BasicBlock {
1416
+ self . double_unwind_guard . unwrap_or_else ( || {
1417
+ assert ! ( !base:: wants_msvc_seh( self . cx. sess( ) ) ) ;
1418
+
1419
+ let mut bx = self . new_block ( "abort" ) ;
1420
+ let llpersonality = self . cx . eh_personality ( ) ;
1421
+ let llretty = self . landing_pad_type ( ) ;
1422
+ bx. cleanup_landing_pad ( llretty, llpersonality) ;
1423
+
1424
+ let def_id = common:: langcall ( bx. tcx ( ) , None , "" , LangItem :: PanicNoUnwind ) ;
1425
+ let instance = ty:: Instance :: mono ( bx. tcx ( ) , def_id) ;
1426
+ let fn_abi = bx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
1427
+ let fn_ptr = bx. get_fn_addr ( instance) ;
1428
+ let fn_ty = bx. fn_decl_backend_type ( & fn_abi) ;
1429
+
1430
+ let llret = bx. call ( fn_ty, fn_ptr, & [ ] , None ) ;
1431
+ bx. apply_attrs_callsite ( & fn_abi, llret) ;
1432
+ bx. apply_attrs_to_cleanup_callsite ( llret) ;
1433
+
1434
+ bx. unreachable ( ) ;
1435
+ let llbb = bx. llbb ( ) ;
1436
+
1437
+ self . double_unwind_guard = Some ( llbb) ;
1438
+ llbb
1439
+ } )
1440
+ }
1441
+
1401
1442
// FIXME(eddyb) replace with `build_sibling_block`/`append_sibling_block`
1402
1443
// (which requires having a `Bx` already, and not all callers do).
1403
1444
fn new_block ( & self , name : & str ) -> Bx {
0 commit comments