Skip to content

Commit

Permalink
native: Fix usage of a deallocated mutex
Browse files Browse the repository at this point in the history
When the timer_helper thread exited, it would attempt to re-acquire the global
task count mutex, but the mutex had previously been deallocated, leading to
undefined behavior of the mutex, and in some cases deadlock.

Another mutex is used to coordinate shutting down the timer helper thread.

Closes #12699
  • Loading branch information
alexcrichton committed Mar 5, 2014
1 parent d8bd8de commit e6acff8
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 16 deletions.
9 changes: 3 additions & 6 deletions src/libnative/bookkeeping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ pub fn decrement() {
/// the entry points of native programs
pub fn wait_for_other_tasks() {
unsafe {
{
let mut guard = TASK_LOCK.lock();
while TASK_COUNT.load(atomics::SeqCst) > 0 {
guard.wait();
}
let mut guard = TASK_LOCK.lock();
while TASK_COUNT.load(atomics::SeqCst) > 0 {
guard.wait();
}
TASK_LOCK.destroy();
}
}
21 changes: 11 additions & 10 deletions src/libnative/io/timer_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ use task;
static mut HELPER_CHAN: *mut Chan<Req> = 0 as *mut Chan<Req>;
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;

static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;

pub fn boot(helper: fn(imp::signal, Port<Req>)) {
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
static mut INITIALIZED: bool = false;
Expand All @@ -53,6 +55,7 @@ pub fn boot(helper: fn(imp::signal, Port<Req>)) {
task::spawn(proc() {
bookkeeping::decrement();
helper(receive, msgp);
TIMER_HELPER_EXIT.lock().signal()
});

rt::at_exit(proc() { shutdown() });
Expand All @@ -70,17 +73,15 @@ pub fn send(req: Req) {
}

fn shutdown() {
// We want to wait for the entire helper task to exit, and in doing so it
// will attempt to decrement the global task count. When the helper was
// created, it decremented the count so it wouldn't count towards preventing
// the program to exit, so here we pair that manual decrement with a manual
// increment. We will then wait for the helper thread to exit by calling
// wait_for_other_tasks.
bookkeeping::increment();

// Request a shutdown, and then wait for the task to exit
send(Shutdown);
bookkeeping::wait_for_other_tasks();
unsafe {
let mut guard = TIMER_HELPER_EXIT.lock();
send(Shutdown);
guard.wait();
drop(guard);
TIMER_HELPER_EXIT.destroy();
}


// Clean up after ther helper thread
unsafe {
Expand Down
22 changes: 22 additions & 0 deletions src/test/run-pass/issue-12699.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate native;

use std::io::timer;

#[start]
fn start(argc: int, argv: **u8) -> int {
native::start(argc, argv, main)
}

fn main() {
timer::sleep(250);
}

0 comments on commit e6acff8

Please sign in to comment.