From d9f0e88f19b691cd3e69be997c4ec75ea14c1db3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 10 Nov 2017 11:00:52 -0800 Subject: [PATCH 1/6] Enable TrapUnreachable in LLVM. Enable LLVM's TrapUnreachable flag, which tells it to translate `unreachable` instructions into hardware trap instructions, rather than allowing control flow to "fall through" into whatever code happens to follow it in memory. --- src/rustllvm/PassWrapper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index b397ad1e98f74..1fc8c42f1dd5e 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -398,6 +398,12 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; + // Tell LLVM to translate `unreachable` into an explicit trap instruction. + // This limits the extent of possible undefined behavior in some cases, as it + // prevents control flow from "falling through" into whatever code happens to + // be layed out next in memory. + Options.TrapUnreachable = true; + TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), RealCPU, Feature, Options, RM, CM, OptLevel); return wrap(TM); From 89652d66c9bd430e9c59bf5167f30c2016ae1e09 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 10 Nov 2017 12:52:06 -0800 Subject: [PATCH 2/6] Fix a spello. --- src/rustllvm/PassWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 1fc8c42f1dd5e..a04092cb5f92d 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -401,7 +401,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( // Tell LLVM to translate `unreachable` into an explicit trap instruction. // This limits the extent of possible undefined behavior in some cases, as it // prevents control flow from "falling through" into whatever code happens to - // be layed out next in memory. + // be laid out next in memory. Options.TrapUnreachable = true; TargetMachine *TM = TheTarget->createTargetMachine( From 626d93b86d3fe0c3f12f0299d72a8f65185ec268 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 10 Nov 2017 15:32:06 -0800 Subject: [PATCH 3/6] Update the "[run-make] run-make/intrinsic-unreachable" test. With rustc now emitting "ud2" on unreachable code, a "return nothing" sequence may take the same number of lines as an "unreachable" sequence in assembly code. This test is testing that intrinsics::unreachable() works by testing that it reduces the number of lines in the assembly code. Fix it by adding a return value, which requires an extra instruction in the reachable case, which provides the test what it's looking for. --- src/test/run-make/intrinsic-unreachable/exit-ret.rs | 4 +++- src/test/run-make/intrinsic-unreachable/exit-unreachable.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/intrinsic-unreachable/exit-ret.rs b/src/test/run-make/intrinsic-unreachable/exit-ret.rs index f5be5a055c3e0..3de079be2a549 100644 --- a/src/test/run-make/intrinsic-unreachable/exit-ret.rs +++ b/src/test/run-make/intrinsic-unreachable/exit-ret.rs @@ -11,10 +11,12 @@ #![feature(asm)] #![crate_type="lib"] -pub fn exit(n: usize) { +#[deny(unreachable_code)] +pub fn exit(n: usize) -> i32 { unsafe { // Pretend this asm is an exit() syscall. asm!("" :: "r"(n) :: "volatile"); // Can't actually reach this point, but rustc doesn't know that. } + 42 } diff --git a/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs b/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs index f58d2cd8f91d8..2a9dea1705aeb 100644 --- a/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs +++ b/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs @@ -13,10 +13,12 @@ use std::intrinsics; -pub fn exit(n: usize) -> ! { +#[allow(unreachable_code)] +pub fn exit(n: usize) -> i32 { unsafe { // Pretend this asm is an exit() syscall. asm!("" :: "r"(n) :: "volatile"); intrinsics::unreachable() } + 42 } From 365c159b8074a89c72cfab54e53fe767f3a63900 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 11 Nov 2017 06:41:45 -0800 Subject: [PATCH 4/6] Add comments to the intrinsic-unreachable test programs. The return value in these tests is just being used to generate extra code so that it can be detected in the test script, which is just counting lines in the assembly output. --- src/test/run-make/intrinsic-unreachable/exit-ret.rs | 3 +++ src/test/run-make/intrinsic-unreachable/exit-unreachable.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/test/run-make/intrinsic-unreachable/exit-ret.rs b/src/test/run-make/intrinsic-unreachable/exit-ret.rs index 3de079be2a549..1b8b644dd78e8 100644 --- a/src/test/run-make/intrinsic-unreachable/exit-ret.rs +++ b/src/test/run-make/intrinsic-unreachable/exit-ret.rs @@ -18,5 +18,8 @@ pub fn exit(n: usize) -> i32 { asm!("" :: "r"(n) :: "volatile"); // Can't actually reach this point, but rustc doesn't know that. } + // This return value is just here to generate some extra code for a return + // value, making it easier for the test script to detect whether the + // compiler deleted it. 42 } diff --git a/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs b/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs index 2a9dea1705aeb..de63809ab6638 100644 --- a/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs +++ b/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs @@ -20,5 +20,8 @@ pub fn exit(n: usize) -> i32 { asm!("" :: "r"(n) :: "volatile"); intrinsics::unreachable() } + // This return value is just here to generate some extra code for a return + // value, making it easier for the test script to detect whether the + // compiler deleted it. 42 } From 7b6b7649177db8edc9ef5c5075eb6cf9b00d8a9d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 11 Nov 2017 07:08:00 -0800 Subject: [PATCH 5/6] Control LLVM's TrapUnreachable feature through rustc's TargetOptions. --- src/librustc_back/target/mod.rs | 7 +++++++ src/librustc_llvm/ffi.rs | 3 ++- src/librustc_trans/back/write.rs | 2 ++ src/rustllvm/PassWrapper.cpp | 14 ++++++++------ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 8fd4aad89c643..d60d6438b4d61 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -435,6 +435,10 @@ pub struct TargetOptions { /// Default number of codegen units to use in debug mode pub default_codegen_units: Option, + + /// Whether to generate trap instructions in places where optimization would + /// otherwise produce control flow that falls through into unrelated memory. + pub trap_unreachable: bool, } impl Default for TargetOptions { @@ -498,6 +502,7 @@ impl Default for TargetOptions { stack_probes: false, min_global_align: None, default_codegen_units: None, + trap_unreachable: true, } } } @@ -739,6 +744,7 @@ impl Target { key!(stack_probes, bool); key!(min_global_align, Option); key!(default_codegen_units, Option); + key!(trap_unreachable, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -932,6 +938,7 @@ impl ToJson for Target { target_option_val!(stack_probes); target_option_val!(min_global_align); target_option_val!(default_codegen_units); + target_option_val!(trap_unreachable); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index ac0e4dde0c102..24c3963fbc4b3 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1605,7 +1605,8 @@ extern "C" { UseSoftFP: bool, PositionIndependentExecutable: bool, FunctionSections: bool, - DataSections: bool) + DataSections: bool, + TrapUnreachable: bool) -> TargetMachineRef; pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index d59d8ca1a7801..e443f13a7a1ca 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -196,6 +196,7 @@ pub fn target_machine_factory(sess: &Session) let cpu = CString::new(cpu.as_bytes()).unwrap(); let features = CString::new(target_feature(sess).as_bytes()).unwrap(); let is_pie_binary = is_pie_binary(sess); + let trap_unreachable = sess.target.target.options.trap_unreachable; Arc::new(move || { let tm = unsafe { @@ -208,6 +209,7 @@ pub fn target_machine_factory(sess: &Session) is_pie_binary, ffunction_sections, fdata_sections, + trap_unreachable, ) }; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a04092cb5f92d..b4116c96ba130 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -366,7 +366,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, - bool DataSections) { + bool DataSections, bool TrapUnreachable) { auto CM = fromRust(RustCM); auto OptLevel = fromRust(RustOptLevel); @@ -398,11 +398,13 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; - // Tell LLVM to translate `unreachable` into an explicit trap instruction. - // This limits the extent of possible undefined behavior in some cases, as it - // prevents control flow from "falling through" into whatever code happens to - // be laid out next in memory. - Options.TrapUnreachable = true; + if (TrapUnreachable) { + // Tell LLVM to translate `unreachable` into an explicit trap instruction. + // This limits the extent of possible undefined behavior in some cases, as + // it prevents control flow from "falling through" into whatever code + // happens to be laid out next in memory. + Options.TrapUnreachable = true; + } TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), RealCPU, Feature, Options, RM, CM, OptLevel); From ac48348db85d0ce9efdc450ab52837dcfc42a932 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 15 Nov 2017 16:07:48 -0800 Subject: [PATCH 6/6] Update the compiler-builtins to latest master. --- src/libcompiler_builtins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 0b9844764ea1f..f5532b22b5d74 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 0b9844764ea1f99ea11a7917a4f3ba7fd2db775c +Subproject commit f5532b22b5d741f3ea207b5b07e3e1ca63476f9b