From 05f08bd6e6d10573df48bb6cdd45012ca6c0fa9b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 17:40:55 +0100 Subject: [PATCH 01/12] Handle panics inside the grown stack --- Cargo.toml | 2 +- src/lib.rs | 27 +++++++++++++++++++++------ tests/panic_handling.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 tests/panic_handling.rs diff --git a/Cargo.toml b/Cargo.toml index ec19b84..329191a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.1.3" +version = "0.2.0" authors = ["Alex Crichton "] build = "build.rs" license = "MIT/Apache-2.0" diff --git a/src/lib.rs b/src/lib.rs index 9420627..2113b89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,9 +60,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>(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 { @@ -81,15 +86,25 @@ pub fn remaining_stack() -> usize { } #[inline(never)] -fn grow_the_stack 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()) { diff --git a/tests/panic_handling.rs b/tests/panic_handling.rs new file mode 100644 index 0000000..045fa28 --- /dev/null +++ b/tests/panic_handling.rs @@ -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 + 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); +} \ No newline at end of file From 34859d868ec90c2bf098cb8091ad7b1078f81f17 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 17:53:52 +0100 Subject: [PATCH 02/12] Implement nop for unsupported platforms --- src/lib.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2113b89..0804ca2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,7 +192,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) + } } } } From d6f75d369f140c4a9525c5ed7ecab46ba1afcef5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 17:55:50 +0100 Subject: [PATCH 03/12] Mention supported platforms --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0804ca2..76a3cc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)] From fc167483781fc10c81e2ee533331f6adf8be96de Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 22:57:15 +0100 Subject: [PATCH 04/12] Properly implement "unsupported target support" --- build.rs | 6 +----- src/arch/fallback.rs | 13 +++++++++++++ src/lib.rs | 14 -------------- 3 files changed, 14 insertions(+), 19 deletions(-) create mode 100644 src/arch/fallback.rs diff --git a/build.rs b/build.rs index 89ca9f7..7b8cab3 100644 --- a/build.rs +++ b/build.rs @@ -14,9 +14,6 @@ fn main() { cfg.define("APPLE", None); } else if target.contains("windows") { cfg.define("WINDOWS", None); - } else { - panic!("\n\nusing currently unsupported target triple with \ - stacker: {}\n\n", target); } if target.starts_with("x86_64") { @@ -26,8 +23,7 @@ fn main() { cfg.file(if msvc {"src/arch/i686.asm"} else {"src/arch/i686.S"}); cfg.define("X86", None); } else { - panic!("\n\nusing currently unsupported target triple with \ - stacker: {}\n\n", target); + cfg.file("fallback.rs"); } cfg.include("src/arch").compile("libstacker.a"); diff --git a/src/arch/fallback.rs b/src/arch/fallback.rs new file mode 100644 index 0000000..b8e008a --- /dev/null +++ b/src/arch/fallback.rs @@ -0,0 +1,13 @@ +#[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) +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 76a3cc0..8f8bd75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -199,19 +199,5 @@ cfg_if! { unsafe fn guess_os_stack_limit() -> usize { 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) - } - } } } From f321d878b7a6628a67863e66ac9936047c1ab0a0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 23:00:19 +0100 Subject: [PATCH 05/12] Use `AssertUnwindSafe` instead of trait bounds --- src/lib.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8f8bd75..62743b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,14 +65,7 @@ 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 + std::panic::UnwindSafe, ->( - red_zone: usize, - stack_size: usize, - f: F, -) -> R { +pub fn maybe_grow R>(red_zone: usize, stack_size: usize, f: F) -> R { if remaining_stack() >= red_zone { f() } else { @@ -91,19 +84,13 @@ pub fn remaining_stack() -> usize { } #[inline(never)] -fn grow_the_stack< - R, - F: FnOnce() -> R + std::panic::UnwindSafe, ->( - stack_size: usize, - f: F, -) -> R { +fn grow_the_stack R>(stack_size: usize, f: F) -> R { let mut f = Some(f); let mut ret = None; unsafe { _grow_the_stack(stack_size, &mut || { let f: F = f.take().unwrap(); - ret = Some(std::panic::catch_unwind(f)); + ret = Some(std::panic::catch_unwind(std::panic::AssertUnwindSafe(f))); }); } match ret.unwrap() { From 93b6cdce394408c9ee74cb707ea802ad57931be5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 11:19:13 +0100 Subject: [PATCH 06/12] Breaking change is no more --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 329191a..3127cb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stacker" -version = "0.2.0" +version = "0.1.4" authors = ["Alex Crichton "] build = "build.rs" license = "MIT/Apache-2.0" From 39d678ce7efb7cdb82056f6196fe10a815ec98e6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 11:28:23 +0100 Subject: [PATCH 07/12] Prefer `Option` over magical "0" stack sizes --- src/arch/fallback.rs | 8 +++---- src/lib.rs | 51 ++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/arch/fallback.rs b/src/arch/fallback.rs index b8e008a..2d1a59c 100644 --- a/src/arch/fallback.rs +++ b/src/arch/fallback.rs @@ -1,13 +1,13 @@ #[no_mangle] extern fn __stacker_stack_pointer() -> usize { - 0 + panic!("not supported") } #[no_mangle] unsafe extern fn __stacker_switch_stacks( _new_stack: usize, - fnptr: unsafe fn(&mut &mut FnMut()), - dataptr: &mut &mut FnMut(), + _fnptr: unsafe fn(&mut &mut FnMut()), + _dataptr: &mut &mut FnMut(), ) { - fnptr(dataptr) + panic!("not supported") } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 62743b6..b81a1e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,17 +43,17 @@ extern { } thread_local! { - static STACK_LIMIT: Cell = Cell::new(unsafe { + static STACK_LIMIT: Cell> = Cell::new(unsafe { guess_os_stack_limit() }) } -fn get_stack_limit() -> usize { +fn get_stack_limit() -> Option { STACK_LIMIT.with(|s| s.get()) } fn set_stack_limit(l: usize) { - STACK_LIMIT.with(|s| s.set(l)) + STACK_LIMIT.with(|s| s.set(Some(l))) } /// Grows the call stack if necessary. @@ -66,10 +66,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>(red_zone: usize, stack_size: usize, f: F) -> R { - if remaining_stack() >= red_zone { - f() + if let Some(remaining_stack_bytes) = remaining_stack() { + if remaining_stack_bytes >= red_zone { + f() + } else { + grow_the_stack(stack_size, f, remaining_stack_bytes) + } } else { - grow_the_stack(stack_size, f) + f() } } @@ -77,18 +81,18 @@ pub fn maybe_grow R>(red_zone: usize, stack_size: usize, f: F) /// /// This function will return the amount of stack space left which will be used /// to determine whether a stack switch should be made or not. -pub fn remaining_stack() -> usize { - unsafe { - __stacker_stack_pointer() - get_stack_limit() - } +pub fn remaining_stack() -> Option { + get_stack_limit().map(|limit| unsafe { + __stacker_stack_pointer() - limit + }) } #[inline(never)] -fn grow_the_stack R>(stack_size: usize, f: F) -> R { +fn grow_the_stack R>(stack_size: usize, f: F, remaining_stack_bytes: usize) -> R { let mut f = Some(f); let mut ret = None; unsafe { - _grow_the_stack(stack_size, &mut || { + _grow_the_stack(stack_size, remaining_stack_bytes, &mut || { let f: F = f.take().unwrap(); ret = Some(std::panic::catch_unwind(std::panic::AssertUnwindSafe(f))); }); @@ -99,7 +103,7 @@ fn grow_the_stack R>(stack_size: usize, f: F) -> R { } } -unsafe fn _grow_the_stack(stack_size: usize, mut f: &mut FnMut()) { +unsafe fn _grow_the_stack(stack_size: usize, old_limit: usize, mut f: &mut FnMut()) { // Align to 16-bytes (see below for why) let stack_size = (stack_size + 15) / 16 * 16; @@ -107,9 +111,6 @@ unsafe fn _grow_the_stack(stack_size: usize, mut f: &mut FnMut()) { let mut stack = Vec::::with_capacity(stack_size); let new_limit = stack.as_ptr() as usize + 32 * 1024; - // Save off the old stack limits - let old_limit = get_stack_limit(); - // Prepare stack limits for the stack switch set_stack_limit(new_limit); @@ -142,7 +143,7 @@ cfg_if! { // // https://github.com/adobe/webkit/blob/0441266/Source/WTF/wtf // /StackBounds.cpp - unsafe fn guess_os_stack_limit() -> usize { + unsafe fn guess_os_stack_limit() -> Option { #[cfg(target_pointer_width = "32")] extern { #[link_name = "__stacker_get_tib_32"] @@ -158,12 +159,12 @@ cfg_if! { // the struct layout of the 32-bit TIB. It looks like the struct // layout of the 64-bit TIB is also the same for getting the stack // limit: http://doxygen.reactos.org/d3/db0/structNT__TIB64.html - *get_tib_address().offset(2) + Some(*get_tib_address().offset(2)) } } else if #[cfg(target_os = "linux")] { use std::mem; - unsafe fn guess_os_stack_limit() -> usize { + unsafe fn guess_os_stack_limit() -> Option { let mut attr: libc::pthread_attr_t = mem::zeroed(); assert_eq!(libc::pthread_attr_init(&mut attr), 0); assert_eq!(libc::pthread_getattr_np(libc::pthread_self(), @@ -173,18 +174,18 @@ cfg_if! { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - stackaddr as usize + Some(stackaddr as usize) } } else if #[cfg(target_os = "macos")] { use libc::{c_void, pthread_t, size_t}; - unsafe fn guess_os_stack_limit() -> usize { - libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()) as usize + unsafe fn guess_os_stack_limit() -> Option { + Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self()) as usize) } } else { - unsafe fn guess_os_stack_limit() -> usize { - 0 + unsafe fn guess_os_stack_limit() -> Option { + None } } } From 9f97d52ad5950dd3300bf171755fed4843464d55 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 6 Nov 2018 20:48:39 +0100 Subject: [PATCH 08/12] Properly build fallback code --- build.rs | 3 ++- src/arch/fallback.rs | 5 ++++- src/lib.rs | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 7b8cab3..972feeb 100644 --- a/build.rs +++ b/build.rs @@ -23,7 +23,8 @@ fn main() { cfg.file(if msvc {"src/arch/i686.asm"} else {"src/arch/i686.S"}); cfg.define("X86", None); } else { - cfg.file("fallback.rs"); + println!("cargo:rustc-cfg=fallback"); + return; } cfg.include("src/arch").compile("libstacker.a"); diff --git a/src/arch/fallback.rs b/src/arch/fallback.rs index 2d1a59c..f464c71 100644 --- a/src/arch/fallback.rs +++ b/src/arch/fallback.rs @@ -10,4 +10,7 @@ unsafe extern fn __stacker_switch_stacks( _dataptr: &mut &mut FnMut(), ) { panic!("not supported") -} \ No newline at end of file +} + +#[no_mangle] +extern fn __stacker_black_box(_: *const u8) {} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b81a1e5..84c65df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,10 @@ extern crate libc; use std::cell::Cell; +#[cfg(fallback)] +#[path="arch/fallback.rs"] +mod fallback; + extern { fn __stacker_stack_pointer() -> usize; fn __stacker_switch_stacks(new_stack: usize, From 464c387951fd84315774ee7ffb1ac439cf24850a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 7 Nov 2018 08:30:13 +0100 Subject: [PATCH 09/12] Iniline-define the `fallback` module and use proper arguments to the various extern functions --- src/arch/fallback.rs | 16 ---------------- src/lib.rs | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 26 deletions(-) delete mode 100644 src/arch/fallback.rs diff --git a/src/arch/fallback.rs b/src/arch/fallback.rs deleted file mode 100644 index f464c71..0000000 --- a/src/arch/fallback.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[no_mangle] -extern fn __stacker_stack_pointer() -> usize { - panic!("not supported") -} - -#[no_mangle] -unsafe extern fn __stacker_switch_stacks( - _new_stack: usize, - _fnptr: unsafe fn(&mut &mut FnMut()), - _dataptr: &mut &mut FnMut(), -) { - panic!("not supported") -} - -#[no_mangle] -extern fn __stacker_black_box(_: *const u8) {} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 84c65df..eba8366 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,16 +36,37 @@ extern crate libc; use std::cell::Cell; #[cfg(fallback)] -#[path="arch/fallback.rs"] -mod fallback; - -extern { - fn __stacker_stack_pointer() -> usize; - fn __stacker_switch_stacks(new_stack: usize, - fnptr: *const u8, - dataptr: *mut u8); +mod intern { + pub fn __stacker_stack_pointer() -> usize { + panic!("not supported") + } + + pub unsafe fn __stacker_switch_stacks( + _new_stack: usize, + _fnptr: unsafe extern fn(&mut &mut FnMut()), + _dataptr: &mut &mut FnMut(), + ) { + panic!("not supported") + } + + #[no_mangle] + extern fn __stacker_black_box(_: *const u8) {} } +#[cfg(not(fallback))] +mod intern { + extern { + pub fn __stacker_stack_pointer() -> usize; + pub fn __stacker_switch_stacks( + new_stack: usize, + fnptr: unsafe extern fn(&mut &mut FnMut()), + dataptr: &mut &mut FnMut(), + ); + } +} + +use intern::*; + thread_local! { static STACK_LIMIT: Cell> = Cell::new(unsafe { guess_os_stack_limit() @@ -129,8 +150,8 @@ unsafe fn _grow_the_stack(stack_size: usize, old_limit: usize, mut f: &mut FnMut 0 }; __stacker_switch_stacks(stack.as_mut_ptr() as usize + stack_size - offset, - doit as usize as *const _, - &mut f as *mut &mut FnMut() as *mut u8); + doit, + &mut f); // Once we've returned reset bothe stack limits and then return value same // value the closure returned. From 30b32ea0514bac734539eccd4157e6d8684abcb6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 8 Nov 2018 16:40:59 +0100 Subject: [PATCH 10/12] Exponentially grow the stack and never throw away the largest stack even after popping it --- src/lib.rs | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index eba8366..2b18097 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ extern crate cfg_if; extern crate libc; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; #[cfg(fallback)] mod intern { @@ -128,13 +128,44 @@ fn grow_the_stack R>(stack_size: usize, f: F, remaining_stack_ } } +#[derive(Default)] +struct StackCache { + /// used to grow the stack exponentially + counter: usize, + /// memorize the largest ever allocated stack frame after popping it + largest: Option>, +} + +impl StackCache { + fn allocate(&mut self, stack_size: usize) -> Vec { + if let Some(largest) = self.largest.take() { + return largest; + } + let pow = 1 << self.counter; + self.counter += 1; + // Align to 16-bytes (see below for why) + let stack_size = (stack_size * pow + 15) / 16 * 16; + Vec::with_capacity(stack_size) + } + + fn cache(&mut self, v: Vec) { + if let Some(ref largest) = self.largest { + debug_assert!(largest.capacity() > v.capacity()); + } else { + self.largest = Some(v); + } + } +} + +thread_local! { + static STACK_CACHE: RefCell = RefCell::default(); +} + unsafe fn _grow_the_stack(stack_size: usize, old_limit: usize, mut f: &mut FnMut()) { - // Align to 16-bytes (see below for why) - let stack_size = (stack_size + 15) / 16 * 16; // Allocate some new stack for oureslves - let mut stack = Vec::::with_capacity(stack_size); - let new_limit = stack.as_ptr() as usize + 32 * 1024; + let mut stack = STACK_CACHE.with(|sc| sc.borrow_mut().allocate(stack_size)); + let new_limit = stack.as_ptr() as usize; // Prepare stack limits for the stack switch set_stack_limit(new_limit); @@ -149,7 +180,7 @@ unsafe fn _grow_the_stack(stack_size: usize, old_limit: usize, mut f: &mut FnMut } else { 0 }; - __stacker_switch_stacks(stack.as_mut_ptr() as usize + stack_size - offset, + __stacker_switch_stacks(stack.as_mut_ptr() as usize + stack.capacity() - offset, doit, &mut f); @@ -157,6 +188,10 @@ unsafe fn _grow_the_stack(stack_size: usize, old_limit: usize, mut f: &mut FnMut // value the closure returned. set_stack_limit(old_limit); + // Do not throw away this allocation. We might be on a stack boundary and end up + // pushing and popping stacks repeatedly + STACK_CACHE.with(|v| v.borrow_mut().cache(stack)); + unsafe extern fn doit(f: &mut &mut FnMut()) { f(); } From 735492cfe00cc78f8c1534fc92e29182755b7993 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 15 Nov 2018 09:24:05 +0100 Subject: [PATCH 11/12] Add non-linux-apple-win fallback --- build.rs | 3 +++ src/lib.rs | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 972feeb..cf35581 100644 --- a/build.rs +++ b/build.rs @@ -14,6 +14,9 @@ fn main() { cfg.define("APPLE", None); } else if target.contains("windows") { cfg.define("WINDOWS", None); + } else { + println!("cargo:rustc-cfg=fallback"); + return; } if target.starts_with("x86_64") { diff --git a/src/lib.rs b/src/lib.rs index 2b18097..8d8b6e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,10 @@ use std::cell::{Cell, RefCell}; #[cfg(fallback)] mod intern { - pub fn __stacker_stack_pointer() -> usize { + // needs to be unsafe to mirror the `extern` fn + // otherwise the callees either get `missing unsafe` errors + // or `unnecessary unsafe` warnings + pub unsafe fn __stacker_stack_pointer() -> usize { panic!("not supported") } From fadf7ddaacd09d316c6344a9f7f89d856bc3e65f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 15 Nov 2018 09:30:21 +0100 Subject: [PATCH 12/12] Also add a test for non-panicking recursion --- tests/simple.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/simple.rs diff --git a/tests/simple.rs b/tests/simple.rs new file mode 100644 index 0000000..4e4c46f --- /dev/null +++ b/tests/simple.rs @@ -0,0 +1,24 @@ +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 + 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 { + ensure_sufficient_stack(|| recurse(n - 1)); + } + drop(x); +} + +#[test] +fn foo() { + recurse(10000); +} \ No newline at end of file