diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -353,7 +353,8 @@ static void addMemTagOptimizationPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createStackSafetyGlobalInfoWrapperPass(/*SetMetadata=*/true)); + PM.add(createStackSafetyGlobalInfoWrapperPass(/*SetMetadata=*/true, + /*Optional=*/true)); } static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, @@ -1346,7 +1347,7 @@ if (CodeGenOpts.OptimizationLevel > 0 && LangOpts.Sanitize.has(SanitizerKind::MemTag)) { - MPM.addPass(StackSafetyGlobalAnnotatorPass()); + MPM.addPass(StackSafetyGlobalAnnotatorPass(/*Optional=*/true)); } if (CodeGenOpts.OptimizationLevel == 0) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -574,6 +574,12 @@ CodeGenOpts.SanitizeCfiCanonicalJumpTables); } + if (CodeGenOpts.OptimizationLevel > 0 && + LangOpts.Sanitize.has(SanitizerKind::MemTag)) { + // Indicate that we want to StackSafety metadata. + getModule().addModuleFlag(llvm::Module::Override, "stack-safe", 1); + } + if (CodeGenOpts.CFProtectionReturn && Target.checkCFProtectionReturnSupported(getDiags())) { // Indicate that we want to instrument return control flow protection. diff --git a/clang/test/CodeGen/stack-safe-flag.cpp b/clang/test/CodeGen/stack-safe-flag.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/stack-safe-flag.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -O0 -triple aarch64-unknown-linux -fsanitize=memtag -emit-llvm -o - %s | FileCheck %s -check-prefix=NO +// RUN: %clang_cc1 -O1 -triple aarch64-unknown-linux -emit-llvm -o - %s | FileCheck %s -check-prefix=NO +// RUN: %clang_cc1 -O1 -triple aarch64-unknown-linux -fsanitize=memtag -emit-llvm -o - %s | FileCheck %s + +// NO-NOT: "stack-safe" +// CHECK: !{i32 4, !"stack-safe", i32 1} \ No newline at end of file diff --git a/clang/test/Driver/memtag_lto.c b/clang/test/Driver/memtag_lto.c --- a/clang/test/Driver/memtag_lto.c +++ b/clang/test/Driver/memtag_lto.c @@ -75,8 +75,7 @@ // RUN: -r %t.lto1.bc,w, \ // RUN: -r %t.lto2.bc,use,plx \ // RUN: -r %t.lto2.bc,z, -// FIXME: Must be -check-prefixes=XSAFE,YSAFE -// RUN: llvm-dis %t.lto.0.5.precodegen.bc -o - | FileCheck %s -check-prefixes=XUNSAFE,YSAFE +// RUN: llvm-dis %t.lto.0.5.precodegen.bc -o - | FileCheck %s -check-prefixes=XSAFE,YSAFE // Full LTO, new PM: both are safe. // RUN: %clang -fexperimental-new-pass-manager -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -c %s -flto=full -o %t.ltonewpm1.bc @@ -88,8 +87,7 @@ // RUN: -r %t.ltonewpm1.bc,w, \ // RUN: -r %t.ltonewpm2.bc,use,plx \ // RUN: -r %t.ltonewpm2.bc,z, -// FIXME: Must be -check-prefixes=XSAFE,YSAFE -// RUN: llvm-dis %t.ltonewpm.0.5.precodegen.bc -o - | FileCheck %s -check-prefixes=XUNSAFE,YSAFE +// RUN: llvm-dis %t.ltonewpm.0.5.precodegen.bc -o - | FileCheck %s -check-prefixes=XSAFE,YSAFE // Thin LTO: both are safe. // RUN: %clang -fno-experimental-new-pass-manager -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -c %s -flto=thin -o %t.thinlto1.bc diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h --- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h +++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h @@ -98,11 +98,16 @@ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +// Attaches StackSafety metadata to allocas. class StackSafetyGlobalAnnotatorPass : public PassInfoMixin { + bool Optional = false; + public: - explicit StackSafetyGlobalAnnotatorPass() {} + // When Optional is true the pass does nothing if no consumers of meta + // information is expected. + explicit StackSafetyGlobalAnnotatorPass(bool Optional) : Optional(Optional) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; @@ -110,12 +115,14 @@ /// (legacy pass manager). class StackSafetyGlobalInfoWrapperPass : public ModulePass { StackSafetyGlobalInfo SSGI; - bool SetMetadata; + bool SetMetadata = false; + bool Optional = false; public: static char ID; - StackSafetyGlobalInfoWrapperPass(bool SetMetadata = false); + explicit StackSafetyGlobalInfoWrapperPass(bool SetMetadata = false, + bool Optional = false); const StackSafetyGlobalInfo &getResult() const { return SSGI; } @@ -125,7 +132,11 @@ bool runOnModule(Module &M) override; }; -ModulePass *createStackSafetyGlobalInfoWrapperPass(bool SetMetadata); +// Attaches StackSafety metadata to allocas. +// When Optional is true the pass does nothing if no consumers of meta +// information is expected. +ModulePass *createStackSafetyGlobalInfoWrapperPass(bool SetMetadata, + bool Optional); } // end namespace llvm diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -603,6 +603,12 @@ return Changed; } +bool isMetadataNeeded(const Module &M) { + auto *CI = + mdconst::extract_or_null(M.getModuleFlag("stack-safe")); + return CI && CI->getZExtValue(); +} + } // end anonymous namespace StackSafetyInfo::StackSafetyInfo() = default; @@ -676,6 +682,8 @@ PreservedAnalyses StackSafetyGlobalAnnotatorPass::run(Module &M, ModuleAnalysisManager &AM) { + if (Optional && !isMetadataNeeded(M)) + return PreservedAnalyses::all(); auto &SSGI = AM.getResult(M); (void)setStackSafetyMetadata(M, SSGI); return PreservedAnalyses::all(); @@ -684,8 +692,8 @@ char StackSafetyGlobalInfoWrapperPass::ID = 0; StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass( - bool SetMetadata) - : ModulePass(ID), SetMetadata(SetMetadata) { + bool SetMetadata, bool Optional) + : ModulePass(ID), SetMetadata(SetMetadata), Optional(Optional) { initializeStackSafetyGlobalInfoWrapperPassPass( *PassRegistry::getPassRegistry()); } @@ -701,6 +709,9 @@ } bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { + if (Optional && !isMetadataNeeded(M)) + return false; + StackSafetyDataFlowAnalysis SSDFA( M, [this](Function &F) -> const StackSafetyInfo & { return getAnalysis(F).getResult(); @@ -709,8 +720,9 @@ return SetMetadata ? setStackSafetyMetadata(M, SSGI) : false; } -ModulePass *llvm::createStackSafetyGlobalInfoWrapperPass(bool SetMetadata) { - return new StackSafetyGlobalInfoWrapperPass(SetMetadata); +ModulePass *llvm::createStackSafetyGlobalInfoWrapperPass(bool SetMetadata, + bool Optional) { + return new StackSafetyGlobalInfoWrapperPass(SetMetadata, Optional); } static const char LocalPassArg[] = "stack-safety-local"; diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1288,6 +1288,9 @@ // is fixed. MPM.addPass(WholeProgramDevirtPass(ExportSummary, nullptr)); + // Add stack safety metatada if needed. + MPM.addPass(StackSafetyGlobalAnnotatorPass(true)); + // Stop here at -O1. if (Level == OptimizationLevel::O1) { // The LowerTypeTestsPass needs to run to lower type metadata and the diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -96,7 +96,7 @@ MODULE_PASS("kasan-module", ModuleAddressSanitizerPass(/*CompileKernel=*/true, false, true, false)) MODULE_PASS("sancov-module", ModuleSanitizerCoveragePass()) MODULE_PASS("poison-checking", PoisonCheckingPass()) -MODULE_PASS("stack-safety-annotator", StackSafetyGlobalAnnotatorPass()) +MODULE_PASS("stack-safety-annotator", StackSafetyGlobalAnnotatorPass(/*Optional=*/false)) #undef MODULE_PASS #ifndef CGSCC_ANALYSIS diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -22,6 +22,7 @@ #include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/ScopedNoAliasAA.h" +#include "llvm/Analysis/StackSafetyAnalysis.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TypeBasedAliasAnalysis.h" #include "llvm/IR/DataLayout.h" @@ -916,6 +917,10 @@ // Apply whole-program devirtualization and virtual constant propagation. PM.add(createWholeProgramDevirtPass(ExportSummary, nullptr)); + // Add stack safety metatada if needed. + PM.add(createStackSafetyGlobalInfoWrapperPass( + /*SetMetadata=*/true, /*Optional=*/true)); + // That's all we need at opt level 1. if (OptLevel == 1) return; diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll --- a/llvm/test/Other/new-pm-lto-defaults.ll +++ b/llvm/test/Other/new-pm-lto-defaults.ll @@ -61,6 +61,7 @@ ; CHECK-O-NEXT: Running analysis: CallGraphAnalysis ; CHECK-O-NEXT: Running pass: GlobalSplitPass ; CHECK-O-NEXT: Running pass: WholeProgramDevirtPass +; CHECK-O-NEXT: Running pass: StackSafetyGlobalAnnotatorPass ; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass ; CHECK-O2-NEXT: Running pass: GlobalOptPass ; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PromotePass>