Skip to content

Commit b2a8e15

Browse files
committed
Don't rely on morestack to guess the stack limit
1 parent 3c7372b commit b2a8e15

File tree

2 files changed

+74
-28
lines changed

2 files changed

+74
-28
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,9 @@ name = "stacker"
1818
doctest = false
1919
test = false
2020

21+
[dependencies]
22+
cfg-if = "0.1"
23+
libc = "0.1"
24+
2125
[build-dependencies]
2226
gcc = "0.3.10"

src/lib.rs

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
2525
#![allow(improper_ctypes)]
2626

27+
#[macro_use]
28+
extern crate cfg_if;
29+
extern crate libc;
30+
2731
use std::cell::Cell;
2832

2933
extern {
@@ -36,7 +40,9 @@ extern {
3640
}
3741

3842
thread_local! {
39-
static STACK_LIMIT: Cell<usize> = Cell::new(guess_os_morestack_stack_limit())
43+
static STACK_LIMIT: Cell<usize> = Cell::new(unsafe {
44+
guess_os_morestack_stack_limit()
45+
})
4046
}
4147

4248
fn get_stack_limit() -> usize {
@@ -112,33 +118,69 @@ unsafe fn grow_the_stack<R, F: FnOnce() -> R>(stack_size: usize, f: F) -> R {
112118
}
113119
}
114120

115-
#[cfg(unix)]
116-
fn guess_os_morestack_stack_limit() -> usize {
117-
unsafe {
118-
__stacker_morestack_stack_limit()
119-
}
120-
}
121+
cfg_if! {
122+
if #[cfg(windows)] {
123+
// See this for where all this logic is coming from.
124+
//
125+
// https://github.com/adobe/webkit/blob/0441266/Source/WTF/wtf
126+
// /StackBounds.cpp
127+
unsafe fn guess_os_morestack_stack_limit() -> usize {
128+
#[cfg(target_pointer_width = "32")]
129+
extern {
130+
#[link_name = "__stacker_get_tib_32"]
131+
fn get_tib_address() -> *const usize;
132+
}
133+
#[cfg(target_pointer_width = "64")]
134+
extern "system" {
135+
#[link_name = "NtCurrentTeb"]
136+
fn get_tib_address() -> *const usize;
137+
}
138+
// https://en.wikipedia.org/wiki/Win32_Thread_Information_Block for
139+
// the struct layout of the 32-bit TIB. It looks like the struct
140+
// layout of the 64-bit TIB is also the same for getting the stack
141+
// limit: http://doxygen.reactos.org/d3/db0/structNT__TIB64.html
142+
*get_tib_address().offset(2)
143+
}
144+
} else if #[cfg(target_os = "linux")] {
145+
use libc::{pthread_attr_t, c_int, size_t, c_void, pthread_t};
146+
use std::mem;
147+
148+
unsafe fn guess_os_morestack_stack_limit() -> usize {
149+
let mut attr: libc::pthread_attr_t = mem::zeroed();
150+
assert_eq!(pthread_attr_init(&mut attr), 0);
151+
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
152+
let mut stackaddr = 0 as *mut _;
153+
let mut stacksize = 0;
154+
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr,
155+
&mut stacksize), 0);
156+
assert_eq!(pthread_attr_destroy(&mut attr), 0);
157+
stackaddr as usize
158+
}
121159

122-
// See this for where all this logic is coming from.
123-
//
124-
// https://github.com/adobe/webkit/blob/0441266/Source/WTF/wtf/StackBounds.cpp
125-
#[cfg(windows)]
126-
fn guess_os_morestack_stack_limit() -> usize {
127-
#[cfg(target_pointer_width = "32")]
128-
extern {
129-
#[link_name = "__stacker_get_tib_32"]
130-
fn get_tib_address() -> *const usize;
131-
}
132-
#[cfg(target_pointer_width = "64")]
133-
extern "system" {
134-
#[link_name = "NtCurrentTeb"]
135-
fn get_tib_address() -> *const usize;
136-
}
137-
unsafe {
138-
// See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block for
139-
// the struct layout of the 32-bit TIB. It looks like the struct layout
140-
// of the 64-bit TIB is also the same for getting the stack limit:
141-
// http://doxygen.reactos.org/d3/db0/structNT__TIB64.html
142-
*get_tib_address().offset(2)
160+
extern {
161+
fn pthread_self() -> pthread_t;
162+
fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
163+
fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> c_int;
164+
fn pthread_attr_getstack(attr: *const pthread_attr_t,
165+
stackaddr: *mut *mut c_void,
166+
stacksize: *mut size_t) -> c_int;
167+
fn pthread_getattr_np(native: pthread_t,
168+
attr: *mut pthread_attr_t) -> c_int;
169+
}
170+
} else if #[cfg(target_os = "macos")] {
171+
use libc::{c_void, pthread_t};
172+
173+
unsafe fn guess_os_morestack_stack_limit() -> usize {
174+
pthread_get_stackaddr_np(pthread_self()) as usize
175+
}
176+
177+
extern {
178+
fn pthread_self() -> pthread_t;
179+
fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut c_void;
180+
}
181+
} else {
182+
unsafe fn guess_os_morestack_stack_limit() -> usize {
183+
panic!("cannot guess the stack limit on this platform");
184+
}
143185
}
144186
}

0 commit comments

Comments
 (0)