about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-09-07 18:16:08 -0700
committerMarijn Haverbeke <marijnh@gmail.com>2011-09-08 10:24:25 +0200
commitfb9ab95a15e3c44d342ee9ef103179fff06baa8f (patch)
treec48469314b0a13e74b5fb5e3a8d36b9b0f8fb7de
parent7a0c9759fe3526310d4c7f30caf30bec39589e26 (diff)
downloadrust-fb9ab95a15e3c44d342ee9ef103179fff06baa8f.tar.gz
rust-fb9ab95a15e3c44d342ee9ef103179fff06baa8f.zip
rustc: When revoking a cleanup of a unique pointer, zero it out so that the GC won't try to visit it
-rw-r--r--src/comp/middle/trans.rs28
-rw-r--r--src/comp/middle/trans_common.rs12
2 files changed, 25 insertions, 15 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 572ce71f75c..aae5faf50f0 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 2943edd4333..6c3aa2f9a4c 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,