@@ -51,7 +51,7 @@ mod imp {
5151 #[ cfg( all( target_os = "linux" , target_env = "gnu" ) ) ]
5252 use libc:: { mmap64, munmap} ;
5353 use libc:: { sigaction, sighandler_t, SA_ONSTACK , SA_SIGINFO , SIGBUS , SIG_DFL } ;
54- use libc:: { sigaltstack, SIGSTKSZ , SS_DISABLE } ;
54+ use libc:: { sigaltstack, SS_DISABLE } ;
5555 use libc:: { MAP_ANON , MAP_PRIVATE , PROT_NONE , PROT_READ , PROT_WRITE , SIGSEGV } ;
5656
5757 use crate :: sync:: atomic:: { AtomicBool , AtomicPtr , Ordering } ;
@@ -130,7 +130,7 @@ mod imp {
130130 drop_handler ( MAIN_ALTSTACK . load ( Ordering :: Relaxed ) ) ;
131131 }
132132
133- unsafe fn get_stackp ( ) -> * mut libc:: c_void {
133+ unsafe fn get_stack ( ) -> libc:: stack_t {
134134 // OpenBSD requires this flag for stack mapping
135135 // otherwise the said mapping will fail as a no-op on most systems
136136 // and has a different meaning on FreeBSD
@@ -148,20 +148,28 @@ mod imp {
148148 target_os = "dragonfly" ,
149149 ) ) ) ]
150150 let flags = MAP_PRIVATE | MAP_ANON ;
151- let stackp =
152- mmap64 ( ptr:: null_mut ( ) , SIGSTKSZ + page_size ( ) , PROT_READ | PROT_WRITE , flags, -1 , 0 ) ;
151+
152+ let sigstack_size = sigstack_size ( ) ;
153+ let page_size = page_size ( ) ;
154+
155+ let stackp = mmap64 (
156+ ptr:: null_mut ( ) ,
157+ sigstack_size + page_size,
158+ PROT_READ | PROT_WRITE ,
159+ flags,
160+ -1 ,
161+ 0 ,
162+ ) ;
153163 if stackp == MAP_FAILED {
154164 panic ! ( "failed to allocate an alternative stack: {}" , io:: Error :: last_os_error( ) ) ;
155165 }
156- let guard_result = libc:: mprotect ( stackp, page_size ( ) , PROT_NONE ) ;
166+ let guard_result = libc:: mprotect ( stackp, page_size, PROT_NONE ) ;
157167 if guard_result != 0 {
158168 panic ! ( "failed to set up alternative stack guard page: {}" , io:: Error :: last_os_error( ) ) ;
159169 }
160- stackp. add ( page_size ( ) )
161- }
170+ let stackp = stackp. add ( page_size) ;
162171
163- unsafe fn get_stack ( ) -> libc:: stack_t {
164- libc:: stack_t { ss_sp : get_stackp ( ) , ss_flags : 0 , ss_size : SIGSTKSZ }
172+ libc:: stack_t { ss_sp : stackp, ss_flags : 0 , ss_size : sigstack_size }
165173 }
166174
167175 pub unsafe fn make_handler ( ) -> Handler {
@@ -182,21 +190,41 @@ mod imp {
182190
183191 pub unsafe fn drop_handler ( data : * mut libc:: c_void ) {
184192 if !data. is_null ( ) {
193+ let sigstack_size = sigstack_size ( ) ;
194+ let page_size = page_size ( ) ;
185195 let stack = libc:: stack_t {
186196 ss_sp : ptr:: null_mut ( ) ,
187197 ss_flags : SS_DISABLE ,
188198 // Workaround for bug in macOS implementation of sigaltstack
189199 // UNIX2003 which returns ENOMEM when disabling a stack while
190200 // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
191201 // both ss_sp and ss_size should be ignored in this case.
192- ss_size : SIGSTKSZ ,
202+ ss_size : sigstack_size ,
193203 } ;
194204 sigaltstack ( & stack, ptr:: null_mut ( ) ) ;
195205 // We know from `get_stackp` that the alternate stack we installed is part of a mapping
196206 // that started one page earlier, so walk back a page and unmap from there.
197- munmap ( data. sub ( page_size ( ) ) , SIGSTKSZ + page_size ( ) ) ;
207+ munmap ( data. sub ( page_size) , sigstack_size + page_size) ;
198208 }
199209 }
210+
211+ /// Modern kernels on modern hardware can have dynamic signal stack sizes.
212+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
213+ fn sigstack_size ( ) -> usize {
214+ // FIXME: reuse const from libc when available?
215+ const AT_MINSIGSTKSZ : crate :: ffi:: c_ulong = 51 ;
216+ let dynamic_sigstksz = unsafe { libc:: getauxval ( AT_MINSIGSTKSZ ) } ;
217+ // If getauxval couldn't find the entry, it returns 0,
218+ // so take the higher of the "constant" and auxval.
219+ // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ
220+ libc:: SIGSTKSZ . max ( dynamic_sigstksz as _ )
221+ }
222+
223+ /// Not all OS support hardware where this is needed.
224+ #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
225+ fn sigstack_size ( ) -> usize {
226+ libc:: SIGSTKSZ
227+ }
200228}
201229
202230#[ cfg( not( any(
0 commit comments