about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-10-10 07:52:00 +0000
committerbors <bors@rust-lang.org>2014-10-10 07:52:00 +0000
commit45797a0765e74d6972f194c5c79425cd65474d53 (patch)
treeed735d2e6ba239ccac645e393bb58030944aa62f
parentb74208bc12390b168e4a342de27d806639d89ffe (diff)
parentbc3831b7303b10781327d270dca2524cefdbff3d (diff)
downloadrust-45797a0765e74d6972f194c5c79425cd65474d53.tar.gz
rust-45797a0765e74d6972f194c5c79425cd65474d53.zip
auto merge of #17037 : kmcallister/rust/no-stack-check, r=thestinger
r? @brson 

Fixes #16980.
-rw-r--r--src/librustc/driver/config.rs2
-rw-r--r--src/librustc/lint/builtin.rs1
-rw-r--r--src/librustc/middle/trans/base.rs38
-rw-r--r--src/librustc/middle/trans/foreign.rs2
-rw-r--r--src/librustc/middle/trans/monomorphize.rs2
-rw-r--r--src/librustrt/thread.rs4
-rw-r--r--src/test/debuginfo/function-prologue-stepping-no-stack-check.rs (renamed from src/test/debuginfo/function-prologue-stepping-no-split-stack.rs)24
-rw-r--r--src/test/run-make/no-stack-check/Makefile15
-rw-r--r--src/test/run-make/no-stack-check/attr.rs25
-rw-r--r--src/test/run-make/no-stack-check/flag.rs24
-rw-r--r--src/test/run-pass/deprecated-no-split-stack.rs14
-rw-r--r--src/test/run-pass/smallest-hello-world.rs2
12 files changed, 121 insertions, 32 deletions
diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs
index fdd3c5b5a26..f5423b22fe2 100644
--- a/src/librustc/driver/config.rs
+++ b/src/librustc/driver/config.rs
@@ -390,6 +390,8 @@ cgoptions!(
         "divide crate into N units to optimize in parallel"),
     remark: Passes = (SomePasses(Vec::new()), parse_passes,
         "print remarks for these optimization passes (space separated, or \"all\")"),
+    no_stack_check: bool = (false, parse_bool,
+        "disable checks for stack exhaustion (a memory-safety hazard!)"),
 )
 
 pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 451d39fbc3d..e0e16390e35 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -571,6 +571,7 @@ impl LintPass for UnusedAttribute {
             "no_builtins",
             "no_mangle",
             "no_split_stack",
+            "no_stack_check",
             "packed",
             "static_assert",
             "thread_local",
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 8df5b375a81..692017b6750 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -204,7 +204,7 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
     // Function addresses in Rust are never significant, allowing functions to be merged.
     llvm::SetUnnamedAddr(llfn, true);
 
-    if ccx.is_split_stack_supported() {
+    if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
         set_split_stack(llfn);
     }
 
@@ -245,7 +245,7 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
     let f = decl_rust_fn(ccx, fn_ty, name);
 
     csearch::get_item_attrs(&ccx.sess().cstore, did, |attrs| {
-        set_llvm_fn_attrs(attrs.as_slice(), f)
+        set_llvm_fn_attrs(ccx, attrs.as_slice(), f)
     });
 
     ccx.externs().borrow_mut().insert(name.to_string(), f);
@@ -450,7 +450,7 @@ pub fn set_inline_hint(f: ValueRef) {
     llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute)
 }
 
-pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
+pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
     use syntax::attr::*;
     // Set the inline hint if there is one
     match find_inline_attr(attrs) {
@@ -460,16 +460,24 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
         InlineNone   => { /* fallthrough */ }
     }
 
-    // Add the no-split-stack attribute if requested
-    if contains_name(attrs, "no_split_stack") {
-        unset_split_stack(llfn);
-    }
-
-    if contains_name(attrs, "cold") {
-        unsafe {
-            llvm::LLVMAddFunctionAttribute(llfn,
-                                           llvm::FunctionIndex as c_uint,
-                                           llvm::ColdAttribute as uint64_t)
+    for attr in attrs.iter() {
+        let mut used = true;
+        match attr.name().get() {
+            "no_stack_check" => unset_split_stack(llfn),
+            "no_split_stack" => {
+                unset_split_stack(llfn);
+                ccx.sess().span_warn(attr.span,
+                                     "no_split_stack is a deprecated synonym for no_stack_check");
+            }
+            "cold" => unsafe {
+                llvm::LLVMAddFunctionAttribute(llfn,
+                                               llvm::FunctionIndex as c_uint,
+                                               llvm::ColdAttribute as uint64_t)
+            },
+            _ => used = false,
+        }
+        if used {
+            attr::mark_used(attr);
         }
     }
 }
@@ -2732,7 +2740,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                                                                    sym,
                                                                    i.id)
                     };
-                    set_llvm_fn_attrs(i.attrs.as_slice(), llfn);
+                    set_llvm_fn_attrs(ccx, i.attrs.as_slice(), llfn);
                     llfn
                 }
 
@@ -2874,7 +2882,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId,
     let sym = exported_name(ccx, id, mty, m.attrs.as_slice());
 
     let llfn = register_fn(ccx, m.span, sym, id, mty);
-    set_llvm_fn_attrs(m.attrs.as_slice(), llfn);
+    set_llvm_fn_attrs(ccx, m.attrs.as_slice(), llfn);
     llfn
 }
 
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 9cff7261806..e47adb6bc0e 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -640,7 +640,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
                id, t.repr(tcx));
 
         let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
-        base::set_llvm_fn_attrs(attrs, llfn);
+        base::set_llvm_fn_attrs(ccx, attrs, llfn);
         base::trans_fn(ccx, decl, body, llfn, param_substs, id, []);
         llfn
     }
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 12a2815cfef..e2c1bf1d8d1 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -149,7 +149,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
     };
     let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| {
         base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
-        set_llvm_fn_attrs(attrs, lldecl);
+        set_llvm_fn_attrs(ccx, attrs, lldecl);
 
         let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
         if is_first {
diff --git a/src/librustrt/thread.rs b/src/librustrt/thread.rs
index bef799d4178..9a67e5c72ac 100644
--- a/src/librustrt/thread.rs
+++ b/src/librustrt/thread.rs
@@ -39,9 +39,9 @@ static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
 
 // This is the starting point of rust os threads. The first thing we do
 // is make sure that we don't trigger __morestack (also why this has a
-// no_split_stack annotation), and then we extract the main function
+// no_stack_check annotation), and then we extract the main function
 // and invoke it.
-#[no_split_stack]
+#[no_stack_check]
 extern fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
     unsafe {
         stack::record_os_managed_stack_bounds(0, uint::MAX);
diff --git a/src/test/debuginfo/function-prologue-stepping-no-split-stack.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
index 05e2c5eb6c7..b68eec386a5 100644
--- a/src/test/debuginfo/function-prologue-stepping-no-split-stack.rs
+++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
@@ -11,7 +11,7 @@
 // ignore-android: FIXME(#10381)
 
 // This test case checks if function arguments already have the correct value when breaking at the
-// beginning of a function. Functions with the #[no_split_stack] attribute have the same prologue as
+// beginning of a function. Functions with the #[no_stack_check] attribute have the same prologue as
 // regular C functions compiled with GCC or Clang and therefore are better handled by GDB. As a
 // consequence, and as opposed to regular Rust functions, we can set the breakpoints via the
 // function name (and don't have to fall back on using line numbers). For LLDB this shouldn't make
@@ -246,7 +246,7 @@
 
 #![allow(unused_variable)]
 
-#[no_split_stack]
+#[no_stack_check]
 fn immediate_args(a: int, b: bool, c: f64) {
     ()
 }
@@ -262,42 +262,42 @@ struct BigStruct {
     h: u64
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn non_immediate_args(a: BigStruct, b: BigStruct) {
     ()
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn binding(a: i64, b: u64, c: f64) {
     let x = 0i;
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn assignment(mut a: u64, b: u64, c: f64) {
     a = b;
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn function_call(x: u64, y: u64, z: f64) {
     std::io::stdio::print("Hi!")
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn identifier(x: u64, y: u64, z: f64) -> u64 {
     x
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn return_expr(x: u64, y: u64, z: f64) -> u64 {
     return x;
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
     x + y
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn if_expr(x: u64, y: u64, z: f64) -> u64 {
     if x + y < 1000 {
         x
@@ -306,7 +306,7 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 {
     }
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
     while x + y < 1000 {
         x += z
@@ -314,7 +314,7 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
     return x;
 }
 
-#[no_split_stack]
+#[no_stack_check]
 fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
     loop {
         x += z;
diff --git a/src/test/run-make/no-stack-check/Makefile b/src/test/run-make/no-stack-check/Makefile
new file mode 100644
index 00000000000..561056d719e
--- /dev/null
+++ b/src/test/run-make/no-stack-check/Makefile
@@ -0,0 +1,15 @@
+-include ../tools.mk
+
+ifndef IS_WINDOWS
+all:
+	$(RUSTC) -O --emit asm attr.rs
+	! grep -q morestack $(TMPDIR)/attr.s
+	$(RUSTC) -O --emit asm flag.rs
+	grep -q morestack $(TMPDIR)/flag.s
+	$(RUSTC) -O --emit asm -C no-stack-check flag.rs
+	! grep -q morestack $(TMPDIR)/flag.s
+else
+# On Windows we use __chkstk and it only appears in functions with large allocations,
+# so this test wouldn't be reliable.
+all:
+endif
diff --git a/src/test/run-make/no-stack-check/attr.rs b/src/test/run-make/no-stack-check/attr.rs
new file mode 100644
index 00000000000..ef2db932b41
--- /dev/null
+++ b/src/test/run-make/no-stack-check/attr.rs
@@ -0,0 +1,25 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="lib"]
+
+extern {
+    // Prevents optimizing away the stack buffer.
+    // This symbol is undefined, but the code doesn't need to pass
+    // the linker.
+    fn black_box(ptr: *const u8);
+}
+
+#[no_stack_check]
+pub unsafe fn foo() {
+    // Make sure we use the stack
+    let x: [u8, ..50] = [0, ..50];
+    black_box(x.as_ptr());
+}
diff --git a/src/test/run-make/no-stack-check/flag.rs b/src/test/run-make/no-stack-check/flag.rs
new file mode 100644
index 00000000000..ee0364001e1
--- /dev/null
+++ b/src/test/run-make/no-stack-check/flag.rs
@@ -0,0 +1,24 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="lib"]
+
+extern {
+    // Prevents optimizing away the stack buffer.
+    // This symbol is undefined, but the code doesn't need to pass
+    // the linker.
+    fn black_box(ptr: *const u8);
+}
+
+pub unsafe fn foo() {
+    // Make sure we use the stack
+    let x: [u8, ..50] = [0, ..50];
+    black_box(x.as_ptr());
+}
diff --git a/src/test/run-pass/deprecated-no-split-stack.rs b/src/test/run-pass/deprecated-no-split-stack.rs
new file mode 100644
index 00000000000..31ba5dde815
--- /dev/null
+++ b/src/test/run-pass/deprecated-no-split-stack.rs
@@ -0,0 +1,14 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//~ WARNING no_split_stack is a deprecated synonym for no_stack_check
+#[no_split_stack]
+fn main() {
+}
diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs
index fdddac6bc37..65307c5e7b5 100644
--- a/src/test/run-pass/smallest-hello-world.rs
+++ b/src/test/run-pass/smallest-hello-world.rs
@@ -25,7 +25,7 @@ extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }
 #[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
 
 #[start]
-#[no_split_stack]
+#[no_stack_check]
 fn main(_: int, _: *const *const u8) -> int {
     unsafe {
         let (ptr, _): (*const u8, uint) = transmute("Hello!\0");