1 //===--- SanitizerMetadata.cpp - Ignored entities for sanitizers ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Class which emits metadata consumed by sanitizer instrumentation passes.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "SanitizerMetadata.h"
13 #include "CodeGenModule.h"
14 #include "clang/AST/Attr.h"
15 #include "clang/AST/Type.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/IR/Constants.h"
19 
20 using namespace clang;
21 using namespace CodeGen;
22 
23 SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
24 
25 static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) {
26   return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
27                      SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress |
28                      SanitizerKind::MemTag);
29 }
30 
31 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
32                                      SourceLocation Loc, StringRef Name,
33                                      QualType Ty, bool IsDynInit,
34                                      bool IsExcluded) {
35   IsDynInit &= !CGM.isInNoSanitizeList(GV, Loc, Ty, "init");
36   IsExcluded |= CGM.isInNoSanitizeList(GV, Loc, Ty);
37 
38   llvm::Metadata *LocDescr = nullptr;
39   llvm::Metadata *GlobalName = nullptr;
40   llvm::LLVMContext &VMContext = CGM.getLLVMContext();
41   if (!IsExcluded) {
42     // Don't generate source location and global name if it is on
43     // the NoSanitizeList - it won't be instrumented anyway.
44     LocDescr = getLocationMetadata(Loc);
45     if (!Name.empty())
46       GlobalName = llvm::MDString::get(VMContext, Name);
47   }
48 
49   llvm::Metadata *GlobalMetadata[] = {
50       llvm::ConstantAsMetadata::get(GV), LocDescr, GlobalName,
51       llvm::ConstantAsMetadata::get(
52           llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit)),
53       llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
54           llvm::Type::getInt1Ty(VMContext), IsExcluded))};
55 
56   llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata);
57   llvm::NamedMDNode *AsanGlobals =
58       CGM.getModule().getOrInsertNamedMetadata("llvm.asan.globals");
59   AsanGlobals->addOperand(ThisGlobal);
60 }
61 
62 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
63                                      bool IsDynInit) {
64   if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
65     return;
66   std::string QualName;
67   llvm::raw_string_ostream OS(QualName);
68   D.printQualifiedName(OS);
69 
70   auto getNoSanitizeMask = [](const VarDecl &D) {
71     if (D.hasAttr<DisableSanitizerInstrumentationAttr>())
72       return SanitizerKind::All;
73 
74     SanitizerMask NoSanitizeMask;
75     for (auto *Attr : D.specific_attrs<NoSanitizeAttr>())
76       NoSanitizeMask |= Attr->getMask();
77 
78     return NoSanitizeMask;
79   };
80   reportGlobal(GV, D.getLocation(), OS.str(), D.getType(), IsDynInit,
81                SanitizerSet{getNoSanitizeMask(D)}.has(SanitizerKind::Address));
82 }
83 
84 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
85                                      SourceLocation Loc, StringRef Name,
86                                      QualType Ty, bool IsDynInit) {
87   if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
88     return;
89   reportGlobal(GV, Loc, Name, Ty, IsDynInit, false);
90 }
91 
92 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
93   // For now, just make sure the global is not modified by the ASan
94   // instrumentation.
95   if (isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
96     reportGlobal(GV, SourceLocation(), "", QualType(), false, true);
97 }
98 
99 void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) {
100   I->setMetadata(llvm::LLVMContext::MD_nosanitize,
101                  llvm::MDNode::get(CGM.getLLVMContext(), None));
102 }
103 
104 llvm::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) {
105   PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc);
106   if (!PLoc.isValid())
107     return nullptr;
108   llvm::LLVMContext &VMContext = CGM.getLLVMContext();
109   llvm::Metadata *LocMetadata[] = {
110       llvm::MDString::get(VMContext, PLoc.getFilename()),
111       llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
112           llvm::Type::getInt32Ty(VMContext), PLoc.getLine())),
113       llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
114           llvm::Type::getInt32Ty(VMContext), PLoc.getColumn())),
115   };
116   return llvm::MDNode::get(VMContext, LocMetadata);
117 }
118