Skip to content

Support panicking and make unsupported platforms a nop #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
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);
}