Skip to content

Commit

Permalink
gc: Avoid double free when pointer appears on stack multiple times.
Browse files Browse the repository at this point in the history
  • Loading branch information
Elliott Slaughter committed Sep 7, 2012
1 parent 3f0d207 commit 9ea4afe
Showing 1 changed file with 23 additions and 14 deletions.
37 changes: 23 additions & 14 deletions src/libcore/gc.rs
@@ -1,5 +1,6 @@
import stackwalk::Word;
import libc::size_t;
import send_map::linear::LinearMap;

extern mod rustrt {
fn rust_annihilate_box(ptr: *Word);
Expand Down Expand Up @@ -37,7 +38,7 @@ unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
return None;
}

type Visitor = fn(root: **Word, tydesc: *Word);
type Visitor = fn(root: **Word, tydesc: *Word) -> bool;

unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
let fp_bytes: *u8 = unsafe::reinterpret_cast(&fp);
Expand Down Expand Up @@ -69,7 +70,7 @@ unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
} else {
ptr::null()
};
visitor(root, tydesc);
if !visitor(root, tydesc) { return; }
}
sri += 1;
}
Expand All @@ -94,25 +95,25 @@ const need_cleanup: Memory = exchange_heap | stack;

unsafe fn walk_gc_roots(mem: Memory, visitor: Visitor) {
let mut last_ret: *Word = ptr::null();
do stackwalk::walk_stack |frame| {
for stackwalk::walk_stack |frame| {
unsafe {
if ptr::is_not_null(last_ret) {
let sp = is_safe_point(last_ret);
match sp {
Some(sp_info) => {
do walk_safe_point(frame.fp, sp_info) |root, tydesc| {
for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
if ptr::is_null(tydesc) {
// Root is a generic box.
let refcount = **root;
if mem | task_local_heap != 0 && refcount != -1 {
visitor(root, tydesc);
if !visitor(root, tydesc) { return; }
} else if mem | exchange_heap != 0 {
visitor(root, tydesc);
if !visitor(root, tydesc) { return; }
}
} else {
// Root is a non-immediate.
if mem | stack != 0 {
visitor(root, tydesc);
if !visitor(root, tydesc) { return; }
}
}
}
Expand All @@ -122,34 +123,42 @@ unsafe fn walk_gc_roots(mem: Memory, visitor: Visitor) {
}
last_ret = *ptr::offset(frame.fp, 1) as *Word;
}
true
}
}

fn gc() {
unsafe {
let mut i = 0;
do walk_gc_roots(task_local_heap) |_root, _tydesc| {
for walk_gc_roots(task_local_heap) |_root, _tydesc| {
// FIXME(#2997): Walk roots and mark them.
io::stdout().write([46]); // .
i += 1;
}
}
}

type RootSet = LinearMap<*Word,()>;

fn RootSet() -> RootSet {
LinearMap()
}

// This should only be called from fail, as it will drop the roots
// which are *live* on the stack, rather than dropping those that are
// dead.
fn cleanup_stack_for_failure() {
unsafe {
let mut i = 0;
do walk_gc_roots(need_cleanup) |root, tydesc| {
let mut roots = ~RootSet();
for walk_gc_roots(need_cleanup) |root, tydesc| {
// Track roots to avoid double frees.
if option::is_some(roots.find(&*root)) {
again;
}
roots.insert(*root, ());

if ptr::is_null(tydesc) {
rustrt::rust_annihilate_box(*root);
} else {
rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t);
}
i += 1;
}
}
}

0 comments on commit 9ea4afe

Please sign in to comment.