From e6acff828787b9b6c65ef66942f45e58b2f22ad6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Mar 2014 18:20:46 -0800 Subject: [PATCH] native: Fix usage of a deallocated mutex 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 --- src/libnative/bookkeeping.rs | 9 +++------ src/libnative/io/timer_helper.rs | 21 +++++++++++---------- src/test/run-pass/issue-12699.rs | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 src/test/run-pass/issue-12699.rs diff --git a/src/libnative/bookkeeping.rs b/src/libnative/bookkeeping.rs index b1addc5cda5..76e58ce753f 100644 --- a/src/libnative/bookkeeping.rs +++ b/src/libnative/bookkeeping.rs @@ -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(); } } diff --git a/src/libnative/io/timer_helper.rs b/src/libnative/io/timer_helper.rs index 7669d4a658f..45bd0f8b67c 100644 --- a/src/libnative/io/timer_helper.rs +++ b/src/libnative/io/timer_helper.rs @@ -36,6 +36,8 @@ use task; static mut HELPER_CHAN: *mut Chan = 0 as *mut Chan; 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)) { static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; static mut INITIALIZED: bool = false; @@ -53,6 +55,7 @@ pub fn boot(helper: fn(imp::signal, Port)) { task::spawn(proc() { bookkeeping::decrement(); helper(receive, msgp); + TIMER_HELPER_EXIT.lock().signal() }); rt::at_exit(proc() { shutdown() }); @@ -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 { diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs new file mode 100644 index 00000000000..24f9a05b2c1 --- /dev/null +++ b/src/test/run-pass/issue-12699.rs @@ -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 or the MIT license +// , 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); +}