]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/stack_overflow.rs
Imported Upstream version 1.7.0+dfsg1
[rustc.git] / src / libstd / sys / unix / stack_overflow.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
9cc50fc6 10#![cfg_attr(test, allow(dead_code))]
1a4d82fc
JJ
11
12use libc;
1a4d82fc
JJ
13use self::imp::{make_handler, drop_handler};
14
9cc50fc6
SL
15pub use self::imp::cleanup;
16pub use self::imp::init;
1a4d82fc
JJ
17
18pub struct Handler {
19 _data: *mut libc::c_void
20}
21
22impl Handler {
23 pub unsafe fn new() -> Handler {
24 make_handler()
25 }
26}
27
28impl Drop for Handler {
29 fn drop(&mut self) {
30 unsafe {
31 drop_handler(self);
32 }
33 }
34}
35
85aaf69f
SL
36#[cfg(any(target_os = "linux",
37 target_os = "macos",
c34b1796 38 target_os = "bitrig",
92a42be0
SL
39 target_os = "dragonfly",
40 target_os = "freebsd",
b039eaaf 41 all(target_os = "netbsd", not(target_vendor = "rumprun")),
85aaf69f 42 target_os = "openbsd"))]
1a4d82fc 43mod imp {
1a4d82fc 44 use super::Handler;
1a4d82fc
JJ
45 use mem;
46 use ptr;
9cc50fc6 47 use libc::{sigaltstack, SIGSTKSZ};
92a42be0 48 use libc::{sigaction, SIGBUS, SIG_DFL,
9cc50fc6 49 SA_SIGINFO, SA_ONSTACK, sighandler_t};
1a4d82fc 50 use libc;
92a42be0 51 use libc::{mmap, munmap};
e9174d1e
SL
52 use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
53 use libc::MAP_FAILED;
1a4d82fc
JJ
54
55 use sys_common::thread_info;
56
57
58 // This is initialized in init() and only read from after
c34b1796 59 static mut PAGE_SIZE: usize = 0;
1a4d82fc 60
92a42be0 61 #[cfg(any(target_os = "linux", target_os = "android"))]
9cc50fc6 62 unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
92a42be0
SL
63 #[repr(C)]
64 struct siginfo_t {
65 a: [libc::c_int; 3], // si_signo, si_code, si_errno,
66 si_addr: *mut libc::c_void,
67 }
68
9cc50fc6 69 (*(info as *const siginfo_t)).si_addr as usize
92a42be0
SL
70 }
71
72 #[cfg(not(any(target_os = "linux", target_os = "android")))]
9cc50fc6
SL
73 unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
74 (*info).si_addr as usize
92a42be0
SL
75 }
76
e9174d1e
SL
77 // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
78 // (unmapped pages) at the end of every thread's stack, so if a thread ends
79 // up running into the guard page it'll trigger this handler. We want to
80 // detect these cases and print out a helpful error saying that the stack
81 // has overflowed. All other signals, however, should go back to what they
82 // were originally supposed to do.
83 //
84 // This handler currently exists purely to print an informative message
85 // whenever a thread overflows its stack. When run the handler always
86 // un-registers itself after running and then returns (to allow the original
87 // signal to be delivered again). By returning we're ensuring that segfaults
88 // do indeed look like segfaults.
89 //
90 // Returning from this kind of signal handler is technically not defined to
91 // work when reading the POSIX spec strictly, but in practice it turns out
92 // many large systems and all implementations allow returning from a signal
93 // handler to work. For a more detailed explanation see the comments on
94 // #26458.
1a4d82fc 95 unsafe extern fn signal_handler(signum: libc::c_int,
92a42be0 96 info: *mut libc::siginfo_t,
e9174d1e 97 _data: *mut libc::c_void) {
9cc50fc6
SL
98 use sys_common::util::report_overflow;
99
d9579d0f 100 let guard = thread_info::stack_guard().unwrap_or(0);
9cc50fc6 101 let addr = siginfo_si_addr(info);
1a4d82fc 102
e9174d1e
SL
103 // If the faulting address is within the guard page, then we print a
104 // message saying so.
105 if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
106 report_overflow();
1a4d82fc
JJ
107 }
108
e9174d1e
SL
109 // Unregister ourselves by reverting back to the default behavior.
110 let mut action: sigaction = mem::zeroed();
111 action.sa_sigaction = SIG_DFL;
112 sigaction(signum, &action, ptr::null_mut());
1a4d82fc 113
e9174d1e 114 // See comment above for why this function returns.
1a4d82fc
JJ
115 }
116
e9174d1e 117 static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
1a4d82fc
JJ
118
119 pub unsafe fn init() {
e9174d1e 120 PAGE_SIZE = ::sys::os::page_size();
1a4d82fc
JJ
121
122 let mut action: sigaction = mem::zeroed();
123 action.sa_flags = SA_SIGINFO | SA_ONSTACK;
124 action.sa_sigaction = signal_handler as sighandler_t;
125 sigaction(SIGSEGV, &action, ptr::null_mut());
126 sigaction(SIGBUS, &action, ptr::null_mut());
127
128 let handler = make_handler();
129 MAIN_ALTSTACK = handler._data;
130 mem::forget(handler);
131 }
132
133 pub unsafe fn cleanup() {
134 Handler { _data: MAIN_ALTSTACK };
135 }
136
137 pub unsafe fn make_handler() -> Handler {
138 let alt_stack = mmap(ptr::null_mut(),
62682a34 139 SIGSTKSZ,
1a4d82fc
JJ
140 PROT_READ | PROT_WRITE,
141 MAP_PRIVATE | MAP_ANON,
142 -1,
143 0);
144 if alt_stack == MAP_FAILED {
145 panic!("failed to allocate an alternative stack");
146 }
147
92a42be0 148 let mut stack: libc::stack_t = mem::zeroed();
1a4d82fc
JJ
149
150 stack.ss_sp = alt_stack;
151 stack.ss_flags = 0;
152 stack.ss_size = SIGSTKSZ;
153
154 sigaltstack(&stack, ptr::null_mut());
155
156 Handler { _data: alt_stack }
157 }
158
159 pub unsafe fn drop_handler(handler: &mut Handler) {
160 munmap(handler._data, SIGSTKSZ);
161 }
1a4d82fc
JJ
162}
163
164#[cfg(not(any(target_os = "linux",
85aaf69f 165 target_os = "macos",
c34b1796 166 target_os = "bitrig",
92a42be0
SL
167 target_os = "dragonfly",
168 target_os = "freebsd",
b039eaaf 169 all(target_os = "netbsd", not(target_vendor = "rumprun")),
85aaf69f 170 target_os = "openbsd")))]
1a4d82fc 171mod imp {
e9174d1e 172 use ptr;
1a4d82fc
JJ
173
174 pub unsafe fn init() {
175 }
176
177 pub unsafe fn cleanup() {
178 }
179
180 pub unsafe fn make_handler() -> super::Handler {
e9174d1e 181 super::Handler { _data: ptr::null_mut() }
1a4d82fc
JJ
182 }
183
184 pub unsafe fn drop_handler(_handler: &mut super::Handler) {
185 }
186}