rsgc/heap/signals/
unix.rs1use std::{mem::MaybeUninit, ptr::null_mut};
2
3use libc::*;
4
5use crate::{
6 heap::{heap::heap, safepoint, stack::approximate_stack_pointer, thread::Thread},
7 utils::machine_context::{registers_from_ucontext, PlatformRegisters},
8};
9
10unsafe extern "C" fn sigdie_handler(sig: i32, _info: *mut siginfo_t, _context: *mut c_void) {
11 let mut sset = MaybeUninit::<libc::sigset_t>::zeroed().assume_init();
12 sigfillset(&mut sset);
13 sigprocmask(SIG_UNBLOCK, &mut sset, null_mut());
14 signal(sig, SIG_DFL);
15
16 if sig != SIGSEGV && sig != SIGBUS && sig != SIGILL {
17 raise(sig);
18 }
19
20 }
22
23pub unsafe extern "C" fn handle_sigsegv(
24 _sig: i32,
25 info: *mut siginfo_t,
26 context: *mut ucontext_t,
27) -> bool {
28 if safepoint::addr_in_safepoint((*info).si_addr() as _) {
29 let thread = Thread::current();
30 thread.platform_registers = registers_from_ucontext(context);
31
32 log::trace!(target: "gc-safepoint", "{:?} reached safepoint", std::thread::current().id());
33 thread.enter_safepoint(get_sp_from_ucontext(context).cast());
35 thread.platform_registers = null_mut();
36 log::trace!(target: "gc-safepoint", "{:?} exit safepoint", std::thread::current().id());
37 true
38 } else {
39 false
40 }
41}
42
43pub unsafe extern "C" fn segv_handler(sig: i32, info: *mut siginfo_t, context: *mut ucontext_t) {
44 if safepoint::addr_in_safepoint((*info).si_addr() as usize) {
47 let thread = Thread::current();
48 thread.platform_registers = registers_from_ucontext(context);
49
50 log::trace!(target: "gc-safepoint", "{:?} reached safepoint", std::thread::current().id());
51 thread.enter_safepoint(get_sp_from_ucontext(context).cast());
53 thread.platform_registers = null_mut();
54 log::trace!(target: "gc-safepoint", "{:?} exit safepoint", std::thread::current().id());
55 return;
56 } else {
57 let heap = heap();
58
59 if heap.is_in((*info).si_addr().cast()) {
60 let backtrace = std::backtrace::Backtrace::force_capture();
66
67 eprintln!(
68 "FATAL: Heap Out of Bounds Access of {:p}",
69 (*info).si_addr()
70 );
71 eprintln!("Probably tried to access uncommited region or it is a bug in GC: report it to https://github.com/playxe/rsgc");
72 eprintln!("{}", backtrace);
73
74 return sigdie_handler(sig, info, context as _);
75 }
76 }
77
78 println!(
79 "FATAL: Unhandled signal {}: {:p}, backtrace: \n{}",
80 sig,
81 (*info).si_addr(),
82 std::backtrace::Backtrace::force_capture()
83 );
84
85 sigdie_handler(sig, info, context as _);
86}
87
88unsafe fn get_sp_from_ucontext(uc: *mut ucontext_t) -> *mut () {
89 cfg_if::cfg_if! {
90 if #[cfg(any(target_os="macos", target_os="ios", target_os="tvos", target_os="watchos"))]
91 {
92 #[cfg(any(target_arch="aarch64", target_arch="arm"))]
93 {
94
95 (*(*uc).uc_mcontext).__ss.__sp as _
96 }
97 #[cfg(target_arch="x86_64")]
98 {
99 (*(*uc).uc_mcontext).__ss.__rsp as _
100 }
101 #[cfg(target_arch="x86")]
102 {
103 (*(*uc).uc_mcontext).__ss.__esp as _
104 }
105 } else {
106 let _ = uc;
107 approximate_stack_pointer() as _
109 }
110 }
111}
112
113pub fn install_signal_handlers() {
114 unsafe {
115 let mut act: sigaction = std::mem::MaybeUninit::<sigaction>::zeroed().assume_init();
116
117 sigemptyset(&mut act.sa_mask);
118 act.sa_sigaction = segv_handler as _;
119 act.sa_flags = SA_SIGINFO;
120
121 if sigaction(SIGSEGV, &act, null_mut()) < 0 {
122 panic!("failed to set SIGSEGV handler for safepoints");
123 }
124
125 if sigaction(SIGBUS, &act, null_mut()) < 0 {
127 panic!("failed to set SIGBUS handler for safepoints");
128 }
129 }
130}