Skip to content

Commit 45797a0

Browse files
committed
auto merge of #17037 : kmcallister/rust/no-stack-check, r=thestinger
r? @brson Fixes #16980.
2 parents b74208b + bc3831b commit 45797a0

File tree

12 files changed

+121
-32
lines changed

12 files changed

+121
-32
lines changed

src/librustc/driver/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ cgoptions!(
390390
"divide crate into N units to optimize in parallel"),
391391
remark: Passes = (SomePasses(Vec::new()), parse_passes,
392392
"print remarks for these optimization passes (space separated, or \"all\")"),
393+
no_stack_check: bool = (false, parse_bool,
394+
"disable checks for stack exhaustion (a memory-safety hazard!)"),
393395
)
394396

395397
pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions

src/librustc/lint/builtin.rs

+1
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ impl LintPass for UnusedAttribute {
571571
"no_builtins",
572572
"no_mangle",
573573
"no_split_stack",
574+
"no_stack_check",
574575
"packed",
575576
"static_assert",
576577
"thread_local",

src/librustc/middle/trans/base.rs

+23-15
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
204204
// Function addresses in Rust are never significant, allowing functions to be merged.
205205
llvm::SetUnnamedAddr(llfn, true);
206206

207-
if ccx.is_split_stack_supported() {
207+
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
208208
set_split_stack(llfn);
209209
}
210210

@@ -245,7 +245,7 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
245245
let f = decl_rust_fn(ccx, fn_ty, name);
246246

247247
csearch::get_item_attrs(&ccx.sess().cstore, did, |attrs| {
248-
set_llvm_fn_attrs(attrs.as_slice(), f)
248+
set_llvm_fn_attrs(ccx, attrs.as_slice(), f)
249249
});
250250

251251
ccx.externs().borrow_mut().insert(name.to_string(), f);
@@ -450,7 +450,7 @@ pub fn set_inline_hint(f: ValueRef) {
450450
llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute)
451451
}
452452

453-
pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
453+
pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
454454
use syntax::attr::*;
455455
// Set the inline hint if there is one
456456
match find_inline_attr(attrs) {
@@ -460,16 +460,24 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
460460
InlineNone => { /* fallthrough */ }
461461
}
462462

463-
// Add the no-split-stack attribute if requested
464-
if contains_name(attrs, "no_split_stack") {
465-
unset_split_stack(llfn);
466-
}
467-
468-
if contains_name(attrs, "cold") {
469-
unsafe {
470-
llvm::LLVMAddFunctionAttribute(llfn,
471-
llvm::FunctionIndex as c_uint,
472-
llvm::ColdAttribute as uint64_t)
463+
for attr in attrs.iter() {
464+
let mut used = true;
465+
match attr.name().get() {
466+
"no_stack_check" => unset_split_stack(llfn),
467+
"no_split_stack" => {
468+
unset_split_stack(llfn);
469+
ccx.sess().span_warn(attr.span,
470+
"no_split_stack is a deprecated synonym for no_stack_check");
471+
}
472+
"cold" => unsafe {
473+
llvm::LLVMAddFunctionAttribute(llfn,
474+
llvm::FunctionIndex as c_uint,
475+
llvm::ColdAttribute as uint64_t)
476+
},
477+
_ => used = false,
478+
}
479+
if used {
480+
attr::mark_used(attr);
473481
}
474482
}
475483
}
@@ -2732,7 +2740,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
27322740
sym,
27332741
i.id)
27342742
};
2735-
set_llvm_fn_attrs(i.attrs.as_slice(), llfn);
2743+
set_llvm_fn_attrs(ccx, i.attrs.as_slice(), llfn);
27362744
llfn
27372745
}
27382746

@@ -2874,7 +2882,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId,
28742882
let sym = exported_name(ccx, id, mty, m.attrs.as_slice());
28752883

28762884
let llfn = register_fn(ccx, m.span, sym, id, mty);
2877-
set_llvm_fn_attrs(m.attrs.as_slice(), llfn);
2885+
set_llvm_fn_attrs(ccx, m.attrs.as_slice(), llfn);
28782886
llfn
28792887
}
28802888

src/librustc/middle/trans/foreign.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
640640
id, t.repr(tcx));
641641

642642
let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
643-
base::set_llvm_fn_attrs(attrs, llfn);
643+
base::set_llvm_fn_attrs(ccx, attrs, llfn);
644644
base::trans_fn(ccx, decl, body, llfn, param_substs, id, []);
645645
llfn
646646
}

src/librustc/middle/trans/monomorphize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
149149
};
150150
let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| {
151151
base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
152-
set_llvm_fn_attrs(attrs, lldecl);
152+
set_llvm_fn_attrs(ccx, attrs, lldecl);
153153

154154
let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
155155
if is_first {

src/librustrt/thread.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
3939

4040
// This is the starting point of rust os threads. The first thing we do
4141
// is make sure that we don't trigger __morestack (also why this has a
42-
// no_split_stack annotation), and then we extract the main function
42+
// no_stack_check annotation), and then we extract the main function
4343
// and invoke it.
44-
#[no_split_stack]
44+
#[no_stack_check]
4545
extern fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
4646
unsafe {
4747
stack::record_os_managed_stack_bounds(0, uint::MAX);

src/test/debuginfo/function-prologue-stepping-no-split-stack.rs renamed to src/test/debuginfo/function-prologue-stepping-no-stack-check.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// ignore-android: FIXME(#10381)
1212

1313
// This test case checks if function arguments already have the correct value when breaking at the
14-
// beginning of a function. Functions with the #[no_split_stack] attribute have the same prologue as
14+
// beginning of a function. Functions with the #[no_stack_check] attribute have the same prologue as
1515
// regular C functions compiled with GCC or Clang and therefore are better handled by GDB. As a
1616
// consequence, and as opposed to regular Rust functions, we can set the breakpoints via the
1717
// function name (and don't have to fall back on using line numbers). For LLDB this shouldn't make
@@ -246,7 +246,7 @@
246246

247247
#![allow(unused_variable)]
248248

249-
#[no_split_stack]
249+
#[no_stack_check]
250250
fn immediate_args(a: int, b: bool, c: f64) {
251251
()
252252
}
@@ -262,42 +262,42 @@ struct BigStruct {
262262
h: u64
263263
}
264264

265-
#[no_split_stack]
265+
#[no_stack_check]
266266
fn non_immediate_args(a: BigStruct, b: BigStruct) {
267267
()
268268
}
269269

270-
#[no_split_stack]
270+
#[no_stack_check]
271271
fn binding(a: i64, b: u64, c: f64) {
272272
let x = 0i;
273273
}
274274

275-
#[no_split_stack]
275+
#[no_stack_check]
276276
fn assignment(mut a: u64, b: u64, c: f64) {
277277
a = b;
278278
}
279279

280-
#[no_split_stack]
280+
#[no_stack_check]
281281
fn function_call(x: u64, y: u64, z: f64) {
282282
std::io::stdio::print("Hi!")
283283
}
284284

285-
#[no_split_stack]
285+
#[no_stack_check]
286286
fn identifier(x: u64, y: u64, z: f64) -> u64 {
287287
x
288288
}
289289

290-
#[no_split_stack]
290+
#[no_stack_check]
291291
fn return_expr(x: u64, y: u64, z: f64) -> u64 {
292292
return x;
293293
}
294294

295-
#[no_split_stack]
295+
#[no_stack_check]
296296
fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
297297
x + y
298298
}
299299

300-
#[no_split_stack]
300+
#[no_stack_check]
301301
fn if_expr(x: u64, y: u64, z: f64) -> u64 {
302302
if x + y < 1000 {
303303
x
@@ -306,15 +306,15 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 {
306306
}
307307
}
308308

309-
#[no_split_stack]
309+
#[no_stack_check]
310310
fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
311311
while x + y < 1000 {
312312
x += z
313313
}
314314
return x;
315315
}
316316

317-
#[no_split_stack]
317+
#[no_stack_check]
318318
fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
319319
loop {
320320
x += z;
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-include ../tools.mk
2+
3+
ifndef IS_WINDOWS
4+
all:
5+
$(RUSTC) -O --emit asm attr.rs
6+
! grep -q morestack $(TMPDIR)/attr.s
7+
$(RUSTC) -O --emit asm flag.rs
8+
grep -q morestack $(TMPDIR)/flag.s
9+
$(RUSTC) -O --emit asm -C no-stack-check flag.rs
10+
! grep -q morestack $(TMPDIR)/flag.s
11+
else
12+
# On Windows we use __chkstk and it only appears in functions with large allocations,
13+
# so this test wouldn't be reliable.
14+
all:
15+
endif
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
#![crate_type="lib"]
12+
13+
extern {
14+
// Prevents optimizing away the stack buffer.
15+
// This symbol is undefined, but the code doesn't need to pass
16+
// the linker.
17+
fn black_box(ptr: *const u8);
18+
}
19+
20+
#[no_stack_check]
21+
pub unsafe fn foo() {
22+
// Make sure we use the stack
23+
let x: [u8, ..50] = [0, ..50];
24+
black_box(x.as_ptr());
25+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
#![crate_type="lib"]
12+
13+
extern {
14+
// Prevents optimizing away the stack buffer.
15+
// This symbol is undefined, but the code doesn't need to pass
16+
// the linker.
17+
fn black_box(ptr: *const u8);
18+
}
19+
20+
pub unsafe fn foo() {
21+
// Make sure we use the stack
22+
let x: [u8, ..50] = [0, ..50];
23+
black_box(x.as_ptr());
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
//~ WARNING no_split_stack is a deprecated synonym for no_stack_check
12+
#[no_split_stack]
13+
fn main() {
14+
}

src/test/run-pass/smallest-hello-world.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }
2525
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
2626

2727
#[start]
28-
#[no_split_stack]
28+
#[no_stack_check]
2929
fn main(_: int, _: *const *const u8) -> int {
3030
unsafe {
3131
let (ptr, _): (*const u8, uint) = transmute("Hello!\0");

0 commit comments

Comments
 (0)