From a61e13423e57380a08ea1475db57fc30cb7deb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 3 Mar 2020 00:00:00 +0000 Subject: [PATCH 1/3] Invoke OptimizerLastEPCallbacks in PreLinkThinLTO The default ThinLTO pre-link pipeline does not include optimizer last extension points. Thus, when using the new LLVM pass manager & ThinLTO & sanitizers on any opt-level different from zero, the sanitizer function passes would be omitted from the pipeline. Add optimizer last extensions points manually to the pipeline, but guard registration with stage check in the case this behaviour changes in the future. --- src/rustllvm/PassWrapper.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 65071c3ed86e0..90d24d20737db 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -868,8 +868,10 @@ LLVMRustOptimizeWithNewPassManager( } else { for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); + if (OptStage != LLVMRustOptStage::PreLinkThinLTO) { + for (const auto &C : OptimizerLastEPCallbacks) + PB.registerOptimizerLastEPCallback(C); + } switch (OptStage) { case LLVMRustOptStage::PreLinkNoLTO: @@ -877,6 +879,12 @@ LLVMRustOptimizeWithNewPassManager( break; case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); + if (!OptimizerLastEPCallbacks.empty()) { + FunctionPassManager FPM(DebugPassManager); + for (const auto &C : OptimizerLastEPCallbacks) + C(FPM, OptLevel); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } break; case LLVMRustOptStage::PreLinkFatLTO: MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); From 52c5f2a577bdc5181af96eb6a2f82cd502f92f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 3 Mar 2020 00:00:00 +0000 Subject: [PATCH 2/3] Add test for -Znew-llvm-pass-manager -Clto=thin -Zsanitizer=... Additionally verify that the current implementation of LLVM version check (which uses lexicographic ordering) is good enough to exclude versions before LLVM 9, where the new LLVM pass manager is unsupported. --- .../new-llvm-pass-manager-thin-lto.rs | 27 +++++++++++++++++++ src/tools/compiletest/src/header/tests.rs | 18 +++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs new file mode 100644 index 0000000000000..61d5d51cfd248 --- /dev/null +++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -0,0 +1,27 @@ +// Regression test for sanitizer function instrumentation passes not +// being run when compiling with new LLVM pass manager and ThinLTO. +// Note: The issue occured only on non-zero opt-level. +// +// min-llvm-version 9.0 +// needs-sanitizer-support +// only-x86_64 +// +// no-prefer-dynamic +// revisions: opt0 opt1 +// compile-flags: -Znew-llvm-pass-manager=yes -Zsanitizer=address -Clto=thin +//[opt0]compile-flags: -Copt-level=0 +//[opt1]compile-flags: -Copt-level=1 +// run-fail +// error-pattern: ERROR: AddressSanitizer: stack-use-after-scope + +static mut P: *mut usize = std::ptr::null_mut(); + +fn main() { + unsafe { + { + let mut x = 0; + P = &mut x; + } + std::ptr::write_volatile(P, 123); + } +} diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 38fa778219de2..6c478f7e29da4 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -109,6 +109,24 @@ fn no_system_llvm() { assert!(parse_rs(&config, "// no-system-llvm").ignore); } +#[test] +fn llvm_version() { + let mut config = config(); + + config.llvm_version = Some("8.1.2-rust".to_owned()); + assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore); + + config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned()); + assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore); + + config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned()); + assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore); + + // FIXME. + // config.llvm_version = Some("10.0.0-rust".to_owned()); + // assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore); +} + #[test] fn ignore_target() { let mut config = config(); From b0e288d9f1d8b0f4038bb955a68308b892d54ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 3 Mar 2020 00:00:00 +0000 Subject: [PATCH 3/3] Fix check for __msan_keep_going in sanitizer-recover test Match `@__msan_keep_going = weak_odr constant i32 1`. --- src/test/codegen/sanitizer-recover.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs index 9a583725b0bf0..05b4ab5653cc8 100644 --- a/src/test/codegen/sanitizer-recover.rs +++ b/src/test/codegen/sanitizer-recover.rs @@ -14,8 +14,8 @@ //[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -C lto=fat // // MSAN-NOT: @__msan_keep_going -// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}} constant i32 1 -// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}} constant i32 1 +// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}}constant i32 1 +// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1 // ASAN-LABEL: define i32 @penguin( // ASAN: call void @__asan_report_load4(i64 %0)