]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/stack_overflow.rs
mk: The beta channel produces things called 'beta'
[rust.git] / src / libstd / sys / unix / stack_overflow.rs
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.
10
11 use libc;
12 use core::prelude::*;
13 use self::imp::{make_handler, drop_handler};
14
15 pub use self::imp::{init, cleanup};
16
17 pub struct Handler {
18     _data: *mut libc::c_void
19 }
20
21 impl Handler {
22     pub unsafe fn new() -> Handler {
23         make_handler()
24     }
25 }
26
27 impl Drop for Handler {
28     fn drop(&mut self) {
29         unsafe {
30             drop_handler(self);
31         }
32     }
33 }
34
35 #[cfg(any(target_os = "linux", target_os = "macos"))]
36 mod imp {
37     use core::prelude::*;
38     use sys_common::stack;
39
40     use super::Handler;
41     use rt::util::report_overflow;
42     use mem;
43     use ptr;
44     use intrinsics;
45     use self::signal::{siginfo, sigaction, SIGBUS, SIG_DFL,
46                        SA_SIGINFO, SA_ONSTACK, sigaltstack,
47                        SIGSTKSZ};
48     use libc;
49     use libc::funcs::posix88::mman::{mmap, munmap};
50     use libc::consts::os::posix88::{SIGSEGV,
51                                     PROT_READ,
52                                     PROT_WRITE,
53                                     MAP_PRIVATE,
54                                     MAP_ANON,
55                                     MAP_FAILED};
56
57     use sys_common::thread_info;
58
59
60     // This is initialized in init() and only read from after
61     static mut PAGE_SIZE: uint = 0;
62
63     #[no_stack_check]
64     unsafe extern fn signal_handler(signum: libc::c_int,
65                                      info: *mut siginfo,
66                                      _data: *mut libc::c_void) {
67
68         // We can not return from a SIGSEGV or SIGBUS signal.
69         // See: https://www.gnu.org/software/libc/manual/html_node/Handler-Returns.html
70
71         unsafe fn term(signum: libc::c_int) -> ! {
72             use core::mem::transmute;
73
74             signal(signum, transmute(SIG_DFL));
75             raise(signum);
76             intrinsics::abort();
77         }
78
79         // We're calling into functions with stack checks
80         stack::record_sp_limit(0);
81
82         let guard = thread_info::stack_guard();
83         let addr = (*info).si_addr as uint;
84
85         if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
86             term(signum);
87         }
88
89         report_overflow();
90
91         intrinsics::abort()
92     }
93
94     static mut MAIN_ALTSTACK: *mut libc::c_void = 0 as *mut libc::c_void;
95
96     pub unsafe fn init() {
97         let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
98         if psize == -1 {
99             panic!("failed to get page size");
100         }
101
102         PAGE_SIZE = psize as uint;
103
104         let mut action: sigaction = mem::zeroed();
105         action.sa_flags = SA_SIGINFO | SA_ONSTACK;
106         action.sa_sigaction = signal_handler as sighandler_t;
107         sigaction(SIGSEGV, &action, ptr::null_mut());
108         sigaction(SIGBUS, &action, ptr::null_mut());
109
110         let handler = make_handler();
111         MAIN_ALTSTACK = handler._data;
112         mem::forget(handler);
113     }
114
115     pub unsafe fn cleanup() {
116         Handler { _data: MAIN_ALTSTACK };
117     }
118
119     pub unsafe fn make_handler() -> Handler {
120         let alt_stack = mmap(ptr::null_mut(),
121                              signal::SIGSTKSZ,
122                              PROT_READ | PROT_WRITE,
123                              MAP_PRIVATE | MAP_ANON,
124                              -1,
125                              0);
126         if alt_stack == MAP_FAILED {
127             panic!("failed to allocate an alternative stack");
128         }
129
130         let mut stack: sigaltstack = mem::zeroed();
131
132         stack.ss_sp = alt_stack;
133         stack.ss_flags = 0;
134         stack.ss_size = SIGSTKSZ;
135
136         sigaltstack(&stack, ptr::null_mut());
137
138         Handler { _data: alt_stack }
139     }
140
141     pub unsafe fn drop_handler(handler: &mut Handler) {
142         munmap(handler._data, SIGSTKSZ);
143     }
144
145     type sighandler_t = *mut libc::c_void;
146
147     #[cfg(any(all(target_os = "linux", target_arch = "x86"), // may not match
148               all(target_os = "linux", target_arch = "x86_64"),
149               all(target_os = "linux", target_arch = "arm"), // may not match
150               all(target_os = "linux", target_arch = "aarch64"),
151               all(target_os = "linux", target_arch = "mips"), // may not match
152               all(target_os = "linux", target_arch = "mipsel"), // may not match
153               target_os = "android"))] // may not match
154     mod signal {
155         use libc;
156         use super::sighandler_t;
157
158         pub static SA_ONSTACK: libc::c_int = 0x08000000;
159         pub static SA_SIGINFO: libc::c_int = 0x00000004;
160         pub static SIGBUS: libc::c_int = 7;
161
162         pub static SIGSTKSZ: libc::size_t = 8192;
163
164         pub const SIG_DFL: sighandler_t = 0i as sighandler_t;
165
166         // This definition is not as accurate as it could be, {si_addr} is
167         // actually a giant union. Currently we're only interested in that field,
168         // however.
169         #[repr(C)]
170         pub struct siginfo {
171             si_signo: libc::c_int,
172             si_errno: libc::c_int,
173             si_code: libc::c_int,
174             pub si_addr: *mut libc::c_void
175         }
176
177         #[repr(C)]
178         pub struct sigaction {
179             pub sa_sigaction: sighandler_t,
180             pub sa_mask: sigset_t,
181             pub sa_flags: libc::c_int,
182             sa_restorer: *mut libc::c_void,
183         }
184
185         #[cfg(any(all(stage0, target_word_size = "32"),
186                   all(not(stage0), target_pointer_width = "32")))]
187         #[repr(C)]
188         pub struct sigset_t {
189             __val: [libc::c_ulong; 32],
190         }
191         #[cfg(any(all(stage0, target_word_size = "64"),
192                   all(not(stage0), target_pointer_width = "64")))]
193         #[repr(C)]
194         pub struct sigset_t {
195             __val: [libc::c_ulong; 16],
196         }
197
198         #[repr(C)]
199         pub struct sigaltstack {
200             pub ss_sp: *mut libc::c_void,
201             pub ss_flags: libc::c_int,
202             pub ss_size: libc::size_t
203         }
204
205     }
206
207     #[cfg(target_os = "macos")]
208     mod signal {
209         use libc;
210         use super::sighandler_t;
211
212         pub const SA_ONSTACK: libc::c_int = 0x0001;
213         pub const SA_SIGINFO: libc::c_int = 0x0040;
214         pub const SIGBUS: libc::c_int = 10;
215
216         pub const SIGSTKSZ: libc::size_t = 131072;
217
218         pub const SIG_DFL: sighandler_t = 0i as sighandler_t;
219
220         pub type sigset_t = u32;
221
222         // This structure has more fields, but we're not all that interested in
223         // them.
224         #[repr(C)]
225         pub struct siginfo {
226             pub si_signo: libc::c_int,
227             pub si_errno: libc::c_int,
228             pub si_code: libc::c_int,
229             pub pid: libc::pid_t,
230             pub uid: libc::uid_t,
231             pub status: libc::c_int,
232             pub si_addr: *mut libc::c_void
233         }
234
235         #[repr(C)]
236         pub struct sigaltstack {
237             pub ss_sp: *mut libc::c_void,
238             pub ss_size: libc::size_t,
239             pub ss_flags: libc::c_int
240         }
241
242         #[repr(C)]
243         pub struct sigaction {
244             pub sa_sigaction: sighandler_t,
245             pub sa_mask: sigset_t,
246             pub sa_flags: libc::c_int,
247         }
248     }
249
250     extern {
251         pub fn signal(signum: libc::c_int, handler: sighandler_t) -> sighandler_t;
252         pub fn raise(signum: libc::c_int) -> libc::c_int;
253
254         pub fn sigaction(signum: libc::c_int,
255                          act: *const sigaction,
256                          oldact: *mut sigaction) -> libc::c_int;
257
258         pub fn sigaltstack(ss: *const sigaltstack,
259                            oss: *mut sigaltstack) -> libc::c_int;
260     }
261 }
262
263 #[cfg(not(any(target_os = "linux",
264               target_os = "macos")))]
265 mod imp {
266     use libc;
267
268     pub unsafe fn init() {
269     }
270
271     pub unsafe fn cleanup() {
272     }
273
274     pub unsafe fn make_handler() -> super::Handler {
275         super::Handler { _data: 0i as *mut libc::c_void }
276     }
277
278     pub unsafe fn drop_handler(_handler: &mut super::Handler) {
279     }
280 }