From c341eb90522294dda6dbce646d1c0a7170a48bfc Mon Sep 17 00:00:00 2001 From: Elliott Slaughter Date: Mon, 23 Jul 2012 16:00:19 -0700 Subject: [PATCH] Don't emit invoke instructions inside landing pads. We can't throw an exception from inside a landing pad without corrupting the exception handler, so we have no hope of dealing with these exceptions anyway. See: http://llvm.org/docs/ExceptionHandling.html#cleanups Part of #2861. --- src/libcore/rt.rs | 6 +++++ src/rustc/middle/trans/base.rs | 38 +++++++++++++++++++------------ src/rustc/middle/trans/closure.rs | 2 +- src/rustc/middle/trans/common.rs | 13 +++++++---- src/rustc/middle/trans/foreign.rs | 2 +- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/libcore/rt.rs b/src/libcore/rt.rs index 356e81689f0..8990891112d 100644 --- a/src/libcore/rt.rs +++ b/src/libcore/rt.rs @@ -37,6 +37,9 @@ fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { ret rustrt::rust_upcall_exchange_malloc(td, size); } +// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from +// inside a landing pad may corrupt the state of the exception handler. If a +// problem occurs, call exit instead. #[rt(exchange_free)] fn rt_exchange_free(ptr: *c_char) { rustrt::rust_upcall_exchange_free(ptr); @@ -47,6 +50,9 @@ fn rt_malloc(td: *c_char, size: uintptr_t) -> *c_char { ret rustrt::rust_upcall_malloc(td, size); } +// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from +// inside a landing pad may corrupt the state of the exception handler. If a +// problem occurs, call exit instead. #[rt(free)] fn rt_free(ptr: *c_char) { rustrt::rust_upcall_free(ptr); diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 1d9080d2b19..beae7d59b7c 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -276,7 +276,7 @@ fn alloca_zeroed(cx: block, t: TypeRef) -> ValueRef { fn alloca_maybe_zeroed(cx: block, t: TypeRef, zero: bool) -> ValueRef { let _icx = cx.insn_ctxt(~"alloca"); if cx.unreachable { ret llvm::LLVMGetUndef(t); } - let initcx = raw_block(cx.fcx, cx.fcx.llstaticallocas); + let initcx = raw_block(cx.fcx, false, cx.fcx.llstaticallocas); let p = Alloca(initcx, t); if zero { Store(initcx, C_null(t), p); } ret p; @@ -294,7 +294,7 @@ fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) -> block { fn arrayalloca(cx: block, t: TypeRef, v: ValueRef) -> ValueRef { let _icx = cx.insn_ctxt(~"arrayalloca"); if cx.unreachable { ret llvm::LLVMGetUndef(t); } - ret ArrayAlloca(raw_block(cx.fcx, cx.fcx.llstaticallocas), t, v); + ret ArrayAlloca(raw_block(cx.fcx, false, cx.fcx.llstaticallocas), t, v); } // Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes). @@ -3228,6 +3228,11 @@ fn need_invoke(bcx: block) -> bool { ret false; } + // Avoid using invoke if we are already inside a landing pad. + if bcx.is_lpad { + ret false; + } + if have_cached_lpad(bcx) { ret true; } @@ -3291,7 +3296,7 @@ fn get_landing_pad(bcx: block) -> BasicBlockRef { alt copy inf.landing_pad { some(target) { cached = some(target); } none { - pad_bcx = sub_block(bcx, ~"unwind"); + pad_bcx = lpad_block(bcx, ~"unwind"); inf.landing_pad = some(pad_bcx.llbb); } } @@ -4107,7 +4112,8 @@ fn trans_stmt(cx: block, s: ast::stmt) -> block { // You probably don't want to use this one. See the // next three functions instead. fn new_block(cx: fn_ctxt, parent: option, +kind: block_kind, - name: ~str, opt_node_info: option) -> block { + is_lpad: bool, name: ~str, opt_node_info: option) + -> block { let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo { cx.ccx.names(name) @@ -4115,7 +4121,7 @@ fn new_block(cx: fn_ctxt, parent: option, +kind: block_kind, let llbb: BasicBlockRef = str::as_c_str(s, |buf| { llvm::LLVMAppendBasicBlock(cx.llfn, buf) }); - let bcx = mk_block(llbb, parent, kind, opt_node_info, cx); + let bcx = mk_block(llbb, parent, kind, is_lpad, opt_node_info, cx); do option::iter(parent) |cx| { if cx.unreachable { Unreachable(bcx); } }; @@ -4129,14 +4135,14 @@ fn simple_block_scope() -> block_kind { // Use this when you're at the top block of a function or the like. fn top_scope_block(fcx: fn_ctxt, opt_node_info: option) -> block { - ret new_block(fcx, none, simple_block_scope(), + ret new_block(fcx, none, simple_block_scope(), false, ~"function top level", opt_node_info); } fn scope_block(bcx: block, opt_node_info: option, n: ~str) -> block { - ret new_block(bcx.fcx, some(bcx), simple_block_scope(), + ret new_block(bcx.fcx, some(bcx), simple_block_scope(), bcx.is_lpad, n, opt_node_info); } @@ -4147,17 +4153,21 @@ fn loop_scope_block(bcx: block, loop_break: block, n: ~str, mut cleanups: ~[], mut cleanup_paths: ~[], mut landing_pad: none - }), n, opt_node_info); + }), bcx.is_lpad, n, opt_node_info); } +// Use this when creating a block for the inside of a landing pad. +fn lpad_block(bcx: block, n: ~str) -> block { + new_block(bcx.fcx, some(bcx), block_non_scope, true, n, none) +} // Use this when you're making a general CFG BB within a scope. fn sub_block(bcx: block, n: ~str) -> block { - new_block(bcx.fcx, some(bcx), block_non_scope, n, none) + new_block(bcx.fcx, some(bcx), block_non_scope, bcx.is_lpad, n, none) } -fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block { - mk_block(llbb, none, block_non_scope, none, fcx) +fn raw_block(fcx: fn_ctxt, is_lpad: bool, llbb: BasicBlockRef) -> block { + mk_block(llbb, none, block_non_scope, is_lpad, none, fcx) } @@ -4475,14 +4485,14 @@ fn copy_args_to_allocas(fcx: fn_ctxt, bcx: block, args: ~[ast::arg], fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) { let _icx = fcx.insn_ctxt(~"finish_fn"); tie_up_header_blocks(fcx, lltop); - let ret_cx = raw_block(fcx, fcx.llreturn); + let ret_cx = raw_block(fcx, false, fcx.llreturn); RetVoid(ret_cx); } fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) { let _icx = fcx.insn_ctxt(~"tie_up_header_blocks"); - Br(raw_block(fcx, fcx.llstaticallocas), fcx.llloadenv); - Br(raw_block(fcx, fcx.llloadenv), lltop); + Br(raw_block(fcx, false, fcx.llstaticallocas), fcx.llloadenv); + Br(raw_block(fcx, false, fcx.llloadenv), lltop); } enum self_arg { impl_self(ty::t), no_self, } diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs index c8d55ff0945..5cfc1d98ec6 100644 --- a/src/rustc/middle/trans/closure.rs +++ b/src/rustc/middle/trans/closure.rs @@ -319,7 +319,7 @@ fn load_environment(fcx: fn_ctxt, load_ret_handle: bool, ck: ty::closure_kind) { let _icx = fcx.insn_ctxt(~"closure::load_environment"); - let bcx = raw_block(fcx, fcx.llloadenv); + let bcx = raw_block(fcx, false, fcx.llloadenv); // Load a pointer to the closure data, skipping over the box header: let llcdata = base::opaque_box_body(bcx, cdata_ty, fcx.llenv); diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index c002c5a2a43..fbea25964e6 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -393,17 +393,19 @@ class block_ { let parent: option; // The 'kind' of basic block this is. let kind: block_kind; + // Is this block part of a landing pad? + let is_lpad: bool; // info about the AST node this block originated from, if any let node_info: option; // The function context for the function to which this block is // attached. let fcx: fn_ctxt; new(llbb: BasicBlockRef, parent: option, -kind: block_kind, - node_info: option, fcx: fn_ctxt) { + is_lpad: bool, node_info: option, fcx: fn_ctxt) { // sigh self.llbb = llbb; self.terminated = false; self.unreachable = false; - self.parent = parent; self.kind = kind; self.node_info = node_info; - self.fcx = fcx; + self.parent = parent; self.kind = kind; self.is_lpad = is_lpad; + self.node_info = node_info; self.fcx = fcx; } } @@ -412,8 +414,9 @@ class block_ { enum block = @block_; fn mk_block(llbb: BasicBlockRef, parent: option, -kind: block_kind, - node_info: option, fcx: fn_ctxt) -> block { - block(@block_(llbb, parent, kind, node_info, fcx)) + is_lpad: bool, node_info: option, fcx: fn_ctxt) + -> block { + block(@block_(llbb, parent, kind, is_lpad, node_info, fcx)) } // First two args are retptr, env diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs index 21ffefc5456..9d11c936a29 100644 --- a/src/rustc/middle/trans/foreign.rs +++ b/src/rustc/middle/trans/foreign.rs @@ -537,7 +537,7 @@ fn build_wrap_fn_(ccx: @crate_ctxt, tie_up_header_blocks(fcx, lltop); // Make sure our standard return block (that we didn't use) is terminated - let ret_cx = raw_block(fcx, fcx.llreturn); + let ret_cx = raw_block(fcx, false, fcx.llreturn); Unreachable(ret_cx); }