@@ -87,13 +87,18 @@ mod imp {
8787 // out many large systems and all implementations allow returning from a
8888 // signal handler to work. For a more detailed explanation see the
8989 // 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) ]
9094 unsafe extern "C" fn signal_handler (
9195 signum : libc:: c_int ,
9296 info : * mut libc:: siginfo_t ,
9397 _data : * mut libc:: c_void ,
9498 ) {
9599 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 ( ) } ;
97102
98103 // If the faulting address is within the guard page, then we print a
99104 // message saying so and abort.
@@ -105,9 +110,11 @@ mod imp {
105110 rtabort ! ( "stack overflow" ) ;
106111 } else {
107112 // 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 ( ) } ;
109115 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 ( ) ) } ;
111118
112119 // See comment above for why this function returns.
113120 }
@@ -117,32 +124,45 @@ mod imp {
117124 static MAIN_ALTSTACK : AtomicPtr < libc:: c_void > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
118125 static NEED_ALTSTACK : AtomicBool = AtomicBool :: new ( false ) ;
119126
127+ /// # Safety
128+ /// Must be called only once
129+ #[ forbid( unsafe_op_in_unsafe_fn) ]
120130 pub unsafe fn init ( ) {
121131 PAGE_SIZE . store ( os:: page_size ( ) , Ordering :: Relaxed ) ;
122132
123133 // 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 ) } ;
125135 GUARD . set ( ( guard. start , guard. end ) ) ;
126136
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 ( ) } ;
128139 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) } ;
130142 // Configure our signal handler if one is not already set.
131143 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+ }
132151 action. sa_flags = SA_SIGINFO | SA_ONSTACK ;
133152 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 ( ) ) } ;
136155 }
137156 }
138-
139- let handler = make_handler ( true ) ;
140- MAIN_ALTSTACK . store ( handler. data , Ordering :: Relaxed ) ;
141- mem:: forget ( handler) ;
142157 }
143158
159+ /// # Safety
160+ /// Must be called only once
161+ #[ forbid( unsafe_op_in_unsafe_fn) ]
144162 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 ) ) } ;
146166 }
147167
148168 unsafe fn get_stack ( ) -> libc:: stack_t {
@@ -187,34 +207,48 @@ mod imp {
187207 libc:: stack_t { ss_sp : stackp, ss_flags : 0 , ss_size : sigstack_size }
188208 }
189209
210+ /// # Safety
211+ /// Mutates the alternate signal stack
212+ #[ forbid( unsafe_op_in_unsafe_fn) ]
190213 pub unsafe fn make_handler ( main_thread : bool ) -> Handler {
191- if !NEED_ALTSTACK . load ( Ordering :: Relaxed ) {
214+ if !NEED_ALTSTACK . load ( Ordering :: Acquire ) {
192215 return Handler :: null ( ) ;
193216 }
194217
195218 if !main_thread {
196219 // 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 ) ;
198221 GUARD . set ( ( guard. start , guard. end ) ) ;
199222 }
200223
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) } ;
203228 // Configure alternate signal stack, if one is not already set.
204229 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+ }
207235 Handler { data : stack. ss_sp as * mut libc:: c_void }
208236 } else {
209237 Handler :: null ( )
210238 }
211239 }
212240
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) ]
213247 pub unsafe fn drop_handler ( data : * mut libc:: c_void ) {
214248 if !data. is_null ( ) {
215249 let sigstack_size = sigstack_size ( ) ;
216250 let page_size = PAGE_SIZE . load ( Ordering :: Relaxed ) ;
217- let stack = libc:: stack_t {
251+ let disabling_stack = libc:: stack_t {
218252 ss_sp : ptr:: null_mut ( ) ,
219253 ss_flags : SS_DISABLE ,
220254 // Workaround for bug in macOS implementation of sigaltstack
@@ -223,10 +257,11 @@ mod imp {
223257 // both ss_sp and ss_size should be ignored in this case.
224258 ss_size : sigstack_size,
225259 } ;
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) } ;
230265 }
231266 }
232267
@@ -455,6 +490,7 @@ mod imp {
455490 }
456491
457492 #[ cfg( any( target_os = "macos" , target_os = "openbsd" , target_os = "solaris" ) ) ]
493+ // FIXME: I am probably not unsafe.
458494 unsafe fn current_guard ( ) -> Option < Range < usize > > {
459495 let stackptr = get_stack_start ( ) ?;
460496 let stackaddr = stackptr. addr ( ) ;
@@ -469,6 +505,7 @@ mod imp {
469505 target_os = "netbsd" ,
470506 target_os = "l4re"
471507 ) ) ]
508+ // FIXME: I am probably not unsafe.
472509 unsafe fn current_guard ( ) -> Option < Range < usize > > {
473510 let mut ret = None ;
474511 let mut attr: libc:: pthread_attr_t = crate :: mem:: zeroed ( ) ;
0 commit comments