[Github] Label lldb-dap PRs (#125139)
[llvm-project.git] / clang / lib / CodeGen / SanitizerMetadata.cpp
blobb7b212ba46efd33eaacd1d56af4f3cd45482040b
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.
11 //===----------------------------------------------------------------------===//
12 #include "SanitizerMetadata.h"
13 #include "CodeGenModule.h"
14 #include "clang/AST/Attr.h"
15 #include "clang/AST/Type.h"
17 using namespace clang;
18 using namespace CodeGen;
20 SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
22 static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) {
23 return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
24 SanitizerKind::HWAddress | SanitizerKind::MemTag |
25 SanitizerKind::Type);
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;
35 static bool shouldTagGlobal(const llvm::GlobalVariable &G) {
36 // For now, don't instrument constant data, as it'll be in .rodata anyway. It
37 // may be worth instrumenting these in future to stop them from being used as
38 // gadgets.
39 if (G.getName().starts_with("llvm.") || G.isThreadLocal() || G.isConstant())
40 return false;
42 // Globals can be placed implicitly or explicitly in sections. There's two
43 // different types of globals that meet this criteria that cause problems:
44 // 1. Function pointers that are going into various init arrays (either
45 // explicitly through `__attribute__((section(<foo>)))` or implicitly
46 // through `__attribute__((constructor)))`, such as ".(pre)init(_array)",
47 // ".fini(_array)", ".ctors", and ".dtors". These function pointers end up
48 // overaligned and overpadded, making iterating over them problematic, and
49 // each function pointer is individually tagged (so the iteration over
50 // them causes SIGSEGV/MTE[AS]ERR).
51 // 2. Global variables put into an explicit section, where the section's name
52 // is a valid C-style identifier. The linker emits a `__start_<name>` and
53 // `__stop_<name>` symbol for the section, so that you can iterate over
54 // globals within this section. Unfortunately, again, these globals would
55 // be tagged and so iteration causes SIGSEGV/MTE[AS]ERR.
57 // To mitigate both these cases, and because specifying a section is rare
58 // outside of these two cases, disable MTE protection for globals in any
59 // section.
60 if (G.hasSection())
61 return false;
63 return true;
66 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
67 SourceLocation Loc, StringRef Name,
68 QualType Ty,
69 SanitizerMask NoSanitizeAttrMask,
70 bool IsDynInit) {
71 SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
72 if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument))
73 return;
75 FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask);
76 NoSanitizeAttrMask = expandKernelSanitizerMasks(NoSanitizeAttrMask);
77 SanitizerSet NoSanitizeAttrSet = {NoSanitizeAttrMask &
78 FsanitizeArgument.Mask};
80 llvm::GlobalVariable::SanitizerMetadata Meta;
81 if (GV->hasSanitizerMetadata())
82 Meta = GV->getSanitizerMetadata();
84 Meta.NoAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::Address);
85 Meta.NoAddress |= CGM.isInNoSanitizeList(
86 FsanitizeArgument.Mask & SanitizerKind::Address, GV, Loc, Ty);
88 Meta.NoHWAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::HWAddress);
89 Meta.NoHWAddress |= CGM.isInNoSanitizeList(
90 FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
92 if (shouldTagGlobal(*GV)) {
93 Meta.Memtag |= static_cast<bool>(FsanitizeArgument.Mask &
94 SanitizerKind::MemtagGlobals);
95 Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
96 Meta.Memtag &= !CGM.isInNoSanitizeList(
97 FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
98 } else {
99 Meta.Memtag = false;
102 Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&
103 FsanitizeArgument.has(SanitizerKind::Address) &&
104 !CGM.isInNoSanitizeList(SanitizerKind::Address |
105 SanitizerKind::KernelAddress,
106 GV, Loc, Ty, "init");
108 GV->setSanitizerMetadata(Meta);
110 if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
111 NoSanitizeAttrMask & SanitizerKind::Type)
112 return;
114 llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty);
115 if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
116 return;
118 llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
119 TBAAInfo};
121 // Metadata for the global already registered.
122 if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata))
123 return;
125 llvm::MDNode *ThisGlobal =
126 llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
127 llvm::NamedMDNode *TysanGlobals =
128 CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
129 TysanGlobals->addOperand(ThisGlobal);
132 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
133 bool IsDynInit) {
134 if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize))
135 return;
136 std::string QualName;
137 llvm::raw_string_ostream OS(QualName);
138 D.printQualifiedName(OS);
140 auto getNoSanitizeMask = [](const VarDecl &D) {
141 if (D.hasAttr<DisableSanitizerInstrumentationAttr>())
142 return SanitizerKind::All;
144 SanitizerMask NoSanitizeMask;
145 for (auto *Attr : D.specific_attrs<NoSanitizeAttr>())
146 NoSanitizeMask |= Attr->getMask();
148 // External definitions and incomplete types get handled at the place they
149 // are defined.
150 if (D.hasExternalStorage() || D.getType()->isIncompleteType())
151 NoSanitizeMask |= SanitizerKind::Type;
153 return NoSanitizeMask;
156 reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
157 IsDynInit);
160 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
161 reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);