Skip to content

Commit 303d7c7

Browse files
committed
Print stack overflow messages for Windows, Linux and OS X
Fixes rust-lang#17562
1 parent 9ec3772 commit 303d7c7

File tree

14 files changed

+773
-29
lines changed

14 files changed

+773
-29
lines changed

src/libgreen/simple.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ impl Runtime for SimpleTask {
8181
}
8282
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> { None }
8383
fn stack_bounds(&self) -> (uint, uint) { fail!() }
84+
fn stack_guard(&self) -> Option<uint> { fail!() }
8485
fn can_block(&self) -> bool { true }
8586
fn wrap(self: Box<SimpleTask>) -> Box<Any+'static> { fail!() }
8687
}

src/libgreen/stack.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ impl Stack {
8282
}
8383
}
8484

85+
/// Point to the last writable byte of the stack
86+
pub fn guard(&self) -> *const uint {
87+
(self.start() as uint + page_size()) as *const uint
88+
}
89+
8590
/// Point to the low end of the allocated stack
8691
pub fn start(&self) -> *const uint {
8792
self.buf.as_ref().map(|m| m.data() as *const uint)

src/libgreen/task.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,13 @@ impl Runtime for GreenTask {
486486
c.current_stack_segment.end() as uint)
487487
}
488488

489+
fn stack_guard(&self) -> Option<uint> {
490+
let c = self.coroutine.as_ref()
491+
.expect("GreenTask.stack_guard called without a coroutine");
492+
493+
Some(c.current_stack_segment.guard() as uint)
494+
}
495+
489496
fn can_block(&self) -> bool { false }
490497

491498
fn wrap(self: Box<GreenTask>) -> Box<Any+'static> {

src/libnative/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int {
132132
rt::init(argc, argv);
133133
let mut exit_code = None;
134134
let mut main = Some(main);
135-
let mut task = task::new((my_stack_bottom, my_stack_top));
135+
let mut task = task::new((my_stack_bottom, my_stack_top),
136+
rt::thread::main_guard_page());
136137
task.name = Some(str::Slice("<main>"));
137138
drop(task.run(|| {
138139
unsafe {

src/libnative/task.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ use io;
2929
use std::task::{TaskBuilder, Spawner};
3030

3131
/// Creates a new Task which is ready to execute as a 1:1 task.
32-
pub fn new(stack_bounds: (uint, uint)) -> Box<Task> {
32+
pub fn new(stack_bounds: (uint, uint), stack_guard: uint) -> Box<Task> {
3333
let mut task = box Task::new();
3434
let mut ops = ops();
3535
ops.stack_bounds = stack_bounds;
36+
ops.stack_guard = stack_guard;
3637
task.put_runtime(ops);
3738
return task;
3839
}
@@ -44,6 +45,7 @@ fn ops() -> Box<Ops> {
4445
io: io::IoFactory::new(),
4546
// these *should* get overwritten
4647
stack_bounds: (0, 0),
48+
stack_guard: 0
4749
}
4850
}
4951

@@ -115,6 +117,8 @@ struct Ops {
115117
// native tasks necessarily know their precise bounds, hence this is
116118
// optional.
117119
stack_bounds: (uint, uint),
120+
121+
stack_guard: uint
118122
}
119123

120124
impl rt::Runtime for Ops {
@@ -138,6 +142,14 @@ impl rt::Runtime for Ops {
138142

139143
fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds }
140144

145+
fn stack_guard(&self) -> Option<uint> {
146+
if self.stack_guard != 0 {
147+
Some(self.stack_guard)
148+
} else {
149+
None
150+
}
151+
}
152+
141153
fn can_block(&self) -> bool { true }
142154

143155
// This function gets a little interesting. There are a few safety and

src/librustrt/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ mod local_ptr;
5151
mod thread_local_storage;
5252
mod util;
5353
mod libunwind;
54+
mod stack_overflow;
5455

5556
pub mod args;
5657
pub mod bookkeeping;
@@ -92,6 +93,8 @@ pub trait Runtime {
9293
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>>;
9394
/// The (low, high) edges of the current stack.
9495
fn stack_bounds(&self) -> (uint, uint); // (lo, hi)
96+
/// The last writable byte of the stack next to the guard page
97+
fn stack_guard(&self) -> Option<uint>;
9598
fn can_block(&self) -> bool;
9699

97100
// FIXME: This is a serious code smell and this should not exist at all.
@@ -113,6 +116,7 @@ pub fn init(argc: int, argv: *const *const u8) {
113116
args::init(argc, argv);
114117
local_ptr::init();
115118
at_exit_imp::init();
119+
thread::init();
116120
}
117121

118122
// FIXME(#14344) this shouldn't be necessary
@@ -151,6 +155,7 @@ pub unsafe fn cleanup() {
151155
bookkeeping::wait_for_other_tasks();
152156
at_exit_imp::run();
153157
args::cleanup();
158+
thread::cleanup();
154159
local_ptr::cleanup();
155160
}
156161

src/librustrt/stack.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ pub const RED_ZONE: uint = 20 * 1024;
5656
#[lang = "stack_exhausted"]
5757
extern fn stack_exhausted() {
5858
use core::prelude::*;
59-
use alloc::boxed::Box;
6059
use local::Local;
6160
use task::Task;
6261
use core::intrinsics;
@@ -104,21 +103,13 @@ extern fn stack_exhausted() {
104103
// #9854 - unwinding on windows through __morestack has never worked
105104
// #2361 - possible implementation of not using landing pads
106105

107-
let task: Option<Box<Task>> = Local::try_take();
108-
let name = match task {
109-
Some(ref task) => {
110-
task.name.as_ref().map(|n| n.as_slice())
111-
}
112-
None => None
113-
};
114-
let name = name.unwrap_or("<unknown>");
106+
let task: Option<*mut Task> = Local::try_unsafe_borrow();
115107

116-
// See the message below for why this is not emitted to the
117-
// task's logger. This has the additional conundrum of the
118-
// logger may not be initialized just yet, meaning that an FFI
119-
// call would happen to initialized it (calling out to libuv),
120-
// and the FFI call needs 2MB of stack when we just ran out.
121-
rterrln!("task '{}' has overflowed its stack", name);
108+
let name = task.and_then(|task| {
109+
(*task).name.as_ref().map(|n| n.as_slice())
110+
});
111+
112+
::stack_overflow::report(name);
122113

123114
intrinsics::abort();
124115
}

0 commit comments

Comments
 (0)