Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stacker"
version = "0.1.3"
version = "0.2.0"
authors = ["Alex Crichton <[email protected]>"]
build = "build.rs"
license = "MIT/Apache-2.0"
Expand Down
48 changes: 41 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
//! // guaranteed to have at least 32K of stack
//! });
//! ```
//!
//! # Platform support
//!
//! Only Windows, MacOS and Linux are supported. Other platforms don't do anything
//! and will overflow your stack.

#![allow(improper_ctypes)]

Expand Down Expand Up @@ -60,9 +65,14 @@ fn set_stack_limit(l: usize) {
///
/// The closure `f` is guaranteed to run on a stack with at least `red_zone`
/// bytes, and it will be run on the current stack if there's space available.
pub fn maybe_grow<R, F: FnOnce() -> R>(red_zone: usize,
stack_size: usize,
f: F) -> R {
pub fn maybe_grow<
R,
F: FnOnce() -> R + std::panic::UnwindSafe,
>(
red_zone: usize,
stack_size: usize,
f: F,
) -> R {
if remaining_stack() >= red_zone {
f()
} else {
Expand All @@ -81,15 +91,25 @@ pub fn remaining_stack() -> usize {
}

#[inline(never)]
fn grow_the_stack<R, F: FnOnce() -> R>(stack_size: usize, f: F) -> R {
fn grow_the_stack<
R,
F: FnOnce() -> R + std::panic::UnwindSafe,
>(
stack_size: usize,
f: F,
) -> R {
let mut f = Some(f);
let mut ret = None;
unsafe {
_grow_the_stack(stack_size, &mut || {
ret = Some(f.take().unwrap()());
let f: F = f.take().unwrap();
ret = Some(std::panic::catch_unwind(f));
});
}
ret.unwrap()
match ret.unwrap() {
Ok(ret) => ret,
Err(payload) => std::panic::resume_unwind(payload),
}
}

unsafe fn _grow_the_stack(stack_size: usize, mut f: &mut FnMut()) {
Expand Down Expand Up @@ -177,7 +197,21 @@ cfg_if! {
}
} else {
unsafe fn guess_os_stack_limit() -> usize {
panic!("cannot guess the stack limit on this platform");
0
}
mod exports {
#[no_mangle]
extern fn __stacker_stack_pointer() -> usize {
0
}
#[no_mangle]
unsafe extern fn __stacker_switch_stacks(
_new_stack: usize,
fnptr: unsafe fn(&mut &mut FnMut()),
dataptr: &mut &mut FnMut(),
) {
fnptr(dataptr)
}
}
}
}
27 changes: 27 additions & 0 deletions tests/panic_handling.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
extern crate stacker;

const RED_ZONE: usize = 100*1024; // 100k
const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB

pub fn ensure_sufficient_stack<R, F: FnOnce() -> R + std::panic::UnwindSafe>(
f: F
) -> R {
stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f)
}

#[inline(never)]
fn recurse(n: usize) {
let x = [42u8; 50000];
if n == 0 {
panic!("an inconvenient time");
} else {
ensure_sufficient_stack(|| recurse(n - 1));
}
drop(x);
}

#[test]
#[should_panic]
fn foo() {
recurse(10000);
}