From 91e30ecf6774929babdc6ed7660a39f539239565 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 26 Sep 2014 10:11:22 -0700 Subject: [PATCH 1/5] rustc: Turn off split stacks on Windows --- src/librustc/middle/trans/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 962f97ab74c6..5c8c6a24b4fa 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -546,7 +546,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { // but it could be enabled (with patched LLVM) pub fn is_split_stack_supported(&self) -> bool { let ref cfg = self.sess().targ_cfg; - cfg.os != abi::OsiOS || cfg.arch != abi::Arm + (cfg.os != abi::OsiOS || cfg.arch != abi::Arm) && cfg.os != abi::OsWindows } From a52eaaa996a7edeb699a756f755ad4b8c23dc9df Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 24 Sep 2014 15:35:44 -0700 Subject: [PATCH 2/5] Disable runtime split stack support on Windows --- src/librustrt/stack.rs | 19 ++++----------- src/libstd/rand/os.rs | 40 +------------------------------ src/test/run-pass/out-of-stack.rs | 10 ++++++-- 3 files changed, 13 insertions(+), 56 deletions(-) diff --git a/src/librustrt/stack.rs b/src/librustrt/stack.rs index 3190e9f78414..a4cbbf248113 100644 --- a/src/librustrt/stack.rs +++ b/src/librustrt/stack.rs @@ -200,11 +200,7 @@ pub unsafe fn record_sp_limit(limit: uint) { asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile") } #[cfg(target_arch = "x86_64", target_os = "windows")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block - // store this inside of the "arbitrary data slot", but double the size - // because this is 64 bit instead of 32 bit - asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile") + unsafe fn target_record_sp_limit(_: uint) { } #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] unsafe fn target_record_sp_limit(limit: uint) { @@ -228,10 +224,7 @@ pub unsafe fn record_sp_limit(limit: uint) { asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile") } #[cfg(target_arch = "x86", target_os = "windows")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block - // store this inside of the "arbitrary data slot" - asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile") + unsafe fn target_record_sp_limit(_: uint) { } // mips, arm - Some brave soul can port these to inline asm, but it's over @@ -282,9 +275,7 @@ pub unsafe fn get_sp_limit() -> uint { } #[cfg(target_arch = "x86_64", target_os = "windows")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile"); - return limit; + return 1024; } #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { @@ -318,9 +309,7 @@ pub unsafe fn get_sp_limit() -> uint { } #[cfg(target_arch = "x86", target_os = "windows")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile"); - return limit; + return 1024; } // mips, arm - Some brave soul can port these to inline asm, but it's over diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 95be3191bab4..120ace1c36a5 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -136,7 +136,6 @@ mod imp { use os; use rand::Rng; use result::{Ok, Err}; - use rt::stack; use self::libc::{DWORD, BYTE, LPCSTR, BOOL}; use self::libc::types::os::arch::extra::{LONG_PTR}; use slice::MutableSlice; @@ -159,7 +158,6 @@ mod imp { static PROV_RSA_FULL: DWORD = 1; static CRYPT_SILENT: DWORD = 64; static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; - static NTE_BAD_SIGNATURE: DWORD = 0x80090006; #[allow(non_snake_case)] extern "system" { @@ -178,48 +176,12 @@ mod imp { /// Create a new `OsRng`. pub fn new() -> IoResult { let mut hcp = 0; - let mut ret = unsafe { + let ret = unsafe { CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT) }; - // FIXME #13259: - // It turns out that if we can't acquire a context with the - // NTE_BAD_SIGNATURE error code, the documentation states: - // - // The provider DLL signature could not be verified. Either the - // DLL or the digital signature has been tampered with. - // - // Sounds fishy, no? As it turns out, our signature can be bad - // because our Thread Information Block (TIB) isn't exactly what it - // expects. As to why, I have no idea. The only data we store in the - // TIB is the stack limit for each thread, but apparently that's - // enough to make the signature valid. - // - // Furthermore, this error only happens the *first* time we call - // CryptAcquireContext, so we don't have to worry about future - // calls. - // - // Anyway, the fix employed here is that if we see this error, we - // pray that we're not close to the end of the stack, temporarily - // set the stack limit to 0 (what the TIB originally was), acquire a - // context, and then reset the stack limit. - // - // Again, I'm not sure why this is the fix, nor why we're getting - // this error. All I can say is that this seems to allow libnative - // to progress where it otherwise would be hindered. Who knew? - if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE { - unsafe { - let limit = stack::get_sp_limit(); - stack::record_sp_limit(0); - ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR, - PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT); - stack::record_sp_limit(limit); - } - } - if ret == 0 { Err(IoError::last_error()) } else { diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index 7f2f9f9ece83..bbaa09bfac31 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -42,11 +42,17 @@ fn main() { let silent = Command::new(args[0].as_slice()).arg("silent").output().unwrap(); assert!(!silent.status.success()); let error = String::from_utf8_lossy(silent.error.as_slice()); - assert!(error.as_slice().contains("has overflowed its stack")); + // FIXME #17562: Windows is using stack probes and isn't wired up to print an error + if !cfg!(windows) { + assert!(error.as_slice().contains("has overflowed its stack")); + } let loud = Command::new(args[0].as_slice()).arg("loud").output().unwrap(); assert!(!loud.status.success()); let error = String::from_utf8_lossy(silent.error.as_slice()); - assert!(error.as_slice().contains("has overflowed its stack")); + // FIXME #17562: Windows is using stack probes and isn't wired up to print an error + if !cfg!(windows) { + assert!(error.as_slice().contains("has overflowed its stack")); + } } } From 3b3d7021e4a2bccace8816bb24eec33eac09c9f2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 25 Sep 2014 13:01:32 -0700 Subject: [PATCH 3/5] Add test for #13259. Closes #13259 and #14742 --- .../run-pass/issue-13259-windows-tcb-trash.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/run-pass/issue-13259-windows-tcb-trash.rs diff --git a/src/test/run-pass/issue-13259-windows-tcb-trash.rs b/src/test/run-pass/issue-13259-windows-tcb-trash.rs new file mode 100644 index 000000000000..94953730df89 --- /dev/null +++ b/src/test/run-pass/issue-13259-windows-tcb-trash.rs @@ -0,0 +1,28 @@ +extern crate libc; +use libc::{c_void, LPVOID, DWORD}; +use libc::types::os::arch::extra::LPWSTR; + +extern "system" { + fn FormatMessageW(flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void) + -> DWORD; +} + +fn test() { + let mut buf: [u16, ..50] = [0, ..50]; + let ret = unsafe { + FormatMessageW(0x1000, 0 as *mut c_void, 1, 0x400, + buf.as_mut_ptr(), buf.len() as u32, 0 as *const c_void) + }; + // On some 32-bit Windowses (Win7-8 at least) this will fail with segmented + // stacks taking control of pvArbitrary + assert!(ret != 0); +} +fn main() { + test() +} \ No newline at end of file From 2acd6b77413817d89a067603fe54fdc9baa66df0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 26 Sep 2014 09:41:40 -0700 Subject: [PATCH 4/5] Remove windows TCB hack from rustdoc --- src/librustdoc/lib.rs | 42 +----------------------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 237a88ded711..71d00e50af83 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -89,47 +89,7 @@ local_data_key!(pub analysiskey: core::CrateAnalysis) type Output = (clean::Crate, Vec ); pub fn main() { - // Why run rustdoc in a separate task? That's a good question! - // - // We first begin our adventure at the ancient commit of e7c4fb69. In this - // commit it was discovered that the stack limit frobbing on windows ended - // up causing some syscalls to fail. This was worked around manually in the - // relevant location. - // - // Our journey now continues with #13259 where it was discovered that this - // stack limit frobbing has the ability to affect nearly any syscall. Note - // that the key idea here is that there is currently no knowledge as to why - // this is happening or how to preserve it, fun times! - // - // Now we continue along to #16275 where it was discovered that --test on - // windows didn't work at all! Yet curiously rustdoc worked without --test. - // The exact reason that #16275 cropped up is that during the expansion - // phase the compiler attempted to open libstd to read out its macros. This - // invoked the LLVMRustOpenArchive shim which in turned went to LLVM to go - // open a file and read it. Lo and behold this function returned an error! - // It was then discovered that when the same fix mentioned in #13259 was - // applied, the error went away. The plot thickens! - // - // Remember that rustdoc works without --test, which raises the question of - // how because the --test and non --test paths are almost identical. The - // first thing both paths do is parse and expand a crate! It turns out that - // the difference is that --test runs on the *main task* while the normal - // path runs in subtask. It turns out that running --test in a sub task also - // fixes the problem! - // - // So, in summary, it is unknown why this is necessary, what it is - // preventing, or what the actual bug is. In the meantime, this allows - // --test to work on windows, which seems good, right? Fun times. - let (tx, rx) = channel(); - spawn(proc() { - std::os::set_exit_status(main_args(std::os::args().as_slice())); - tx.send(()); - }); - - // If the task failed, set an error'd exit status - if rx.recv_opt().is_err() { - std::os::set_exit_status(std::rt::DEFAULT_ERROR_CODE); - } + std::os::set_exit_status(main_args(std::os::args().as_slice())); } pub fn opts() -> Vec { From bdeb1d738676d671b92a7057e3ba1791fa012351 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 29 Sep 2014 11:34:53 -0700 Subject: [PATCH 5/5] Ignore win-tcb test on non-windows --- .../run-pass/issue-13259-windows-tcb-trash.rs | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/test/run-pass/issue-13259-windows-tcb-trash.rs b/src/test/run-pass/issue-13259-windows-tcb-trash.rs index 94953730df89..1a909db92e32 100644 --- a/src/test/run-pass/issue-13259-windows-tcb-trash.rs +++ b/src/test/run-pass/issue-13259-windows-tcb-trash.rs @@ -1,28 +1,48 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + extern crate libc; -use libc::{c_void, LPVOID, DWORD}; -use libc::types::os::arch::extra::LPWSTR; -extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const c_void) - -> DWORD; +#[cfg(windows)] +mod imp { + use libc::{c_void, LPVOID, DWORD}; + use libc::types::os::arch::extra::LPWSTR; + + extern "system" { + fn FormatMessageW(flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void) + -> DWORD; + } + + pub fn test() { + let mut buf: [u16, ..50] = [0, ..50]; + let ret = unsafe { + FormatMessageW(0x1000, 0 as *mut c_void, 1, 0x400, + buf.as_mut_ptr(), buf.len() as u32, 0 as *const c_void) + }; + // On some 32-bit Windowses (Win7-8 at least) this will fail with segmented + // stacks taking control of pvArbitrary + assert!(ret != 0); + } } -fn test() { - let mut buf: [u16, ..50] = [0, ..50]; - let ret = unsafe { - FormatMessageW(0x1000, 0 as *mut c_void, 1, 0x400, - buf.as_mut_ptr(), buf.len() as u32, 0 as *const c_void) - }; - // On some 32-bit Windowses (Win7-8 at least) this will fail with segmented - // stacks taking control of pvArbitrary - assert!(ret != 0); +#[cfg(not(windows))] +mod imp { + pub fn test() { } } + fn main() { - test() -} \ No newline at end of file + imp::test() +}