Skip to content

Commit 9f00586

Browse files
committed
rustuv: Fix a memory leak (documented inside)
This happened because the environment of a procedure was never deallocated.
1 parent f25c81a commit 9f00586

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

src/libgreen/context.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use stack::StackSegment;
2424
// then misalign the regs again.
2525
pub struct Context {
2626
/// The context entry point, saved here for later destruction
27-
priv start: ~Option<proc()>,
27+
priv start: Option<~proc()>,
2828
/// Hold the registers while the task or scheduler is suspended
2929
priv regs: ~Registers,
3030
/// Lower bound and upper bound for the stack
@@ -34,7 +34,7 @@ pub struct Context {
3434
impl Context {
3535
pub fn empty() -> Context {
3636
Context {
37-
start: ~None,
37+
start: None,
3838
regs: new_regs(),
3939
stack_bounds: None,
4040
}
@@ -43,8 +43,26 @@ impl Context {
4343
/// Create a new context that will resume execution by running proc()
4444
pub fn new(start: proc(), stack: &mut StackSegment) -> Context {
4545
// The C-ABI function that is the task entry point
46-
extern fn task_start_wrapper(f: &mut Option<proc()>) {
47-
f.take_unwrap()()
46+
//
47+
// Note that this function is a little sketchy. We're taking a
48+
// procedure, transmuting it to a stack-closure, and then calling to
49+
// closure. This leverages the fact that the representation of these two
50+
// types is the same.
51+
//
52+
// The reason that we're doing this is that this procedure is expected
53+
// to never return. The codegen which frees the environment of the
54+
// procedure occurs *after* the procedure has completed, and this means
55+
// that we'll never actually free the procedure.
56+
//
57+
// To solve this, we use this transmute (to not trigger the procedure
58+
// deallocation here), and then store a copy of the procedure in the
59+
// `Context` structure returned. When the `Context` is deallocated, then
60+
// the entire procedure box will be deallocated as well.
61+
extern fn task_start_wrapper(f: &proc()) {
62+
unsafe {
63+
let f: &|| = transmute(f);
64+
(*f)()
65+
}
4866
}
4967

5068
let sp: *uint = stack.end();
@@ -60,10 +78,10 @@ impl Context {
6078
// FIXME #7767: Putting main into a ~ so it's a thin pointer and can
6179
// be passed to the spawn function. Another unfortunate
6280
// allocation
63-
let box = ~Some(start);
81+
let start = ~start;
6482
initialize_call_frame(&mut *regs,
6583
task_start_wrapper as *c_void,
66-
unsafe { transmute(&*box) },
84+
unsafe { transmute(&*start) },
6785
sp);
6886

6987
// Scheduler tasks don't have a stack in the "we allocated it" sense,
@@ -78,7 +96,7 @@ impl Context {
7896
Some((stack_base as uint, sp as uint))
7997
};
8098
return Context {
81-
start: box,
99+
start: Some(start),
82100
regs: regs,
83101
stack_bounds: bounds,
84102
}

0 commit comments

Comments
 (0)