128 lines · cpp
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-exception6//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 17using namespace clang;18using namespace CodeGen;19 20SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}21 22static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) {23 return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |24 SanitizerKind::HWAddress | SanitizerKind::MemTag |25 SanitizerKind::Type);26}27 28static 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 35void 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 97void 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 they114 // 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 125void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {126 reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);127}128