@@ -209,6 +209,7 @@ pub mod guard {
209209 pub type Guard = Range < usize > ;
210210 pub unsafe fn current ( ) -> Option < Guard > { None }
211211 pub unsafe fn init ( ) -> Option < Guard > { None }
212+ pub unsafe fn deinit ( ) { }
212213}
213214
214215
@@ -222,8 +223,8 @@ pub mod guard {
222223#[ cfg_attr( test, allow( dead_code) ) ]
223224pub mod guard {
224225 use libc;
225- use libc:: mmap;
226- use libc:: { PROT_NONE , MAP_PRIVATE , MAP_ANON , MAP_FAILED , MAP_FIXED } ;
226+ use libc:: { mmap, mprotect } ;
227+ use libc:: { PROT_NONE , PROT_READ , PROT_WRITE , MAP_PRIVATE , MAP_ANON , MAP_FAILED , MAP_FIXED } ;
227228 use ops:: Range ;
228229 use sys:: os;
229230
@@ -284,10 +285,10 @@ pub mod guard {
284285 ret
285286 }
286287
287- pub unsafe fn init ( ) -> Option < Guard > {
288- PAGE_SIZE = os :: page_size ( ) ;
289-
290- let mut stackaddr = get_stack_start ( ) ?;
288+ // Precondition: PAGE_SIZE is initialized.
289+ unsafe fn get_stack_start_aligned ( ) -> Option < * mut libc :: c_void > {
290+ assert ! ( PAGE_SIZE != 0 ) ;
291+ let stackaddr = get_stack_start ( ) ?;
291292
292293 // Ensure stackaddr is page aligned! A parent process might
293294 // have reset RLIMIT_STACK to be non-page aligned. The
@@ -296,10 +297,17 @@ pub mod guard {
296297 // page-aligned, calculate the fix such that stackaddr <
297298 // new_page_aligned_stackaddr < stackaddr + stacksize
298299 let remainder = ( stackaddr as usize ) % PAGE_SIZE ;
299- if remainder != 0 {
300- stackaddr = ( ( stackaddr as usize ) + PAGE_SIZE - remainder)
301- as * mut libc:: c_void ;
302- }
300+ Some ( if remainder == 0 {
301+ stackaddr
302+ } else {
303+ ( ( stackaddr as usize ) + PAGE_SIZE - remainder) as * mut libc:: c_void
304+ } )
305+ }
306+
307+ pub unsafe fn init ( ) -> Option < Guard > {
308+ PAGE_SIZE = os:: page_size ( ) ;
309+
310+ let stackaddr = get_stack_start_aligned ( ) ?;
303311
304312 if cfg ! ( target_os = "linux" ) {
305313 // Linux doesn't allocate the whole stack right away, and
@@ -336,6 +344,26 @@ pub mod guard {
336344 }
337345 }
338346
347+ pub unsafe fn deinit ( ) {
348+ if !cfg ! ( target_os = "linux" ) {
349+ if let Some ( stackaddr) = get_stack_start_aligned ( ) {
350+ // Remove the protection on the guard page.
351+ // FIXME: we cannot unmap the page, because when we mmap()
352+ // above it may be already mapped by the OS, which we can't
353+ // detect from mmap()'s return value. If we unmap this page,
354+ // it will lead to failure growing stack size on platforms like
355+ // macOS. Instead, just restore the page to a writable state.
356+ // This ain't Linux, so we probably don't need to care about
357+ // execstack.
358+ let result = mprotect ( stackaddr, PAGE_SIZE , PROT_READ | PROT_WRITE ) ;
359+
360+ if result != 0 {
361+ panic ! ( "unable to reset the guard page" ) ;
362+ }
363+ }
364+ }
365+ }
366+
339367 #[ cfg( any( target_os = "macos" ,
340368 target_os = "bitrig" ,
341369 target_os = "openbsd" ,
0 commit comments