Skip to content

Rename no_split_stack to no_stack_check, and add a -C option #17037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/driver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ impl LintPass for UnusedAttribute {
"no_builtins",
"no_mangle",
"no_split_stack",
"no_stack_check",
"packed",
"static_assert",
"thread_local",
Expand Down
38 changes: 23 additions & 15 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -436,7 +436,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) {
Expand All @@ -446,16 +446,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);
}
}
}
Expand Down Expand Up @@ -2751,7 +2759,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
}

Expand Down Expand Up @@ -2893,7 +2901,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
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/librustrt/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -246,7 +246,7 @@

#![allow(unused_variable)]

#[no_split_stack]
#[no_stack_check]
fn immediate_args(a: int, b: bool, c: f64) {
()
}
Expand All @@ -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
Expand All @@ -306,15 +306,15 @@ 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
}
return x;
}

#[no_split_stack]
#[no_stack_check]
fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
loop {
x += z;
Expand Down
15 changes: 15 additions & 0 deletions src/test/run-make/no-stack-check/Makefile
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions src/test/run-make/no-stack-check/attr.rs
Original file line number Diff line number Diff line change
@@ -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());
}
24 changes: 24 additions & 0 deletions src/test/run-make/no-stack-check/flag.rs
Original file line number Diff line number Diff line change
@@ -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());
}
14 changes: 14 additions & 0 deletions src/test/run-pass/deprecated-no-split-stack.rs
Original file line number Diff line number Diff line change
@@ -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() {
}
2 changes: 1 addition & 1 deletion src/test/run-pass/smallest-hello-world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down