Rollup merge of #127843 - workingjubilee:break-up-big-ass-stack-overf… · model-checking/verify-rust-std@bd26295
@@ -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)]
9094unsafe extern "C" fn signal_handler(
9195signum: libc::c_int,
9296info: *mut libc::siginfo_t,
9397_data: *mut libc::c_void,
9498) {
9599let (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() };
9710298103// 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 {
105110rtabort!("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()) };
111118112119// See comment above for why this function returns.
113120}
@@ -117,32 +124,45 @@ mod imp {
117124static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
118125static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
119126127+/// # Safety
128+ /// Must be called only once
129+ #[forbid(unsafe_op_in_unsafe_fn)]
120130pub unsafe fn init() {
121131PAGE_SIZE.store(os::page_size(), Ordering::Relaxed);
122132123133// 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) };
125135GUARD.set((guard.start, guard.end));
126136127-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() };
128139for &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.
131143if 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}
143158159+/// # Safety
160+ /// Must be called only once
161+ #[forbid(unsafe_op_in_unsafe_fn)]
144162pub 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}
147167148168unsafe 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}
189209210+/// # Safety
211+ /// Mutates the alternate signal stack
212+ #[forbid(unsafe_op_in_unsafe_fn)]
190213pub unsafe fn make_handler(main_thread: bool) -> Handler {
191-if !NEED_ALTSTACK.load(Ordering::Relaxed) {
214+if !NEED_ALTSTACK.load(Ordering::Acquire) {
192215return Handler::null();
193216}
194217195218if !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);
198221GUARD.set((guard.start, guard.end));
199222}
200223201-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.
204229if 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+}
207235Handler { data: stack.ss_sp as *mut libc::c_void }
208236} else {
209237Handler::null()
210238}
211239}
212240241+/// # 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)]
213247pub unsafe fn drop_handler(data: *mut libc::c_void) {
214248if !data.is_null() {
215249let sigstack_size = sigstack_size();
216250let page_size = PAGE_SIZE.load(Ordering::Relaxed);
217-let stack = libc::stack_t {
251+let disabling_stack = libc::stack_t {
218252ss_sp: ptr::null_mut(),
219253ss_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.
224258ss_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}
456491457492#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
493+// FIXME: I am probably not unsafe.
458494unsafe fn current_guard() -> Option<Range<usize>> {
459495let stackptr = get_stack_start()?;
460496let 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.
472509unsafe fn current_guard() -> Option<Range<usize>> {
473510let mut ret = None;
474511let mut attr: libc::pthread_attr_t = crate::mem::zeroed();