@@ -25,15 +25,36 @@ impl Drop for Handler {
2525    } 
2626} 
2727
28- #[ cfg( any(  
29-     target_os = "linux" ,  
30-     target_os = "freebsd" ,  
31-     target_os = "hurd" ,  
32-     target_os = "macos" ,  
33-     target_os = "netbsd" ,  
34-     target_os = "openbsd" ,  
35-     target_os = "solaris" ,  
36-     target_os = "illumos" ,  
28+ #[ cfg( all(  
29+     not( miri) ,  
30+     any(  
31+         target_os = "linux" ,  
32+         target_os = "freebsd" ,  
33+         target_os = "hurd" ,  
34+         target_os = "macos" ,  
35+         target_os = "netbsd" ,  
36+         target_os = "openbsd" ,  
37+         target_os = "solaris" ,  
38+         target_os = "illumos" ,  
39+     ) ,  
40+ ) ) ] 
41+ mod  thread_info; 
42+ 
43+ // miri doesn't model signals nor stack overflows and this code has some 
44+ // synchronization properties that we don't want to expose to user code, 
45+ // hence we disable it on miri. 
46+ #[ cfg( all(  
47+     not( miri) ,  
48+     any(  
49+         target_os = "linux" ,  
50+         target_os = "freebsd" ,  
51+         target_os = "hurd" ,  
52+         target_os = "macos" ,  
53+         target_os = "netbsd" ,  
54+         target_os = "openbsd" ,  
55+         target_os = "solaris" ,  
56+         target_os = "illumos" ,  
57+     )  
3758) ) ] 
3859mod  imp { 
3960    use  libc:: { 
@@ -46,22 +67,13 @@ mod imp {
4667    use  libc:: { mmap64,  mprotect,  munmap} ; 
4768
4869    use  super :: Handler ; 
49-     use  crate :: cell :: Cell ; 
70+     use  super :: thread_info :: { delete_current_info ,  set_current_info ,  with_current_info } ; 
5071    use  crate :: ops:: Range ; 
5172    use  crate :: sync:: OnceLock ; 
5273    use  crate :: sync:: atomic:: { Atomic ,  AtomicBool ,  AtomicPtr ,  AtomicUsize ,  Ordering } ; 
5374    use  crate :: sys:: pal:: unix:: os; 
54-     use  crate :: { io,  mem,  ptr,  thread} ; 
55- 
56-     // We use a TLS variable to store the address of the guard page. While TLS 
57-     // variables are not guaranteed to be signal-safe, this works out in practice 
58-     // since we make sure to write to the variable before the signal stack is 
59-     // installed, thereby ensuring that the variable is always allocated when 
60-     // the signal handler is called. 
61-     thread_local !  { 
62-         // FIXME: use `Range` once that implements `Copy`. 
63-         static  GUARD :  Cell <( usize ,  usize ) > = const  {  Cell :: new( ( 0 ,  0 ) )  } ; 
64-     } 
75+     use  crate :: thread:: with_current_name; 
76+     use  crate :: { io,  mem,  panic,  ptr} ; 
6577
6678    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages 
6779    // (unmapped pages) at the end of every thread's stack, so if a thread ends 
@@ -93,29 +105,35 @@ mod imp {
93105        info :  * mut  libc:: siginfo_t , 
94106        _data :  * mut  libc:: c_void , 
95107    )  { 
96-         let  ( start,  end)  = GUARD . get ( ) ; 
97108        // SAFETY: this pointer is provided by the system and will always point to a valid `siginfo_t`. 
98-         let  addr = unsafe  {  ( * info) . si_addr ( ) . addr ( )  } ; 
109+         let  fault_addr = unsafe  {  ( * info) . si_addr ( ) . addr ( )  } ; 
110+ 
111+         // `with_current_info` expects that the process aborts after it is 
112+         // called. If the signal was not caused by a memory access, this might 
113+         // not be true. We detect this by noticing that the `si_addr` field is 
114+         // zero if the signal is synthetic. 
115+         if  fault_addr != 0  { 
116+             with_current_info ( |thread_info| { 
117+                 // If the faulting address is within the guard page, then we print a 
118+                 // message saying so and abort. 
119+                 if  let  Some ( thread_info)  = thread_info
120+                     && thread_info. guard_page_range . contains ( & fault_addr) 
121+                 { 
122+                     let  name = thread_info. thread_name . as_deref ( ) . unwrap_or ( "<unknown>" ) ; 
123+                     rtprintpanic ! ( "\n thread '{name}' has overflowed its stack\n " ) ; 
124+                     rtabort ! ( "stack overflow" ) ; 
125+                 } 
126+             } ) 
127+         } 
99128
100-         // If the faulting address is within the guard page, then we print a 
101-         // message saying so and abort. 
102-         if  start <= addr && addr < end { 
103-             thread:: with_current_name ( |name| { 
104-                 let  name = name. unwrap_or ( "<unknown>" ) ; 
105-                 rtprintpanic ! ( "\n thread '{name}' has overflowed its stack\n " ) ; 
106-             } ) ; 
129+         // Unregister ourselves by reverting back to the default behavior. 
130+         // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" 
131+         let  mut  action:  sigaction  = unsafe  {  mem:: zeroed ( )  } ; 
132+         action. sa_sigaction  = SIG_DFL ; 
133+         // SAFETY: pray this is a well-behaved POSIX implementation of fn sigaction 
134+         unsafe  {  sigaction ( signum,  & action,  ptr:: null_mut ( ) )  } ; 
107135
108-             rtabort ! ( "stack overflow" ) ; 
109-         }  else  { 
110-             // Unregister ourselves by reverting back to the default behavior. 
111-             // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" 
112-             let  mut  action:  sigaction  = unsafe  {  mem:: zeroed ( )  } ; 
113-             action. sa_sigaction  = SIG_DFL ; 
114-             // SAFETY: pray this is a well-behaved POSIX implementation of fn sigaction 
115-             unsafe  {  sigaction ( signum,  & action,  ptr:: null_mut ( ) )  } ; 
116- 
117-             // See comment above for why this function returns. 
118-         } 
136+         // See comment above for why this function returns. 
119137    } 
120138
121139    static  PAGE_SIZE :  Atomic < usize >  = AtomicUsize :: new ( 0 ) ; 
@@ -128,9 +146,7 @@ mod imp {
128146    pub  unsafe  fn  init ( )  { 
129147        PAGE_SIZE . store ( os:: page_size ( ) ,  Ordering :: Relaxed ) ; 
130148
131-         // Always write to GUARD to ensure the TLS variable is allocated. 
132-         let  guard = unsafe  {  install_main_guard ( ) . unwrap_or ( 0 ..0 )  } ; 
133-         GUARD . set ( ( guard. start ,  guard. end ) ) ; 
149+         let  mut  guard_page_range = unsafe  {  install_main_guard ( )  } ; 
134150
135151        // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" 
136152        let  mut  action:  sigaction  = unsafe  {  mem:: zeroed ( )  } ; 
@@ -145,7 +161,13 @@ mod imp {
145161                    let  handler = unsafe  {  make_handler ( true )  } ; 
146162                    MAIN_ALTSTACK . store ( handler. data ,  Ordering :: Relaxed ) ; 
147163                    mem:: forget ( handler) ; 
164+ 
165+                     if  let  Some ( guard_page_range)  = guard_page_range. take ( )  { 
166+                         let  thread_name = with_current_name ( |name| name. map ( Box :: from) ) ; 
167+                         set_current_info ( guard_page_range,  thread_name) ; 
168+                     } 
148169                } 
170+ 
149171                action. sa_flags  = SA_SIGINFO  | SA_ONSTACK ; 
150172                action. sa_sigaction  = signal_handler as  sighandler_t ; 
151173                // SAFETY: only overriding signals if the default is set 
@@ -214,9 +236,10 @@ mod imp {
214236        } 
215237
216238        if  !main_thread { 
217-             // Always write to GUARD to ensure the TLS variable is allocated. 
218-             let  guard = unsafe  {  current_guard ( )  } . unwrap_or ( 0 ..0 ) ; 
219-             GUARD . set ( ( guard. start ,  guard. end ) ) ; 
239+             if  let  Some ( guard_page_range)  = unsafe  {  current_guard ( )  }  { 
240+                 let  thread_name = with_current_name ( |name| name. map ( Box :: from) ) ; 
241+                 set_current_info ( guard_page_range,  thread_name) ; 
242+             } 
220243        } 
221244
222245        // SAFETY: assuming stack_t is zero-initializable 
@@ -261,6 +284,8 @@ mod imp {
261284            // a mapping that started one page earlier, so walk back a page and unmap from there. 
262285            unsafe  {  munmap ( data. sub ( page_size) ,  sigstack_size + page_size)  } ; 
263286        } 
287+ 
288+         delete_current_info ( ) ; 
264289    } 
265290
266291    /// Modern kernels on modern hardware can have dynamic signal stack sizes. 
@@ -590,17 +615,20 @@ mod imp {
590615// usually have fewer qualms about forwards compatibility, since the runtime 
591616// is shipped with the OS): 
592617// <https://github.com/apple/swift/blob/swift-5.10-RELEASE/stdlib/public/runtime/CrashHandlerMacOS.cpp> 
593- #[ cfg( not( any(  
594-     target_os = "linux" ,  
595-     target_os = "freebsd" ,  
596-     target_os = "hurd" ,  
597-     target_os = "macos" ,  
598-     target_os = "netbsd" ,  
599-     target_os = "openbsd" ,  
600-     target_os = "solaris" ,  
601-     target_os = "illumos" ,  
602-     target_os = "cygwin" ,  
603- ) ) ) ] 
618+ #[ cfg( any(  
619+     miri,  
620+     not( any(  
621+         target_os = "linux" ,  
622+         target_os = "freebsd" ,  
623+         target_os = "hurd" ,  
624+         target_os = "macos" ,  
625+         target_os = "netbsd" ,  
626+         target_os = "openbsd" ,  
627+         target_os = "solaris" ,  
628+         target_os = "illumos" ,  
629+         target_os = "cygwin" ,  
630+     ) )  
631+ ) ) ] 
604632mod  imp { 
605633    pub  unsafe  fn  init ( )  { } 
606634
0 commit comments