From fb9ab95a15e3c44d342ee9ef103179fff06baa8f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 7 Sep 2011 18:16:08 -0700 Subject: [PATCH] rustc: When revoking a cleanup of a unique pointer, zero it out so that the GC won't try to visit it --- src/comp/middle/trans.rs | 28 +++++++++++++++------------- src/comp/middle/trans_common.rs | 12 ++++++++++-- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 572ce71f75c0..aae5faf50f0d 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -2179,18 +2179,15 @@ fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef, if src.is_mem { ret zero_alloca(cx, src.res.val, t).bcx; } // If we're here, it must be a temporary. - revoke_clean(cx, src_val); - ret cx; + ret revoke_clean(cx, src_val, t); } else if ty::type_is_unique(tcx, t) || type_is_structural_or_param(tcx, t) { if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); } cx = memmove_ty(cx, dst, src_val, t).bcx; - if src.is_mem { - ret zero_alloca(cx, src_val, t).bcx; - } else { // Temporary value - revoke_clean(cx, src_val); - ret cx; - } + if src.is_mem { ret zero_alloca(cx, src_val, t).bcx; } + + // If we're here, it must be a temporary. + ret revoke_clean(cx, src_val, t); } bcx_ccx(cx).sess.bug("unexpected type in trans::move_val: " + ty_to_str(tcx, t)); @@ -3620,7 +3617,8 @@ fn trans_bind_1(cx: &@block_ctxt, f: &@ast::expr, f_res: &lval_result, fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef, to_zero: &mutable [{v: ValueRef, t: ty::t}], - to_revoke: &mutable [ValueRef], e: &@ast::expr) -> result { + to_revoke: &mutable [{v: ValueRef, t: ty::t}], + e: &@ast::expr) -> result { let ccx = bcx_ccx(cx); let e_ty = ty::expr_ty(ccx.tcx, e); let is_bot = ty::type_is_bot(ccx.tcx, e_ty); @@ -3672,7 +3670,9 @@ fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef, // Use actual ty, not declared ty -- anything else doesn't make // sense if declared ty is a ty param to_zero += [{v: lv.res.val, t: e_ty}]; - } else { to_revoke += [lv.res.val]; } + } else { + to_revoke += [{v: lv.res.val, t: e_ty}]; + } } ret rslt(bcx, val); } @@ -3691,7 +3691,7 @@ fn trans_args(cx: &@block_ctxt, llenv: ValueRef, args: [ValueRef], retslot: ValueRef, to_zero: [{v: ValueRef, t: ty::t}], - to_revoke: [ValueRef]} { + to_revoke: [{v: ValueRef, t: ty::t}]} { let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty); let llargs: [ValueRef] = []; @@ -3869,9 +3869,11 @@ fn trans_call(in_cx: &@block_ctxt, f: &@ast::expr, // Forget about anything we moved out. for {v: v, t: t}: {v: ValueRef, t: ty::t} in args_res.to_zero { - zero_alloca(bcx, v, t) + bcx = zero_alloca(bcx, v, t).bcx; + } + for {v: v, t: t} in args_res.to_revoke { + bcx = revoke_clean(bcx, v, t); } - for v: ValueRef in args_res.to_revoke { revoke_clean(bcx, v) } bcx = trans_block_cleanups(bcx, cx); let next_cx = new_sub_block_ctxt(in_cx, "next"); Br(bcx, next_cx.llbb); diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 2943edd43338..6c3aa2f9a4ca 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -314,7 +314,13 @@ fn add_clean_temp(cx: &@block_ctxt, val: ValueRef, ty: ty::t) { // to a system where we can also cancel the cleanup on local variables, but // this will be more involved. For now, we simply zero out the local, and the // drop glue checks whether it is zero. -fn revoke_clean(cx: &@block_ctxt, val: ValueRef) { +fn revoke_clean(cx: &@block_ctxt, val: ValueRef, t: ty::t) -> @block_ctxt { + if ty::type_is_unique(bcx_tcx(cx), t) { + // Just zero out the allocation. This ensures that the GC won't try to + // traverse dangling pointers. + ret trans::zero_alloca(cx, val, t).bcx; + } + let sc_cx = find_scope_cx(cx); let found = -1; let i = 0; @@ -329,12 +335,14 @@ fn revoke_clean(cx: &@block_ctxt, val: ValueRef) { } // The value does not have a cleanup associated with it. Might be a // constant or some immediate value. - if found == -1 { ret; } + if found == -1 { ret cx; } // We found the cleanup and remove it sc_cx.cleanups = std::vec::slice(sc_cx.cleanups, 0u, found as uint) + std::vec::slice(sc_cx.cleanups, (found as uint) + 1u, std::vec::len(sc_cx.cleanups)); + + ret cx; } fn get_res_dtor(ccx: &@crate_ctxt, sp: &span, did: &ast::def_id,