xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/SanitizerMetadata.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 
17 using namespace clang;
18 using namespace CodeGen;
19 
20 SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
21 
22 static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) {
23   return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
24                      SanitizerKind::HWAddress | SanitizerKind::MemTag |
25                      SanitizerKind::Type);
26 }
27 
28 static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
29   if (Mask & (SanitizerKind::Address | SanitizerKind::KernelAddress))
30     Mask |= SanitizerKind::Address | SanitizerKind::KernelAddress;
31   // Note: KHWASan doesn't support globals.
32   return Mask;
33 }
34 
35 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
36                                      SourceLocation Loc, StringRef Name,
37                                      QualType Ty,
38                                      SanitizerMask NoSanitizeAttrMask,
39                                      bool IsDynInit) {
40   SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
41   if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument))
42     return;
43 
44   FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask);
45   NoSanitizeAttrMask = expandKernelSanitizerMasks(NoSanitizeAttrMask);
46   SanitizerSet NoSanitizeAttrSet = {NoSanitizeAttrMask &
47                                     FsanitizeArgument.Mask};
48 
49   llvm::GlobalVariable::SanitizerMetadata Meta;
50   if (GV->hasSanitizerMetadata())
51     Meta = GV->getSanitizerMetadata();
52 
53   Meta.NoAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::Address);
54   Meta.NoAddress |= CGM.isInNoSanitizeList(
55       FsanitizeArgument.Mask & SanitizerKind::Address, GV, Loc, Ty);
56 
57   Meta.NoHWAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::HWAddress);
58   Meta.NoHWAddress |= CGM.isInNoSanitizeList(
59       FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
60 
61   Meta.Memtag |=
62       static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals);
63   Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
64   Meta.Memtag &= !CGM.isInNoSanitizeList(
65       FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
66 
67   Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&
68                    FsanitizeArgument.has(SanitizerKind::Address) &&
69                    !CGM.isInNoSanitizeList(SanitizerKind::Address |
70                                                SanitizerKind::KernelAddress,
71                                            GV, Loc, Ty, "init");
72 
73   GV->setSanitizerMetadata(Meta);
74 
75   if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
76       NoSanitizeAttrMask & SanitizerKind::Type)
77     return;
78 
79   llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty);
80   if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
81     return;
82 
83   llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
84                                       TBAAInfo};
85 
86   // Metadata for the global already registered.
87   if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata))
88     return;
89 
90   llvm::MDNode *ThisGlobal =
91       llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
92   llvm::NamedMDNode *TysanGlobals =
93       CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
94   TysanGlobals->addOperand(ThisGlobal);
95 }
96 
97 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
98                                      bool IsDynInit) {
99   if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize))
100     return;
101   std::string QualName;
102   llvm::raw_string_ostream OS(QualName);
103   D.printQualifiedName(OS);
104 
105   auto getNoSanitizeMask = [](const VarDecl &D) {
106     if (D.hasAttr<DisableSanitizerInstrumentationAttr>())
107       return SanitizerKind::All;
108 
109     SanitizerMask NoSanitizeMask;
110     for (auto *Attr : D.specific_attrs<NoSanitizeAttr>())
111       NoSanitizeMask |= Attr->getMask();
112 
113     // External definitions and incomplete types get handled at the place they
114     // are defined.
115     if (D.hasExternalStorage() || D.getType()->isIncompleteType())
116       NoSanitizeMask |= SanitizerKind::Type;
117 
118     return NoSanitizeMask;
119   };
120 
121   reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
122                IsDynInit);
123 }
124 
125 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
126   reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
127 }
128