Skip to content

Commit 0ec4b06

Browse files
committed
Auto merge of rust-lang#72178 - tmiasko:inliner-lifetimes, r=nikic
Consistently use LLVM lifetime markers during codegen Ensure that inliner inserts lifetime markers if they have been emitted during codegen. Otherwise if allocas from inlined functions are merged together, lifetime markers from one function might invalidate load & stores performed by the other one. Fixes rust-lang#72154.
2 parents dd927a5 + bbb63d4 commit 0ec4b06

File tree

7 files changed

+50
-13
lines changed

7 files changed

+50
-13
lines changed

src/librustc_codegen_llvm/back/write.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
394394
config.vectorize_slp,
395395
config.vectorize_loop,
396396
config.no_builtins,
397+
config.emit_lifetime_markers,
397398
sanitizer_options.as_ref(),
398399
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
399400
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
@@ -934,10 +935,10 @@ pub unsafe fn with_llvm_pmb(
934935
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
935936
}
936937
(llvm::CodeGenOptLevel::None, ..) => {
937-
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
938+
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
938939
}
939940
(llvm::CodeGenOptLevel::Less, ..) => {
940-
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
941+
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
941942
}
942943
(llvm::CodeGenOptLevel::Default, ..) => {
943944
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);

src/librustc_codegen_llvm/builder.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_data_structures::small_c_str::SmallCStr;
1818
use rustc_hir::def_id::DefId;
1919
use rustc_middle::ty::layout::TyAndLayout;
2020
use rustc_middle::ty::{self, Ty, TyCtxt};
21-
use rustc_session::config::{self, Sanitizer};
2221
use rustc_target::abi::{self, Align, Size};
2322
use rustc_target::spec::{HasTargetSpec, Target};
2423
use std::borrow::Cow;
@@ -1243,14 +1242,7 @@ impl Builder<'a, 'll, 'tcx> {
12431242
return;
12441243
}
12451244

1246-
let opts = &self.cx.sess().opts;
1247-
let emit = match opts.debugging_opts.sanitizer {
1248-
// Some sanitizer use lifetime intrinsics. When they are in use,
1249-
// emit lifetime intrinsics regardless of optimization level.
1250-
Some(Sanitizer::Address | Sanitizer::Memory) => true,
1251-
_ => opts.optimize != config::OptLevel::No,
1252-
};
1253-
if !emit {
1245+
if !self.cx().sess().emit_lifetime_markers() {
12541246
return;
12551247
}
12561248

src/librustc_codegen_llvm/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,6 +2000,7 @@ extern "C" {
20002000
SLPVectorize: bool,
20012001
LoopVectorize: bool,
20022002
DisableSimplifyLibCalls: bool,
2003+
EmitLifetimeMarkers: bool,
20032004
SanitizerOptions: Option<&SanitizerOptions>,
20042005
PGOGenPath: *const c_char,
20052006
PGOUsePath: *const c_char,

src/librustc_codegen_ssa/back/write.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ pub struct ModuleConfig {
110110
pub merge_functions: bool,
111111
pub inline_threshold: Option<usize>,
112112
pub new_llvm_pass_manager: bool,
113+
pub emit_lifetime_markers: bool,
113114
}
114115

115116
impl ModuleConfig {
@@ -244,6 +245,7 @@ impl ModuleConfig {
244245

245246
inline_threshold: sess.opts.cg.inline_threshold,
246247
new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
248+
emit_lifetime_markers: sess.emit_lifetime_markers(),
247249
}
248250
}
249251

src/librustc_session/session.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,16 @@ impl Session {
936936
// then try to skip it where possible.
937937
dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
938938
}
939+
940+
/// Checks if LLVM lifetime markers should be emitted.
941+
pub fn emit_lifetime_markers(&self) -> bool {
942+
match self.opts.debugging_opts.sanitizer {
943+
// AddressSanitizer uses lifetimes to detect use after scope bugs.
944+
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
945+
Some(Sanitizer::Address | Sanitizer::Memory) => true,
946+
_ => self.opts.optimize != config::OptLevel::No,
947+
}
948+
}
939949
}
940950

941951
pub fn build_session(

src/rustllvm/PassWrapper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ LLVMRustOptimizeWithNewPassManager(
717717
LLVMRustOptStage OptStage,
718718
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
719719
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
720-
bool DisableSimplifyLibCalls,
720+
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
721721
LLVMRustSanitizerOptions *SanitizerOptions,
722722
const char *PGOGenPath, const char *PGOUsePath,
723723
void* LlvmSelfProfiler,
@@ -853,7 +853,7 @@ LLVMRustOptimizeWithNewPassManager(
853853
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
854854
}
855855

856-
MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false));
856+
MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
857857

858858
#if LLVM_VERSION_GE(10, 0)
859859
if (PGOOpt) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Regression test for issue 72154, where the use of AddressSanitizer enabled
2+
// emission of lifetime markers during codegen, while at the same time asking
3+
// always inliner pass not to insert them. This eventually lead to a
4+
// miscompilation which was subsequently detected by AddressSanitizer as UB.
5+
//
6+
// needs-sanitizer-support
7+
// only-x86_64
8+
//
9+
// compile-flags: -Copt-level=0 -Zsanitizer=address
10+
// run-pass
11+
12+
pub struct Wrap {
13+
pub t: [usize; 1]
14+
}
15+
16+
impl Wrap {
17+
#[inline(always)]
18+
pub fn new(t: [usize; 1]) -> Self {
19+
Wrap { t }
20+
}
21+
}
22+
23+
#[inline(always)]
24+
pub fn assume_init() -> [usize; 1] {
25+
[1234]
26+
}
27+
28+
fn main() {
29+
let x: [usize; 1] = assume_init();
30+
Wrap::new(x);
31+
}

0 commit comments

Comments
 (0)