Skip to content

Commit 5b8b6a5

Browse files
committed
stack_overflow: Enable re-raising SIGSEGV / SIGBUS in their own handlers
By default, UNIX signals are blocked during their own handlers' execution, so `raise(signum)` from inside a handler was not actually getting delivered. Therefore the following instruction, `intrinsics::abort()`, was getting executed. This led to segfaulting Rust programs incorrectly having a termination status indicating SIGILL from the `abort()`, instead of SIGSEGV (or SIGBUS). We can use the `SA_NODEFER` flag to prevent this behavior. We can also use `SA_RESETHAND` to have the system reset the default signal handler for us upon entry, instead of doing that ourselves.
1 parent 2a93dca commit 5b8b6a5

File tree

3 files changed

+20
-18
lines changed

3 files changed

+20
-18
lines changed

src/libstd/sys/unix/c.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
#![allow(non_camel_case_types)]
2626

2727
pub use self::signal_os::{sigaction, siginfo, sigset_t, sigaltstack};
28-
pub use self::signal_os::{SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSTKSZ, SIG_SETMASK};
28+
pub use self::signal_os::{SA_ONSTACK, SA_SIGINFO, SA_NODEFER, SA_RESETHAND};
29+
pub use self::signal_os::{SIGBUS, SIGSTKSZ, SIG_SETMASK};
2930

3031
use libc;
3132

@@ -168,8 +169,8 @@ pub unsafe fn sigemptyset(set: *mut sigset_t) -> libc::c_int {
168169
#[cfg(any(target_os = "linux",
169170
target_os = "android"))]
170171
mod signal_os {
171-
pub use self::arch::{SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_SETMASK,
172-
sigaction, sigaltstack};
172+
pub use self::arch::{SA_ONSTACK, SA_SIGINFO, SA_NODEFER, SA_RESETHAND,
173+
SIGBUS, SIG_SETMASK, sigaction, sigaltstack};
173174
use libc;
174175

175176
#[cfg(any(target_arch = "x86",
@@ -226,6 +227,8 @@ mod signal_os {
226227

227228
pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
228229
pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
230+
pub const SA_NODEFER: libc::c_ulong = 0x40000000;
231+
pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
229232

230233
pub const SIGBUS: libc::c_int = 7;
231234

@@ -275,6 +278,8 @@ mod signal_os {
275278

276279
pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
277280
pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
281+
pub const SA_NODEFER: libc::c_ulong = 0x40000000;
282+
pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
278283

279284
pub const SIGBUS: libc::c_int = 10;
280285

@@ -328,6 +333,8 @@ mod signal_os {
328333

329334
pub const SA_ONSTACK: libc::c_int = 0x0001;
330335
pub const SA_SIGINFO: libc::c_int = 0x0040;
336+
pub const SA_NODEFER: libc::c_ulong = 0x0010;
337+
pub const SA_RESETHAND: libc::c_int = 0x0004;
331338

332339
pub const SIGBUS: libc::c_int = 10;
333340

src/libstd/sys/unix/stack_overflow.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ mod imp {
4444
use mem;
4545
use ptr;
4646
use intrinsics;
47-
use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
48-
SA_SIGINFO, SA_ONSTACK, sigaltstack,
47+
use sys::c::{siginfo, sigaction, sigaltstack, SIGBUS,
48+
SA_SIGINFO, SA_ONSTACK, SA_NODEFER, SA_RESETHAND,
4949
SIGSTKSZ, sighandler_t, raise};
5050
use libc;
5151
use libc::funcs::posix88::mman::{mmap, munmap};
@@ -71,26 +71,18 @@ mod imp {
7171
// We can not return from a SIGSEGV or SIGBUS signal.
7272
// See: https://www.gnu.org/software/libc/manual/html_node/Handler-Returns.html
7373

74-
unsafe fn term(signum: libc::c_int) -> ! {
75-
use core::mem::transmute;
76-
77-
signal(signum, transmute(SIG_DFL));
78-
raise(signum);
79-
intrinsics::abort();
80-
}
81-
8274
// We're calling into functions with stack checks
8375
stack::record_sp_limit(0);
8476

8577
let guard = thread_info::stack_guard().unwrap_or(0);
8678
let addr = (*info).si_addr as usize;
8779

8880
if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
89-
term(signum);
81+
raise(signum);
82+
} else {
83+
report_overflow();
9084
}
9185

92-
report_overflow();
93-
9486
intrinsics::abort()
9587
}
9688

@@ -105,7 +97,7 @@ mod imp {
10597
PAGE_SIZE = psize as usize;
10698

10799
let mut action: sigaction = mem::zeroed();
108-
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
100+
action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND;
109101
action.sa_sigaction = signal_handler as sighandler_t;
110102
sigaction(SIGSEGV, &action, ptr::null_mut());
111103
sigaction(SIGBUS, &action, ptr::null_mut());

src/test/run-pass/segfault-no-out-of-stack.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(libc)]
12+
extern crate libc;
1113

1214
use std::process::Command;
1315
use std::env;
16+
use libc::consts::os::posix88::SIGSEGV;
1417

1518
fn main() {
1619
let args: Vec<String> = env::args().collect();
1720
if args.len() > 1 && args[1] == "segfault" {
1821
unsafe { *(0 as *mut isize) = 1 }; // trigger a segfault
1922
} else {
2023
let segfault = Command::new(&args[0]).arg("segfault").output().unwrap();
21-
assert!(!segfault.status.success());
24+
assert!(segfault.status.signal() == Some(SIGSEGV));
2225
let error = String::from_utf8_lossy(&segfault.stderr);
2326
assert!(!error.contains("has overflowed its stack"));
2427
}

0 commit comments

Comments
 (0)