hctim created this revision.
hctim added reviewers: vitalybuka, kstoimenov.
Herald added a project: All.
hctim requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch adds generation of sanitizer metadata attributes (which were
added in D126100 <https://reviews.llvm.org/D126100>) to the clang frontend.

We still currently generate the `llvm.asan.globals` that's consumed by
the IR pass, but the plan is to eventually migrate off of that onto
purely debuginfo and these IR attributes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D126929

Files:
  clang/lib/CodeGen/CGDecl.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/SanitizerMetadata.cpp
  clang/lib/CodeGen/SanitizerMetadata.h
  clang/test/CodeGen/asan-globals.cpp
  clang/test/CodeGen/sanitize-init-order.cpp

Index: clang/test/CodeGen/sanitize-init-order.cpp
===================================================================
--- clang/test/CodeGen/sanitize-init-order.cpp
+++ 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}
Index: clang/test/CodeGen/asan-globals.cpp
===================================================================
--- clang/test/CodeGen/asan-globals.cpp
+++ 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
Index: clang/lib/CodeGen/SanitizerMetadata.h
===================================================================
--- clang/lib/CodeGen/SanitizerMetadata.h
+++ 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
Index: clang/lib/CodeGen/SanitizerMetadata.cpp
===================================================================
--- clang/lib/CodeGen/SanitizerMetadata.cpp
+++ 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<NoSanitizeAttr>()) {
+    NoSanitizeMask |= Attr->getMask();
+  }
+
+  if (D.hasAttr<DisableSanitizerInstrumentationAttr>()) {
+    NoSanitizeMask = SanitizerKind::All;
+  }
+
   std::string QualName;
   llvm::raw_string_ostream OS(QualName);
   D.printQualifiedName(OS);
 
-  bool IsExcluded = false;
-  for (auto Attr : D.specific_attrs<NoSanitizeAttr>())
-    if (Attr->getMask() & SanitizerKind::Address)
-      IsExcluded = true;
-  if (D.hasAttr<DisableSanitizerInstrumentationAttr>())
-    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) {
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ 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), "<string literal>",
+  SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), "<string literal>",
                                   QualType());
 
   return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ 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();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to