stacker/
mmap_stack_restore_guard.rs
1use crate::{get_stack_limit, set_stack_limit};
2
3pub struct StackRestoreGuard {
4 mapping: *mut u8,
5 size_with_guard: usize,
6 page_size: usize,
7 old_stack_limit: Option<usize>,
8}
9
10impl StackRestoreGuard {
11 pub fn new(requested_size: usize) -> StackRestoreGuard {
12 let page_size = page_size();
17 let requested_pages = requested_size
18 .checked_add(page_size - 1)
19 .expect("unreasonably large stack requested")
20 / page_size;
21 let page_count_with_guard = std::cmp::max(1, requested_pages) + 2;
22 let size_with_guard = page_count_with_guard
23 .checked_mul(page_size)
24 .expect("unreasonably large stack requested");
25
26 unsafe {
27 let new_stack = libc::mmap(
28 std::ptr::null_mut(),
29 size_with_guard,
30 libc::PROT_NONE,
31 libc::MAP_PRIVATE | libc::MAP_ANON,
32 -1, 0,
34 );
35 assert_ne!(
36 new_stack,
37 libc::MAP_FAILED,
38 "mmap failed to allocate stack: {}",
39 std::io::Error::last_os_error()
40 );
41 let guard = StackRestoreGuard {
42 mapping: new_stack as *mut u8,
43 page_size,
44 size_with_guard,
45 old_stack_limit: get_stack_limit(),
46 };
47 let above_guard_page = new_stack.add(page_size);
50 #[cfg(not(target_os = "openbsd"))]
51 let result = libc::mprotect(
52 above_guard_page,
53 size_with_guard - page_size,
54 libc::PROT_READ | libc::PROT_WRITE,
55 );
56 #[cfg(target_os = "openbsd")]
57 let result = if libc::mmap(
58 above_guard_page,
59 size_with_guard - page_size,
60 libc::PROT_READ | libc::PROT_WRITE,
61 libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_STACK,
62 -1,
63 0,
64 ) == above_guard_page
65 {
66 0
67 } else {
68 -1
69 };
70 assert_ne!(
71 result,
72 -1,
73 "mprotect/mmap failed: {}",
74 std::io::Error::last_os_error()
75 );
76 guard
77 }
78 }
79
80 pub fn stack_area(&self) -> (*mut u8, usize) {
82 unsafe {
83 (
84 self.mapping.add(self.page_size),
85 self.size_with_guard - self.page_size,
86 )
87 }
88 }
89}
90
91impl Drop for StackRestoreGuard {
92 fn drop(&mut self) {
93 unsafe {
94 libc::munmap(self.mapping as *mut std::ffi::c_void, self.size_with_guard);
97 }
98 set_stack_limit(self.old_stack_limit);
99 }
100}
101
102fn page_size() -> usize {
103 unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as usize }
105}