Skip to content

Commit e6acff8

Browse files
committed
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
1 parent d8bd8de commit e6acff8

File tree

3 files changed

+36
-16
lines changed

3 files changed

+36
-16
lines changed

src/libnative/bookkeeping.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@ pub fn decrement() {
3939
/// the entry points of native programs
4040
pub fn wait_for_other_tasks() {
4141
unsafe {
42-
{
43-
let mut guard = TASK_LOCK.lock();
44-
while TASK_COUNT.load(atomics::SeqCst) > 0 {
45-
guard.wait();
46-
}
42+
let mut guard = TASK_LOCK.lock();
43+
while TASK_COUNT.load(atomics::SeqCst) > 0 {
44+
guard.wait();
4745
}
48-
TASK_LOCK.destroy();
4946
}
5047
}

src/libnative/io/timer_helper.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ use task;
3636
static mut HELPER_CHAN: *mut Chan<Req> = 0 as *mut Chan<Req>;
3737
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
3838

39+
static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;
40+
3941
pub fn boot(helper: fn(imp::signal, Port<Req>)) {
4042
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
4143
static mut INITIALIZED: bool = false;
@@ -53,6 +55,7 @@ pub fn boot(helper: fn(imp::signal, Port<Req>)) {
5355
task::spawn(proc() {
5456
bookkeeping::decrement();
5557
helper(receive, msgp);
58+
TIMER_HELPER_EXIT.lock().signal()
5659
});
5760

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

7275
fn shutdown() {
73-
// We want to wait for the entire helper task to exit, and in doing so it
74-
// will attempt to decrement the global task count. When the helper was
75-
// created, it decremented the count so it wouldn't count towards preventing
76-
// the program to exit, so here we pair that manual decrement with a manual
77-
// increment. We will then wait for the helper thread to exit by calling
78-
// wait_for_other_tasks.
79-
bookkeeping::increment();
80-
8176
// Request a shutdown, and then wait for the task to exit
82-
send(Shutdown);
83-
bookkeeping::wait_for_other_tasks();
77+
unsafe {
78+
let mut guard = TIMER_HELPER_EXIT.lock();
79+
send(Shutdown);
80+
guard.wait();
81+
drop(guard);
82+
TIMER_HELPER_EXIT.destroy();
83+
}
84+
8485

8586
// Clean up after ther helper thread
8687
unsafe {

src/test/run-pass/issue-12699.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate native;
12+
13+
use std::io::timer;
14+
15+
#[start]
16+
fn start(argc: int, argv: **u8) -> int {
17+
native::start(argc, argv, main)
18+
}
19+
20+
fn main() {
21+
timer::sleep(250);
22+
}

0 commit comments

Comments
 (0)