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