diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -473,7 +473,7 @@ LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment); CGM.setStaticLocalDeclAddress(&D, castedAddr); - CGM.getSanitizerMetadata()->reportGlobalToASan(var, D); + CGM.getSanitizerMetadata()->reportGlobal(var, D); // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); 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 @@ -2763,18 +2763,10 @@ bool CodeGenModule::isInNoSanitizeList(llvm::GlobalVariable *GV, SourceLocation Loc, QualType Ty, StringRef Category) const { - // For now globals can be ignored only in ASan and KASan. - const SanitizerMask EnabledAsanMask = - LangOpts.Sanitize.Mask & - (SanitizerKind::Address | SanitizerKind::KernelAddress | - SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress | - SanitizerKind::MemTag); - if (!EnabledAsanMask) - return false; const auto &NoSanitizeL = getContext().getNoSanitizeList(); - if (NoSanitizeL.containsGlobal(EnabledAsanMask, GV->getName(), Category)) + if (NoSanitizeL.containsGlobal(LangOpts.Sanitize.Mask, GV->getName(), Category)) return true; - if (NoSanitizeL.containsLocation(EnabledAsanMask, Loc, Category)) + if (NoSanitizeL.containsLocation(LangOpts.Sanitize.Mask, Loc, Category)) return true; // Check global type. if (!Ty.isNull()) { @@ -2786,7 +2778,7 @@ // Only record types (classes, structs etc.) are ignored. if (Ty->isRecordType()) { std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy()); - if (NoSanitizeL.containsType(EnabledAsanMask, TypeStr, Category)) + if (NoSanitizeL.containsType(LangOpts.Sanitize.Mask, TypeStr, Category)) return true; } } @@ -4792,7 +4784,7 @@ if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor); + SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) @@ -5678,7 +5670,7 @@ if (Entry) *Entry = GV; - SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "", + SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), "", QualType()); return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h --- a/clang/lib/CodeGen/SanitizerMetadata.h +++ b/clang/lib/CodeGen/SanitizerMetadata.h @@ -14,13 +14,15 @@ #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/IR/GlobalVariable.h" + namespace llvm { -class GlobalVariable; class Instruction; class MDNode; -} +} // namespace llvm namespace clang { class VarDecl; @@ -34,19 +36,24 @@ void operator=(const SanitizerMetadata &) = delete; CodeGenModule &CGM; + public: SanitizerMetadata(CodeGenModule &CGM); - void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D, - bool IsDynInit = false); - void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc, - StringRef Name, QualType Ty, bool IsDynInit = false, - bool IsExcluded = false); + void reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, + bool IsDynInit = false); + void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc, + StringRef Name, QualType Ty, bool IsDynInit = false, + SanitizerMask NoSanitizeMask = {}); void disableSanitizerForGlobal(llvm::GlobalVariable *GV); void disableSanitizerForInstruction(llvm::Instruction *I); + private: llvm::MDNode *getLocationMetadata(SourceLocation Loc); + void setASanSpecificMetadata(llvm::GlobalVariable::SanitizerMetadata &Meta, + llvm::GlobalVariable *GV, SourceLocation Loc, + QualType Ty, bool IsDynInit = false); }; -} // end namespace CodeGen -} // end namespace clang +} // end namespace CodeGen +} // end namespace clang #endif diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -17,29 +17,86 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/Constants.h" +using GlobalVariable = llvm::GlobalVariable; +using GVSanitizerMetadata = GlobalVariable::SanitizerMetadata; +using GlobalSanitizer = GVSanitizerMetadata::GlobalSanitizer; + using namespace clang; using namespace CodeGen; SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {} -static bool isAsanHwasanOrMemTag(const SanitizerSet& SS) { +static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) { return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress | SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress | SanitizerKind::MemTag); } -void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, - SourceLocation Loc, StringRef Name, - QualType Ty, bool IsDynInit, - bool IsExcluded) { - if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) - return; +void SanitizerMetadata::setASanSpecificMetadata(GVSanitizerMetadata &Meta, + GlobalVariable *GV, + SourceLocation Loc, QualType Ty, + bool IsDynInit) { IsDynInit &= !CGM.isInNoSanitizeList(GV, Loc, Ty, "init"); - IsExcluded |= CGM.isInNoSanitizeList(GV, Loc, Ty); + Meta.IsDynInit = IsDynInit; +} + +void SanitizerMetadata::reportGlobal(GlobalVariable *GV, SourceLocation Loc, + StringRef Name, QualType Ty, + bool IsDynInit, + SanitizerMask NoSanitizeMask) { + + GVSanitizerMetadata Meta; + if (GV->hasSanitizerMetadata()) + Meta = GV->getSanitizerMetadata(); + + bool IsExcluded = false; + if (CGM.isInNoSanitizeList(GV, Loc, Ty) || + NoSanitizeMask == SanitizerKind::All) { + Meta.Sanitizer |= GlobalSanitizer::NoSanitize; + IsExcluded = true; + } + + auto &SanTarget = CGM.getLangOpts().Sanitize; + + if (!isAsanHwasanOrMemTag(SanTarget)) + return; + + SanitizerSet NoSanitizeSet; + NoSanitizeSet.Mask = NoSanitizeMask; + + llvm::LLVMContext &VMContext = CGM.getLLVMContext(); + + if (SanTarget.hasOneOf(SanitizerKind::Address | + SanitizerKind::KernelAddress)) { + if (NoSanitizeSet.hasOneOf(SanitizerKind::Address | + SanitizerKind::KernelAddress) || + Meta.Sanitizer & GlobalSanitizer::NoAddress) { + Meta.Sanitizer |= GlobalSanitizer::NoAddress; + IsExcluded = true; + } + setASanSpecificMetadata(Meta, GV, Loc, Ty, IsDynInit); + } + if (SanTarget.hasOneOf(SanitizerKind::HWAddress | + SanitizerKind::KernelHWAddress)) { + if (NoSanitizeSet.hasOneOf(SanitizerKind::HWAddress | + SanitizerKind::KernelHWAddress) || + Meta.Sanitizer & GlobalSanitizer::NoHWAddress) { + Meta.Sanitizer |= GlobalSanitizer::NoHWAddress; + IsExcluded = true; + } + } + if (SanTarget.hasOneOf(SanitizerKind::MemTag)) { + if (NoSanitizeSet.hasOneOf(SanitizerKind::MemTag) || + Meta.Sanitizer & GlobalSanitizer::NoMemtag) { + Meta.Sanitizer |= GlobalSanitizer::NoMemtag; + IsExcluded = true; + } + } + + GV->setSanitizerMetadata(Meta); llvm::Metadata *LocDescr = nullptr; llvm::Metadata *GlobalName = nullptr; - llvm::LLVMContext &VMContext = CGM.getLLVMContext(); if (!IsExcluded) { // Don't generate source location and global name if it is on // the NoSanitizeList - it won't be instrumented anyway. @@ -50,8 +107,8 @@ llvm::Metadata *GlobalMetadata[] = { llvm::ConstantAsMetadata::get(GV), LocDescr, GlobalName, - llvm::ConstantAsMetadata::get( - llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt1Ty(VMContext), Meta.IsDynInit)), llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( llvm::Type::getInt1Ty(VMContext), IsExcluded))}; @@ -61,29 +118,27 @@ AsanGlobals->addOperand(ThisGlobal); } -void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, - const VarDecl &D, bool IsDynInit) { - if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) - return; +void SanitizerMetadata::reportGlobal(GlobalVariable *GV, const VarDecl &D, + bool IsDynInit) { + SanitizerMask NoSanitizeMask; + for (auto *Attr : D.specific_attrs()) { + NoSanitizeMask |= Attr->getMask(); + } + + if (D.hasAttr()) { + NoSanitizeMask = SanitizerKind::All; + } + std::string QualName; llvm::raw_string_ostream OS(QualName); D.printQualifiedName(OS); - bool IsExcluded = false; - for (auto Attr : D.specific_attrs()) - if (Attr->getMask() & SanitizerKind::Address) - IsExcluded = true; - if (D.hasAttr()) - IsExcluded = true; - reportGlobalToASan(GV, D.getLocation(), OS.str(), D.getType(), IsDynInit, - IsExcluded); + reportGlobal(GV, D.getLocation(), OS.str(), D.getType(), IsDynInit, + NoSanitizeMask); } -void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { - // For now, just make sure the global is not modified by the ASan - // instrumentation. - if (isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) - reportGlobalToASan(GV, SourceLocation(), "", QualType(), false, true); +void SanitizerMetadata::disableSanitizerForGlobal(GlobalVariable *GV) { + reportGlobal(GV, SourceLocation(), "", QualType(), false, SanitizerKind::All); } void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) { diff --git a/clang/test/CodeGen/asan-globals.cpp b/clang/test/CodeGen/asan-globals.cpp --- a/clang/test/CodeGen/asan-globals.cpp +++ b/clang/test/CodeGen/asan-globals.cpp @@ -23,6 +23,9 @@ const char *literal = "Hello, world!"; } +// ASAN: @dyn_init_global = global {{.*}}, sanitize_address_dyninit +// KASAN: @dyn_init_global = global {{.*}}, sanitize_address_dyninit + // ASAN: sectioned_global{{.*}} global { i32, [28 x i8] }{{.*}}, align 32 // KASAN: sectioned_global{{.*}} global i32 // ASAN: @__special_global{{.*}} global { i32, [28 x i8] }{{.*}}, align 32 diff --git a/clang/test/CodeGen/sanitize-init-order.cpp b/clang/test/CodeGen/sanitize-init-order.cpp --- a/clang/test/CodeGen/sanitize-init-order.cpp +++ b/clang/test/CodeGen/sanitize-init-order.cpp @@ -36,12 +36,29 @@ // Check that ASan init-order checking ignores structs with trivial default // constructor. + +// CHECK: @s1 = global +// CHECK-NOT: sanitize_address_dyninit +// CHECK: @s2 = global +// CHECK-NOT: sanitize_address_dyninit +// CHECK: @s3 = global {{.*}}, sanitize_address_dyninit +// CHECK: @{{.*}}array{{.*}} = global {{.*}}, sanitize_address_dyninit + // CHECK: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]+]], ![[GLOB_4:[0-9]+]] // CHECK: ![[GLOB_1]] = !{%struct.PODStruct* {{.*}}, i1 false, i1 false} // CHECK: ![[GLOB_2]] = !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false} // CHECK: ![[GLOB_3]] = !{%struct.PODWithCtorAndDtor* {{.*}}, i1 true, i1 false} // CHECK: ![[GLOB_4]] = !{{{.*}}class.NS::PODWithCtor{{.*}}, i1 true, i1 false} +// IGNORELIST: @s1 = global +// IGNORELIST-NOT: sanitize_address_dyninit +// IGNORELIST: @s2 = global +// IGNORELIST-NOT: sanitize_address_dyninit +// IGNORELIST: @s3 = global +// IGNORELIST-NOT: sanitize_address_dyninit +// IGNORELIST: @{{.*}}array{{.*}} = global +// IGNORELIST-NOT: sanitize_address_dyninit + // IGNORELIST: !llvm.asan.globals = !{![[GLOB_1:[0-9]+]], ![[GLOB_2:[0-9]+]], ![[GLOB_3:[0-9]+]], ![[GLOB_4:[0-9]+]]} // IGNORELIST: ![[GLOB_1]] = !{%struct.PODStruct* {{.*}}, i1 false, i1 false} // IGNORELIST: ![[GLOB_2]] = !{%struct.PODWithDtor* {{.*}}, i1 false, i1 false}