Skip to content

Commit cd72f2e

Browse files
committed
Auto merge of #42816 - alexcrichton:probestack, r=nikomatsakis
rustc: Implement stack probes for x86 This commit implements stack probes on x86/x86_64 using the freshly landed support upstream in LLVM. The purpose of stack probes here are to guarantee a segfault on stack overflow rather than having a chance of running over the guard page already present on all threads by accident. At this time there's no support for any other architecture because LLVM itself does not have support for other architectures.
2 parents 54fc9e4 + 5dbd97d commit cd72f2e

32 files changed

+170
-3
lines changed

src/librustc_back/target/i386_apple_ios.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub fn target() -> TargetResult {
2626
linker_flavor: LinkerFlavor::Gcc,
2727
options: TargetOptions {
2828
max_atomic_width: Some(64),
29+
stack_probes: true,
2930
.. base
3031
}
3132
})

src/librustc_back/target/i686_apple_darwin.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "yonah".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-apple-darwin".to_string(),

src/librustc_back/target/i686_linux_android.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub fn target() -> TargetResult {
2222
// http://developer.android.com/ndk/guides/abis.html#x86
2323
base.cpu = "pentiumpro".to_string();
2424
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
25+
base.stack_probes = true;
2526

2627
Ok(Target {
2728
llvm_target: "i686-linux-android".to_string(),

src/librustc_back/target/i686_unknown_dragonfly.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-unknown-dragonfly".to_string(),

src/librustc_back/target/i686_unknown_freebsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-unknown-freebsd".to_string(),

src/librustc_back/target/i686_unknown_haiku.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-unknown-haiku".to_string(),

src/librustc_back/target/i686_unknown_linux_gnu.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-unknown-linux-gnu".to_string(),

src/librustc_back/target/i686_unknown_linux_musl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub fn target() -> TargetResult {
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
1919
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string());
20+
base.stack_probes = true;
2021

2122
// The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
2223
// implementation, apparently relies on frame pointers existing... somehow.

src/librustc_back/target/i686_unknown_netbsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-unknown-netbsdelf".to_string(),

src/librustc_back/target/i686_unknown_openbsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "pentium4".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "i686-unknown-openbsd".to_string(),

src/librustc_back/target/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,9 @@ pub struct TargetOptions {
409409

410410
/// Whether or not the CRT is statically linked by default.
411411
pub crt_static_default: bool,
412+
413+
/// Whether or not stack probes (__rust_probestack) are enabled
414+
pub stack_probes: bool,
412415
}
413416

414417
impl Default for TargetOptions {
@@ -466,6 +469,7 @@ impl Default for TargetOptions {
466469
panic_strategy: PanicStrategy::Unwind,
467470
abi_blacklist: vec![],
468471
crt_static_default: false,
472+
stack_probes: false,
469473
}
470474
}
471475
}
@@ -688,6 +692,7 @@ impl Target {
688692
key!(min_atomic_width, Option<u64>);
689693
try!(key!(panic_strategy, PanicStrategy));
690694
key!(crt_static_default, bool);
695+
key!(stack_probes, bool);
691696

692697
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
693698
for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -874,6 +879,7 @@ impl ToJson for Target {
874879
target_option_val!(max_atomic_width);
875880
target_option_val!(panic_strategy);
876881
target_option_val!(crt_static_default);
882+
target_option_val!(stack_probes);
877883

878884
if default.abi_blacklist != self.options.abi_blacklist {
879885
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()

src/librustc_back/target/x86_64_apple_darwin.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub fn target() -> TargetResult {
1717
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
1818
base.eliminate_frame_pointer = false;
1919
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
20+
base.stack_probes = true;
2021

2122
Ok(Target {
2223
llvm_target: "x86_64-apple-darwin".to_string(),

src/librustc_back/target/x86_64_apple_ios.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub fn target() -> TargetResult {
2626
linker_flavor: LinkerFlavor::Gcc,
2727
options: TargetOptions {
2828
max_atomic_width: Some(64),
29+
stack_probes: true,
2930
.. base
3031
}
3132
})

src/librustc_back/target/x86_64_linux_android.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub fn target() -> TargetResult {
1818
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
1919
base.max_atomic_width = Some(64);
2020
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
21+
base.stack_probes = true;
2122

2223
Ok(Target {
2324
llvm_target: "x86_64-linux-android".to_string(),

src/librustc_back/target/x86_64_rumprun_netbsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
2525
base.disable_redzone = true;
2626
base.no_default_libraries = false;
2727
base.exe_allocation_crate = None;
28+
base.stack_probes = true;
2829

2930
Ok(Target {
3031
llvm_target: "x86_64-rumprun-netbsd".to_string(),

src/librustc_back/target/x86_64_sun_solaris.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
1717
base.cpu = "x86-64".to_string();
1818
base.max_atomic_width = Some(64);
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-pc-solaris".to_string(),

src/librustc_back/target/x86_64_unknown_bitrig.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-bitrig".to_string(),

src/librustc_back/target/x86_64_unknown_dragonfly.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-dragonfly".to_string(),

src/librustc_back/target/x86_64_unknown_freebsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-freebsd".to_string(),

src/librustc_back/target/x86_64_unknown_fuchsia.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-fuchsia".to_string(),

src/librustc_back/target/x86_64_unknown_haiku.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-haiku".to_string(),

src/librustc_back/target/x86_64_unknown_linux_gnu.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-linux-gnu".to_string(),

src/librustc_back/target/x86_64_unknown_linux_musl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-linux-musl".to_string(),

src/librustc_back/target/x86_64_unknown_netbsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-netbsd".to_string(),

src/librustc_back/target/x86_64_unknown_openbsd.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-openbsd".to_string(),

src/librustc_back/target/x86_64_unknown_redox.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> TargetResult {
1616
base.cpu = "x86-64".to_string();
1717
base.max_atomic_width = Some(64);
1818
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
19+
base.stack_probes = true;
1920

2021
Ok(Target {
2122
llvm_target: "x86_64-unknown-redox".to_string(),

src/librustc_trans/attributes.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
1212
use std::ffi::{CStr, CString};
1313

14+
use rustc::session::config::Sanitizer;
15+
1416
use llvm::{self, Attribute, ValueRef};
1517
use llvm::AttributePlace::Function;
1618
pub use syntax::attr::{self, InlineAttr};
1719
use syntax::ast;
1820
use context::CrateContext;
1921

20-
2122
/// Mark LLVM function to use provided inline heuristic.
2223
#[inline]
2324
pub fn inline(val: ValueRef, inline: InlineAttr) {
@@ -69,13 +70,36 @@ pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) {
6970
}
7071
}
7172

73+
pub fn set_probestack(ccx: &CrateContext, llfn: ValueRef) {
74+
// Only use stack probes if the target specification indicates that we
75+
// should be using stack probes
76+
if !ccx.sess().target.target.options.stack_probes {
77+
return
78+
}
79+
80+
// Currently stack probes seem somewhat incompatible with the address
81+
// sanitizer. With asan we're already protected from stack overflow anyway
82+
// so we don't really need stack probes regardless.
83+
match ccx.sess().opts.debugging_opts.sanitizer {
84+
Some(Sanitizer::Address) => return,
85+
_ => {}
86+
}
87+
88+
// Flag our internal `__rust_probestack` function as the stack probe symbol.
89+
// This is defined in the `compiler-builtins` crate for each architecture.
90+
llvm::AddFunctionAttrStringValue(
91+
llfn, llvm::AttributePlace::Function,
92+
cstr("probe-stack\0"), cstr("__rust_probestack\0"));
93+
}
94+
7295
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
7396
/// attributes.
7497
pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
7598
use syntax::attr::*;
7699
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
77100

78101
set_frame_pointer_elimination(ccx, llfn);
102+
set_probestack(ccx, llfn);
79103
let mut target_features = vec![];
80104
for attr in attrs {
81105
if attr.check_name("target_feature") {

src/llvm

src/test/codegen/stack-probes.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 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+
// ignore-arm
12+
// ignore-wasm
13+
// ignore-emscripten
14+
// ignore-windows
15+
// no-system-llvm
16+
// compile-flags: -C no-prepopulate-passes
17+
18+
#![crate_type = "lib"]
19+
20+
#[no_mangle]
21+
pub fn foo() {
22+
// CHECK: @foo() unnamed_addr #0
23+
// CHECK: attributes #0 = { {{.*}}"probe-stack"="__rust_probestack"{{.*}} }
24+
}

src/test/run-pass/stack-probes-lto.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 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+
// ignore-arm
12+
// ignore-wasm
13+
// ignore-emscripten
14+
// ignore-musl FIXME #31506
15+
// ignore-pretty
16+
// no-system-llvm
17+
// compile-flags: -C lto
18+
// no-prefer-dynamic
19+
20+
include!("stack-probes.rs");

0 commit comments

Comments
 (0)