@@ -51,7 +51,7 @@ mod imp {
51
51
#[ cfg( all( target_os = "linux" , target_env = "gnu" ) ) ]
52
52
use libc:: { mmap64, munmap} ;
53
53
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 } ;
55
55
use libc:: { MAP_ANON , MAP_PRIVATE , PROT_NONE , PROT_READ , PROT_WRITE , SIGSEGV } ;
56
56
57
57
use crate :: sync:: atomic:: { AtomicBool , AtomicPtr , Ordering } ;
@@ -130,7 +130,7 @@ mod imp {
130
130
drop_handler ( MAIN_ALTSTACK . load ( Ordering :: Relaxed ) ) ;
131
131
}
132
132
133
- unsafe fn get_stackp ( ) -> * mut libc:: c_void {
133
+ unsafe fn get_stack ( ) -> libc:: stack_t {
134
134
// OpenBSD requires this flag for stack mapping
135
135
// otherwise the said mapping will fail as a no-op on most systems
136
136
// and has a different meaning on FreeBSD
@@ -148,20 +148,28 @@ mod imp {
148
148
target_os = "dragonfly" ,
149
149
) ) ) ]
150
150
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
+ ) ;
153
163
if stackp == MAP_FAILED {
154
164
panic ! ( "failed to allocate an alternative stack: {}" , io:: Error :: last_os_error( ) ) ;
155
165
}
156
- let guard_result = libc:: mprotect ( stackp, page_size ( ) , PROT_NONE ) ;
166
+ let guard_result = libc:: mprotect ( stackp, page_size, PROT_NONE ) ;
157
167
if guard_result != 0 {
158
168
panic ! ( "failed to set up alternative stack guard page: {}" , io:: Error :: last_os_error( ) ) ;
159
169
}
160
- stackp. add ( page_size ( ) )
161
- }
170
+ let stackp = stackp. add ( page_size) ;
162
171
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 }
165
173
}
166
174
167
175
pub unsafe fn make_handler ( ) -> Handler {
@@ -182,21 +190,41 @@ mod imp {
182
190
183
191
pub unsafe fn drop_handler ( data : * mut libc:: c_void ) {
184
192
if !data. is_null ( ) {
193
+ let sigstack_size = sigstack_size ( ) ;
194
+ let page_size = page_size ( ) ;
185
195
let stack = libc:: stack_t {
186
196
ss_sp : ptr:: null_mut ( ) ,
187
197
ss_flags : SS_DISABLE ,
188
198
// Workaround for bug in macOS implementation of sigaltstack
189
199
// UNIX2003 which returns ENOMEM when disabling a stack while
190
200
// passing ss_size smaller than MINSIGSTKSZ. According to POSIX
191
201
// both ss_sp and ss_size should be ignored in this case.
192
- ss_size : SIGSTKSZ ,
202
+ ss_size : sigstack_size ,
193
203
} ;
194
204
sigaltstack ( & stack, ptr:: null_mut ( ) ) ;
195
205
// We know from `get_stackp` that the alternate stack we installed is part of a mapping
196
206
// 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) ;
198
208
}
199
209
}
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
+ }
200
228
}
201
229
202
230
#[ cfg( not( any(
0 commit comments