Skip to content

Commit 8d68093

Browse files
committed
Remove segmented stack on windows
On Windows, for each function `__chkstk()`/`_alloca()` is (already) inserted at prologue if the function takes 4096 or more bytes on stack. The stack checker aborts (causes segmentation fault) if current stack pointer is out of range. With this check and stack guard page, we can detect stack overflow without segmented stack support. This also fixes some issue regarding `$fs:0x14` (we use it for segmented stack support).
1 parent 124e997 commit 8d68093

File tree

4 files changed

+50
-36
lines changed

4 files changed

+50
-36
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -417,15 +417,23 @@ pub fn set_always_inline(f: ValueRef) {
417417
}
418418

419419
pub fn set_split_stack(f: ValueRef) {
420-
"split-stack".with_c_str(|buf| {
421-
unsafe { llvm::LLVMAddFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); }
422-
})
420+
if !cfg!(windows) {
421+
"split-stack".with_c_str(|buf| {
422+
unsafe {
423+
llvm::LLVMAddFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf);
424+
}
425+
})
426+
}
423427
}
424428

425429
pub fn unset_split_stack(f: ValueRef) {
426-
"split-stack".with_c_str(|buf| {
427-
unsafe { llvm::LLVMRemoveFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); }
428-
})
430+
if !cfg!(windows) {
431+
"split-stack".with_c_str(|buf| {
432+
unsafe {
433+
llvm::LLVMRemoveFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf);
434+
}
435+
})
436+
}
429437
}
430438

431439
// Double-check that we never ask LLVM to declare the same symbol twice. It

src/libstd/rand/os.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ mod imp {
6969
use os;
7070
use rand::Rng;
7171
use result::{Ok, Err};
72-
use rt::stack;
72+
//use rt::stack;
7373
use self::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
7474
use slice::MutableVector;
7575

@@ -91,7 +91,7 @@ mod imp {
9191
static PROV_RSA_FULL: DWORD = 1;
9292
static CRYPT_SILENT: DWORD = 64;
9393
static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
94-
static NTE_BAD_SIGNATURE: DWORD = 0x80090006;
94+
//static NTE_BAD_SIGNATURE: DWORD = 0x80090006;
9595

9696
#[allow(non_snake_case_functions)]
9797
extern "system" {
@@ -110,12 +110,13 @@ mod imp {
110110
/// Create a new `OsRng`.
111111
pub fn new() -> IoResult<OsRng> {
112112
let mut hcp = 0;
113-
let mut ret = unsafe {
113+
let ret = unsafe {
114114
CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
115115
PROV_RSA_FULL,
116116
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
117117
};
118118

119+
// TODO remove this yah
119120
// FIXME #13259:
120121
// It turns out that if we can't acquire a context with the
121122
// NTE_BAD_SIGNATURE error code, the documentation states:
@@ -141,16 +142,16 @@ mod imp {
141142
// Again, I'm not sure why this is the fix, nor why we're getting
142143
// this error. All I can say is that this seems to allow libnative
143144
// to progress where it otherwise would be hindered. Who knew?
144-
if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
145-
unsafe {
146-
let limit = stack::get_sp_limit();
147-
stack::record_sp_limit(0);
148-
ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
149-
PROV_RSA_FULL,
150-
CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
151-
stack::record_sp_limit(limit);
152-
}
153-
}
145+
// if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
146+
// unsafe {
147+
// let limit = stack::get_sp_limit();
148+
// stack::record_sp_limit(0);
149+
// ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
150+
// PROV_RSA_FULL,
151+
// CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
152+
// stack::record_sp_limit(limit);
153+
// }
154+
// }
154155

155156
if ret == 0 {
156157
Err(IoError::last_error())

src/libstd/rt/stack.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,9 @@ pub unsafe fn record_sp_limit(limit: uint) {
162162
asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
163163
}
164164
#[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
165-
unsafe fn target_record_sp_limit(limit: uint) {
166-
// see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
167-
// store this inside of the "arbitrary data slot", but double the size
168-
// because this is 64 bit instead of 32 bit
169-
asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile")
165+
unsafe fn target_record_sp_limit(_limit: uint) {
166+
// on windows, TODO explanation what is this
167+
// asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile")
170168
}
171169
#[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
172170
unsafe fn target_record_sp_limit(limit: uint) {
@@ -185,10 +183,11 @@ pub unsafe fn record_sp_limit(limit: uint) {
185183
asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
186184
}
187185
#[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
188-
unsafe fn target_record_sp_limit(limit: uint) {
186+
unsafe fn target_record_sp_limit(_limit: uint) {
189187
// see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
190188
// store this inside of the "arbitrary data slot"
191-
asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile")
189+
// TODO explanation
190+
// asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile")
192191
}
193192

194193
// mips, arm - Some brave soul can port these to inline asm, but it's over
@@ -232,9 +231,10 @@ pub unsafe fn get_sp_limit() -> uint {
232231
}
233232
#[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
234233
unsafe fn target_get_sp_limit() -> uint {
235-
let limit;
236-
asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
237-
return limit;
234+
return 0; // TODO
235+
// let limit;
236+
// asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
237+
// return limit;
238238
}
239239
#[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
240240
unsafe fn target_get_sp_limit() -> uint {
@@ -260,9 +260,10 @@ pub unsafe fn get_sp_limit() -> uint {
260260
}
261261
#[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
262262
unsafe fn target_get_sp_limit() -> uint {
263-
let limit;
264-
asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
265-
return limit;
263+
return 0; // TODO
264+
//let limit;
265+
//asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
266+
//return limit;
266267
}
267268

268269
// mips, arm - Some brave soul can port these to inline asm, but it's over

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,16 @@ fn main() {
4242
} else {
4343
let silent = Command::new(args[0].as_slice()).arg("silent").output().unwrap();
4444
assert!(!silent.status.success());
45-
let error = str::from_utf8_lossy(silent.error.as_slice());
46-
assert!(error.as_slice().contains("has overflowed its stack"));
45+
if !cfg!(windows) {
46+
let error = str::from_utf8_lossy(silent.error.as_slice());
47+
assert!(error.as_slice().contains("has overflowed its stack"));
48+
}
4749

4850
let loud = Command::new(args[0].as_slice()).arg("loud").output().unwrap();
4951
assert!(!loud.status.success());
50-
let error = str::from_utf8_lossy(silent.error.as_slice());
51-
assert!(error.as_slice().contains("has overflowed its stack"));
52+
if !cfg!(windows) {
53+
let error = str::from_utf8_lossy(silent.error.as_slice());
54+
assert!(error.as_slice().contains("has overflowed its stack"));
55+
}
5256
}
5357
}

0 commit comments

Comments
 (0)