]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 rt::util::report_overflow; | |
12 | use core::prelude::*; | |
13 | use ptr; | |
14 | use mem; | |
15 | use libc; | |
16 | use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL}; | |
17 | use sys_common::{stack, thread_info}; | |
18 | ||
19 | pub struct Handler { | |
20 | _data: *mut libc::c_void | |
21 | } | |
22 | ||
23 | impl Handler { | |
24 | pub unsafe fn new() -> Handler { | |
25 | make_handler() | |
26 | } | |
27 | } | |
28 | ||
29 | impl Drop for Handler { | |
30 | fn drop(&mut self) {} | |
31 | } | |
32 | ||
33 | // get_task_info is called from an exception / signal handler. | |
34 | // It returns the guard page of the current task or 0 if that | |
35 | // guard page doesn't exist. None is returned if there's currently | |
36 | // no local task. | |
37 | unsafe fn get_task_guard_page() -> uint { | |
38 | thread_info::stack_guard() | |
39 | } | |
40 | ||
41 | // This is initialized in init() and only read from after | |
42 | static mut PAGE_SIZE: uint = 0; | |
43 | ||
44 | #[no_stack_check] | |
45 | extern "system" fn vectored_handler(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG { | |
46 | unsafe { | |
47 | let rec = &(*(*ExceptionInfo).ExceptionRecord); | |
48 | let code = rec.ExceptionCode; | |
49 | ||
50 | if code != EXCEPTION_STACK_OVERFLOW { | |
51 | return EXCEPTION_CONTINUE_SEARCH; | |
52 | } | |
53 | ||
54 | // We're calling into functions with stack checks, | |
55 | // however stack checks by limit should be disabled on Windows | |
56 | stack::record_sp_limit(0); | |
57 | ||
58 | report_overflow(); | |
59 | ||
60 | EXCEPTION_CONTINUE_SEARCH | |
61 | } | |
62 | } | |
63 | ||
64 | pub unsafe fn init() { | |
65 | let mut info = mem::zeroed(); | |
66 | libc::GetSystemInfo(&mut info); | |
67 | PAGE_SIZE = info.dwPageSize as uint; | |
68 | ||
69 | if AddVectoredExceptionHandler(0, vectored_handler) == ptr::null_mut() { | |
70 | panic!("failed to install exception handler"); | |
71 | } | |
72 | ||
73 | mem::forget(make_handler()); | |
74 | } | |
75 | ||
76 | pub unsafe fn cleanup() { | |
77 | } | |
78 | ||
79 | pub unsafe fn make_handler() -> Handler { | |
80 | if SetThreadStackGuarantee(&mut 0x5000) == 0 { | |
81 | panic!("failed to reserve stack space for exception handling"); | |
82 | } | |
83 | ||
84 | Handler { _data: 0i as *mut libc::c_void } | |
85 | } | |
86 | ||
87 | pub struct EXCEPTION_RECORD { | |
88 | pub ExceptionCode: DWORD, | |
89 | pub ExceptionFlags: DWORD, | |
90 | pub ExceptionRecord: *mut EXCEPTION_RECORD, | |
91 | pub ExceptionAddress: LPVOID, | |
92 | pub NumberParameters: DWORD, | |
93 | pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] | |
94 | } | |
95 | ||
96 | pub struct EXCEPTION_POINTERS { | |
97 | pub ExceptionRecord: *mut EXCEPTION_RECORD, | |
98 | pub ContextRecord: LPVOID | |
99 | } | |
100 | ||
101 | pub type PVECTORED_EXCEPTION_HANDLER = extern "system" | |
102 | fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; | |
103 | ||
104 | pub type ULONG = libc::c_ulong; | |
105 | ||
106 | const EXCEPTION_CONTINUE_SEARCH: LONG = 0; | |
107 | const EXCEPTION_MAXIMUM_PARAMETERS: uint = 15; | |
108 | const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; | |
109 | ||
110 | extern "system" { | |
111 | fn AddVectoredExceptionHandler(FirstHandler: ULONG, | |
112 | VectoredHandler: PVECTORED_EXCEPTION_HANDLER) | |
113 | -> LPVOID; | |
114 | fn SetThreadStackGuarantee(StackSizeInBytes: *mut ULONG) -> BOOL; | |
115 | } |