@@ -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