Skip to content

Consistently use LLVM lifetime markers during codegen #72178

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

Merged
merged 1 commit into from
May 17, 2020
Merged
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
5 changes: 3 additions & 2 deletions src/librustc_codegen_llvm/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
config.vectorize_slp,
config.vectorize_loop,
config.no_builtins,
config.emit_lifetime_markers,
sanitizer_options.as_ref(),
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
Expand Down Expand Up @@ -934,10 +935,10 @@ pub unsafe fn with_llvm_pmb(
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
}
(llvm::CodeGenOptLevel::None, ..) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
}
(llvm::CodeGenOptLevel::Less, ..) => {
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
}
(llvm::CodeGenOptLevel::Default, ..) => {
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
Expand Down
10 changes: 1 addition & 9 deletions src/librustc_codegen_llvm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::{self, Sanitizer};
use rustc_target::abi::{self, Align, Size};
use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
Expand Down Expand Up @@ -1243,14 +1242,7 @@ impl Builder<'a, 'll, 'tcx> {
return;
}

let opts = &self.cx.sess().opts;
let emit = match opts.debugging_opts.sanitizer {
// Some sanitizer use lifetime intrinsics. When they are in use,
// emit lifetime intrinsics regardless of optimization level.
Some(Sanitizer::Address | Sanitizer::Memory) => true,
_ => opts.optimize != config::OptLevel::No,
};
if !emit {
if !self.cx().sess().emit_lifetime_markers() {
return;
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc_codegen_llvm/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2000,6 +2000,7 @@ extern "C" {
SLPVectorize: bool,
LoopVectorize: bool,
DisableSimplifyLibCalls: bool,
EmitLifetimeMarkers: bool,
SanitizerOptions: Option<&SanitizerOptions>,
PGOGenPath: *const c_char,
PGOUsePath: *const c_char,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_codegen_ssa/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ pub struct ModuleConfig {
pub merge_functions: bool,
pub inline_threshold: Option<usize>,
pub new_llvm_pass_manager: bool,
pub emit_lifetime_markers: bool,
}

impl ModuleConfig {
Expand Down Expand Up @@ -244,6 +245,7 @@ impl ModuleConfig {

inline_threshold: sess.opts.cg.inline_threshold,
new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
emit_lifetime_markers: sess.emit_lifetime_markers(),
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/librustc_session/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,16 @@ impl Session {
// then try to skip it where possible.
dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
}

/// Checks if LLVM lifetime markers should be emitted.
pub fn emit_lifetime_markers(&self) -> bool {
match self.opts.debugging_opts.sanitizer {
// AddressSanitizer uses lifetimes to detect use after scope bugs.
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
Some(Sanitizer::Address | Sanitizer::Memory) => true,
_ => self.opts.optimize != config::OptLevel::No,
}
}
}

pub fn build_session(
Expand Down
4 changes: 2 additions & 2 deletions src/rustllvm/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ LLVMRustOptimizeWithNewPassManager(
LLVMRustOptStage OptStage,
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
bool DisableSimplifyLibCalls,
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
LLVMRustSanitizerOptions *SanitizerOptions,
const char *PGOGenPath, const char *PGOUsePath,
void* LlvmSelfProfiler,
Expand Down Expand Up @@ -853,7 +853,7 @@ LLVMRustOptimizeWithNewPassManager(
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}

MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false));
MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));

#if LLVM_VERSION_GE(10, 0)
if (PGOOpt) {
Expand Down
31 changes: 31 additions & 0 deletions src/test/ui/sanitize/issue-72154-lifetime-markers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Regression test for issue 72154, where the use of AddressSanitizer enabled
// emission of lifetime markers during codegen, while at the same time asking
// always inliner pass not to insert them. This eventually lead to a
// miscompilation which was subsequently detected by AddressSanitizer as UB.
//
// needs-sanitizer-support
// only-x86_64
//
// compile-flags: -Copt-level=0 -Zsanitizer=address
// run-pass

pub struct Wrap {
pub t: [usize; 1]
}

impl Wrap {
#[inline(always)]
pub fn new(t: [usize; 1]) -> Self {
Wrap { t }
}
}

#[inline(always)]
pub fn assume_init() -> [usize; 1] {
[1234]
}

fn main() {
let x: [usize; 1] = assume_init();
Wrap::new(x);
}