@@ -87,13 +87,18 @@ mod imp {
87
87
// out many large systems and all implementations allow returning from a
88
88
// signal handler to work. For a more detailed explanation see the
89
89
// comments on #26458.
90
+ /// SIGSEGV/SIGBUS entry point
91
+ /// # Safety
92
+ /// Rust doesn't call this, it *gets called*.
93
+ #[ forbid( unsafe_op_in_unsafe_fn) ]
90
94
unsafe extern "C" fn signal_handler (
91
95
signum : libc:: c_int ,
92
96
info : * mut libc:: siginfo_t ,
93
97
_data : * mut libc:: c_void ,
94
98
) {
95
99
let ( start, end) = GUARD . get ( ) ;
96
- let addr = ( * info) . si_addr ( ) as usize ;
100
+ // SAFETY: this pointer is provided by the system and will always point to a valid `siginfo_t`.
101
+ let addr = unsafe { ( * info) . si_addr ( ) . addr ( ) } ;
97
102
98
103
// If the faulting address is within the guard page, then we print a
99
104
// message saying so and abort.
@@ -105,9 +110,11 @@ mod imp {
105
110
rtabort ! ( "stack overflow" ) ;
106
111
} else {
107
112
// Unregister ourselves by reverting back to the default behavior.
108
- let mut action: sigaction = mem:: zeroed ( ) ;
113
+ // SAFETY: assuming all platforms define struct sigaction as "zero-initializable"
114
+ let mut action: sigaction = unsafe { mem:: zeroed ( ) } ;
109
115
action. sa_sigaction = SIG_DFL ;
110
- sigaction ( signum, & action, ptr:: null_mut ( ) ) ;
116
+ // SAFETY: pray this is a well-behaved POSIX implementation of fn sigaction
117
+ unsafe { sigaction ( signum, & action, ptr:: null_mut ( ) ) } ;
111
118
112
119
// See comment above for why this function returns.
113
120
}
@@ -117,32 +124,45 @@ mod imp {
117
124
static MAIN_ALTSTACK : AtomicPtr < libc:: c_void > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
118
125
static NEED_ALTSTACK : AtomicBool = AtomicBool :: new ( false ) ;
119
126
127
+ /// # Safety
128
+ /// Must be called only once
129
+ #[ forbid( unsafe_op_in_unsafe_fn) ]
120
130
pub unsafe fn init ( ) {
121
131
PAGE_SIZE . store ( os:: page_size ( ) , Ordering :: Relaxed ) ;
122
132
123
133
// Always write to GUARD to ensure the TLS variable is allocated.
124
- let guard = install_main_guard ( ) . unwrap_or ( 0 ..0 ) ;
134
+ let guard = unsafe { install_main_guard ( ) . unwrap_or ( 0 ..0 ) } ;
125
135
GUARD . set ( ( guard. start , guard. end ) ) ;
126
136
127
- let mut action: sigaction = mem:: zeroed ( ) ;
137
+ // SAFETY: assuming all platforms define struct sigaction as "zero-initializable"
138
+ let mut action: sigaction = unsafe { mem:: zeroed ( ) } ;
128
139
for & signal in & [ SIGSEGV , SIGBUS ] {
129
- sigaction ( signal, ptr:: null_mut ( ) , & mut action) ;
140
+ // SAFETY: just fetches the current signal handler into action
141
+ unsafe { sigaction ( signal, ptr:: null_mut ( ) , & mut action) } ;
130
142
// Configure our signal handler if one is not already set.
131
143
if action. sa_sigaction == SIG_DFL {
144
+ if !NEED_ALTSTACK . load ( Ordering :: Relaxed ) {
145
+ // haven't set up our sigaltstack yet
146
+ NEED_ALTSTACK . store ( true , Ordering :: Release ) ;
147
+ let handler = unsafe { make_handler ( true ) } ;
148
+ MAIN_ALTSTACK . store ( handler. data , Ordering :: Relaxed ) ;
149
+ mem:: forget ( handler) ;
150
+ }
132
151
action. sa_flags = SA_SIGINFO | SA_ONSTACK ;
133
152
action. sa_sigaction = signal_handler as sighandler_t ;
134
- sigaction ( signal , & action , ptr :: null_mut ( ) ) ;
135
- NEED_ALTSTACK . store ( true , Ordering :: Relaxed ) ;
153
+ // SAFETY: only overriding signals if the default is set
154
+ unsafe { sigaction ( signal , & action , ptr :: null_mut ( ) ) } ;
136
155
}
137
156
}
138
-
139
- let handler = make_handler ( true ) ;
140
- MAIN_ALTSTACK . store ( handler. data , Ordering :: Relaxed ) ;
141
- mem:: forget ( handler) ;
142
157
}
143
158
159
+ /// # Safety
160
+ /// Must be called only once
161
+ #[ forbid( unsafe_op_in_unsafe_fn) ]
144
162
pub unsafe fn cleanup ( ) {
145
- drop_handler ( MAIN_ALTSTACK . load ( Ordering :: Relaxed ) ) ;
163
+ // FIXME: I probably cause more bugs than I'm worth!
164
+ // see https://github.com/rust-lang/rust/issues/111272
165
+ unsafe { drop_handler ( MAIN_ALTSTACK . load ( Ordering :: Relaxed ) ) } ;
146
166
}
147
167
148
168
unsafe fn get_stack ( ) -> libc:: stack_t {
@@ -187,34 +207,48 @@ mod imp {
187
207
libc:: stack_t { ss_sp : stackp, ss_flags : 0 , ss_size : sigstack_size }
188
208
}
189
209
210
+ /// # Safety
211
+ /// Mutates the alternate signal stack
212
+ #[ forbid( unsafe_op_in_unsafe_fn) ]
190
213
pub unsafe fn make_handler ( main_thread : bool ) -> Handler {
191
- if !NEED_ALTSTACK . load ( Ordering :: Relaxed ) {
214
+ if !NEED_ALTSTACK . load ( Ordering :: Acquire ) {
192
215
return Handler :: null ( ) ;
193
216
}
194
217
195
218
if !main_thread {
196
219
// Always write to GUARD to ensure the TLS variable is allocated.
197
- let guard = current_guard ( ) . unwrap_or ( 0 ..0 ) ;
220
+ let guard = unsafe { current_guard ( ) } . unwrap_or ( 0 ..0 ) ;
198
221
GUARD . set ( ( guard. start , guard. end ) ) ;
199
222
}
200
223
201
- let mut stack = mem:: zeroed ( ) ;
202
- sigaltstack ( ptr:: null ( ) , & mut stack) ;
224
+ // SAFETY: assuming stack_t is zero-initializable
225
+ let mut stack = unsafe { mem:: zeroed ( ) } ;
226
+ // SAFETY: reads current stack_t into stack
227
+ unsafe { sigaltstack ( ptr:: null ( ) , & mut stack) } ;
203
228
// Configure alternate signal stack, if one is not already set.
204
229
if stack. ss_flags & SS_DISABLE != 0 {
205
- stack = get_stack ( ) ;
206
- sigaltstack ( & stack, ptr:: null_mut ( ) ) ;
230
+ // SAFETY: We warned our caller this would happen!
231
+ unsafe {
232
+ stack = get_stack ( ) ;
233
+ sigaltstack ( & stack, ptr:: null_mut ( ) ) ;
234
+ }
207
235
Handler { data : stack. ss_sp as * mut libc:: c_void }
208
236
} else {
209
237
Handler :: null ( )
210
238
}
211
239
}
212
240
241
+ /// # Safety
242
+ /// Must be called
243
+ /// - only with our handler or nullptr
244
+ /// - only when done with our altstack
245
+ /// This disables the alternate signal stack!
246
+ #[ forbid( unsafe_op_in_unsafe_fn) ]
213
247
pub unsafe fn drop_handler ( data : * mut libc:: c_void ) {
214
248
if !data. is_null ( ) {
215
249
let sigstack_size = sigstack_size ( ) ;
216
250
let page_size = PAGE_SIZE . load ( Ordering :: Relaxed ) ;
217
- let stack = libc:: stack_t {
251
+ let disabling_stack = libc:: stack_t {
218
252
ss_sp : ptr:: null_mut ( ) ,
219
253
ss_flags : SS_DISABLE ,
220
254
// Workaround for bug in macOS implementation of sigaltstack
@@ -223,10 +257,11 @@ mod imp {
223
257
// both ss_sp and ss_size should be ignored in this case.
224
258
ss_size : sigstack_size,
225
259
} ;
226
- sigaltstack ( & stack, ptr:: null_mut ( ) ) ;
227
- // We know from `get_stackp` that the alternate stack we installed is part of a mapping
228
- // that started one page earlier, so walk back a page and unmap from there.
229
- munmap ( data. sub ( page_size) , sigstack_size + page_size) ;
260
+ // SAFETY: we warned the caller this disables the alternate signal stack!
261
+ unsafe { sigaltstack ( & disabling_stack, ptr:: null_mut ( ) ) } ;
262
+ // SAFETY: We know from `get_stackp` that the alternate stack we installed is part of
263
+ // a mapping that started one page earlier, so walk back a page and unmap from there.
264
+ unsafe { munmap ( data. sub ( page_size) , sigstack_size + page_size) } ;
230
265
}
231
266
}
232
267
@@ -455,6 +490,7 @@ mod imp {
455
490
}
456
491
457
492
#[ cfg( any( target_os = "macos" , target_os = "openbsd" , target_os = "solaris" ) ) ]
493
+ // FIXME: I am probably not unsafe.
458
494
unsafe fn current_guard ( ) -> Option < Range < usize > > {
459
495
let stackptr = get_stack_start ( ) ?;
460
496
let stackaddr = stackptr. addr ( ) ;
@@ -469,6 +505,7 @@ mod imp {
469
505
target_os = "netbsd" ,
470
506
target_os = "l4re"
471
507
) ) ]
508
+ // FIXME: I am probably not unsafe.
472
509
unsafe fn current_guard ( ) -> Option < Range < usize > > {
473
510
let mut ret = None ;
474
511
let mut attr: libc:: pthread_attr_t = crate :: mem:: zeroed ( ) ;
0 commit comments