hctim created this revision. hctim added reviewers: vitalybuka, kstoimenov. Herald added subscribers: ormris, jdoerfert, steven_wu, hiraditya. Herald added a project: All. hctim requested review of this revision. Herald added projects: clang, LLVM. Herald added subscribers: llvm-commits, cfe-commits.
Plan is the migrate the global variable metadata for sanitizers, that's currently carried around generally in the 'llvm.asan.globals' section, onto the global variable itself. This patch adds the attribute and plumbs it through the LLVM IR and bitcode formats, but is a no-op other than that so far. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D126100 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-alias.cpp clang/test/CodeGen/asan-globals-odr.cpp clang/test/CodeGen/asan-static-odr.cpp clang/test/CodeGen/asan-strings.c llvm/docs/LangRef.rst llvm/include/llvm/AsmParser/LLParser.h llvm/include/llvm/AsmParser/LLToken.h llvm/include/llvm/IR/GlobalValue.h llvm/lib/AsmParser/LLLexer.cpp llvm/lib/AsmParser/LLParser.cpp llvm/lib/Bitcode/Reader/BitcodeReader.cpp llvm/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/lib/IR/AsmWriter.cpp llvm/lib/IR/Globals.cpp llvm/lib/IR/LLVMContextImpl.h
Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -1503,6 +1503,9 @@ /// Collection of per-GlobalValue partitions used in this context. DenseMap<const GlobalValue *, StringRef> GlobalValuePartitions; + DenseMap<const GlobalValue *, GlobalValue::SanitizerMetadata> + GlobalValueSanitizerMetadata; + /// DiscriminatorTable - This table maps file:line locations to an /// integer representing the next DWARF path discriminator to assign to /// instructions in different blocks at the same location. Index: llvm/lib/IR/Globals.cpp =================================================================== --- llvm/lib/IR/Globals.cpp +++ llvm/lib/IR/Globals.cpp @@ -67,6 +67,8 @@ setDLLStorageClass(Src->getDLLStorageClass()); setDSOLocal(Src->isDSOLocal()); setPartition(Src->getPartition()); + if (Src->hasSanitizerMetadata()) + setSanitizerMetadata(Src->getSanitizerMetadata()); } void GlobalValue::removeFromParent() { @@ -217,6 +219,18 @@ HasPartition = !S.empty(); } +using SanitizerMetadata = GlobalValue::SanitizerMetadata; +using GlobalSanitizer = GlobalValue::SanitizerMetadata::GlobalSanitizer; +const SanitizerMetadata &GlobalValue::getSanitizerMetadata() const { + assert(hasSanitizerMetadata()); + return getContext().pImpl->GlobalValueSanitizerMetadata[this]; +} + +void GlobalValue::setSanitizerMetadata(const SanitizerMetadata &Meta) { + getContext().pImpl->GlobalValueSanitizerMetadata[this] = Meta; + HasSanitizerMetadata = true; +} + StringRef GlobalObject::getSectionImpl() const { assert(hasSection()); return getContext().pImpl->GlobalObjectSections[this]; Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -100,6 +100,9 @@ using UseListOrderMap = DenseMap<const Function *, MapVector<const Value *, std::vector<unsigned>>>; +using SanitizerMetadata = llvm::GlobalValue::SanitizerMetadata; +using GlobalSanitizer = SanitizerMetadata::GlobalSanitizer; + /// Look for a value that might be wrapped as metadata, e.g. a value in a /// metadata operand. Returns the input value as-is if it is not wrapped. static const Value *skipMetadataWrapper(const Value *V) { @@ -3537,6 +3540,28 @@ Out << '"'; } + if (GV->hasSanitizerMetadata()) { + SanitizerMetadata MD = GV->getSanitizerMetadata(); + if (MD.HasSanitizer(SanitizerMetadata::NoSanitize)) { + Out << ", no_sanitize"; + } else { + if (MD.HasSanitizer(SanitizerMetadata::Address)) + Out << ", sanitize_address"; + if (MD.HasSanitizer(SanitizerMetadata::HWAddress)) + Out << ", sanitize_hwaddress"; + if (MD.HasSanitizer(SanitizerMetadata::Memtag)) + Out << ", sanitize_address"; + if (MD.HasSanitizer(SanitizerMetadata::NoAddress)) + Out << ", no_sanitize_address"; + if (MD.HasSanitizer(SanitizerMetadata::NoHWAddress)) + Out << ", no_sanitize_hwaddress"; + if (MD.HasSanitizer(SanitizerMetadata::NoMemtag)) + Out << ", no_sanitize_memtag"; + if (MD.HasSanitizer(GlobalSanitizer::Address) && MD.IsDynInit) + Out << ", sanitize_address_dyninit"; + } + } + maybePrintComdat(Out, *GV); if (MaybeAlign A = GV->getAlign()) Out << ", align " << A->value(); Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1344,7 +1344,8 @@ // GLOBALVAR: [strtab offset, strtab size, type, isconst, initid, // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, externally_initialized, dllstorageclass, - // comdat, attributes, DSO_Local] + // comdat, attributes, DSO_Local, GlobalSanitizer::Sanitizer, + // GlobalSanitizer::IsDynInit] Vals.push_back(addToStrtab(GV.getName())); Vals.push_back(GV.getName().size()); Vals.push_back(VE.getTypeID(GV.getValueType())); @@ -1360,10 +1361,8 @@ GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None || GV.isExternallyInitialized() || GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass || - GV.hasComdat() || - GV.hasAttributes() || - GV.isDSOLocal() || - GV.hasPartition()) { + GV.hasComdat() || GV.hasAttributes() || GV.isDSOLocal() || + GV.hasPartition() || GV.hasSanitizerMetadata()) { Vals.push_back(getEncodedVisibility(GV)); Vals.push_back(getEncodedThreadLocalMode(GV)); Vals.push_back(getEncodedUnnamedAddr(GV)); @@ -1377,6 +1376,15 @@ Vals.push_back(GV.isDSOLocal()); Vals.push_back(addToStrtab(GV.getPartition())); Vals.push_back(GV.getPartition().size()); + + if (!GV.hasSanitizerMetadata()) { + Vals.push_back(UINT_MAX); + Vals.push_back(UINT_MAX); + } else { + const auto &MD = GV.getSanitizerMetadata(); + Vals.push_back(static_cast<int>(MD.Sanitizer)); + Vals.push_back(MD.IsDynInit); + } } else { AbbrevToUse = SimpleGVarAbbrev; } Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3540,6 +3540,15 @@ if (Record.size() > 15) NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15])); + if (Record.size() > 17 && Record[16] != UINT_MAX && Record[17] != UINT_MAX) { + llvm::GlobalValue::SanitizerMetadata Meta; + Meta.Sanitizer = + static_cast<llvm::GlobalValue::SanitizerMetadata::GlobalSanitizer>( + Record[16]); + Meta.IsDynInit = static_cast<bool>(Record[17]); + NewGV->setSanitizerMetadata(Meta); + } + return Error::success(); } Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -52,6 +52,9 @@ using namespace llvm; +using SanitizerMetadata = GlobalValue::SanitizerMetadata; +using GlobalSanitizer = SanitizerMetadata::GlobalSanitizer; + static std::string getTypeString(Type *T) { std::string Result; raw_string_ostream Tmp(Result); @@ -1103,6 +1106,65 @@ return false; } +static bool isSanitizer(lltok::Kind Kind) { + switch (Kind) { + case lltok::kw_no_sanitize: + case lltok::kw_sanitize_address: + case lltok::kw_no_sanitize_address: + case lltok::kw_sanitize_hwaddress: + case lltok::kw_no_sanitize_hwaddress: + case lltok::kw_sanitize_memtag: + case lltok::kw_no_sanitize_memtag: + case lltok::kw_sanitize_address_dyninit: + return true; + default: + return false; + } +} + +bool LLParser::parseSanitizer(GlobalVariable *GV) { + SanitizerMetadata Meta; + if (GV->hasSanitizerMetadata()) + Meta = GV->getSanitizerMetadata(); + + switch (Lex.getKind()) { + case lltok::kw_no_sanitize: + Meta.AddSanitizer(GlobalSanitizer::NoSanitize); + break; + case lltok::kw_sanitize_address: + Meta.AddSanitizer(GlobalSanitizer::Address); + break; + case lltok::kw_no_sanitize_address: + Meta.AddSanitizer(GlobalSanitizer::NoAddress); + break; + case lltok::kw_sanitize_hwaddress: + Meta.AddSanitizer(GlobalSanitizer::HWAddress); + break; + case lltok::kw_no_sanitize_hwaddress: + Meta.AddSanitizer(GlobalSanitizer::NoHWAddress); + break; + case lltok::kw_sanitize_memtag: + Meta.AddSanitizer(GlobalSanitizer::Memtag); + break; + case lltok::kw_no_sanitize_memtag: + Meta.AddSanitizer(GlobalSanitizer::NoMemtag); + break; + case lltok::kw_sanitize_address_dyninit: + if (!GV->hasSanitizerMetadata() || + !Meta.HasSanitizer(SanitizerMetadata::Address)) { + return tokError( + "sanitize_address_dyninit must only occur after sanitize_address"); + } + Meta.IsDynInit = true; + break; + default: + return tokError("non-sanitizer token passed to LLParser::parseSanitizer()"); + } + GV->setSanitizerMetadata(Meta); + Lex.Lex(); + return false; +} + /// parseGlobal /// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier /// OptionalVisibility OptionalDLLStorageClass @@ -1221,6 +1283,9 @@ } else if (Lex.getKind() == lltok::MetadataVar) { if (parseGlobalObjectMetadataAttachment(*GV)) return true; + } else if (isSanitizer(Lex.getKind())) { + if (parseSanitizer(GV)) + return true; } else { Comdat *C; if (parseOptionalComdat(Name, C)) Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -580,6 +580,18 @@ KEYWORD(prefix); KEYWORD(prologue); + // Sanitizer keywords. Some are inherited from Attributes.td. See LLToken.h + // for more information. +#define DEFINED_IN_ATTRIBUTES_TD_NO_OP(var) + KEYWORD(no_sanitize); + DEFINED_IN_ATTRIBUTES_TD_NO_OP(sanitize_address); + KEYWORD(no_sanitize_address); + KEYWORD(sanitize_address_dyninit); + DEFINED_IN_ATTRIBUTES_TD_NO_OP(sanitize_hwaddress); + KEYWORD(no_sanitize_hwaddress); + DEFINED_IN_ATTRIBUTES_TD_NO_OP(sanitize_memtag); + KEYWORD(no_sanitize_memtag); + KEYWORD(ccc); KEYWORD(fastcc); KEYWORD(coldcc); Index: llvm/include/llvm/IR/GlobalValue.h =================================================================== --- llvm/include/llvm/IR/GlobalValue.h +++ llvm/include/llvm/IR/GlobalValue.h @@ -79,14 +79,15 @@ ValueType(Ty), Visibility(DefaultVisibility), UnnamedAddrVal(unsigned(UnnamedAddr::None)), DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal), - HasLLVMReservedName(false), IsDSOLocal(false), HasPartition(false) { + HasLLVMReservedName(false), IsDSOLocal(false), HasPartition(false), + HasSanitizerMetadata(false) { setLinkage(Linkage); setName(Name); } Type *ValueType; - static const unsigned GlobalValueSubClassDataBits = 16; + static const unsigned GlobalValueSubClassDataBits = 15; // All bitfields use unsigned as the underlying type so that MSVC will pack // them. @@ -111,9 +112,14 @@ /// https://lld.llvm.org/Partitions.html). unsigned HasPartition : 1; + /// True if this symbol has sanitizer metadata available. Should only happen + /// if sanitizers were enabled when building the translation unit which + /// contains this GV. + unsigned HasSanitizerMetadata : 1; + private: // Give subclasses access to what otherwise would be wasted padding. - // (16 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1) == 32. + // (15 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1 + 1) == 32. unsigned SubClassData : GlobalValueSubClassDataBits; friend class Constant; @@ -288,6 +294,47 @@ StringRef getPartition() const; void setPartition(StringRef Part); + struct SanitizerMetadata { + enum GlobalSanitizer : unsigned { + NoSanitize = 1 << 0, + Address = 1 << 1, + HWAddress = 1 << 2, + Memtag = 1 << 3, + NoAddress = 1 << 4, + NoHWAddress = 1 << 5, + NoMemtag = 1 << 6, + }; + // Bitset of sanitizer options. + std::underlying_type<GlobalSanitizer>::type Sanitizer = 0; + + void AddSanitizer(GlobalSanitizer S) { Sanitizer |= S; } + void RemoveSanitizer(GlobalSanitizer S) { Sanitizer &= ~S; } + bool HasSanitizer(GlobalSanitizer S) const { + if (Sanitizer == GlobalSanitizer::NoSanitize) + return S == GlobalSanitizer::NoSanitize; + switch (S) { + case GlobalSanitizer::Address: + return (Sanitizer & S) && !(Sanitizer & GlobalSanitizer::NoAddress); + case GlobalSanitizer::HWAddress: + return (Sanitizer & S) && !(Sanitizer & GlobalSanitizer::NoHWAddress); + case GlobalSanitizer::Memtag: + return (Sanitizer & S) && !(Sanitizer & GlobalSanitizer::NoMemtag); + case GlobalSanitizer::NoSanitize: // clang doesn't see the handling above. + case GlobalSanitizer::NoAddress: + case GlobalSanitizer::NoHWAddress: + case GlobalSanitizer::NoMemtag: + return Sanitizer & S; + } + } + + // Metadata specific to ASan. + bool IsDynInit = false; + }; + + bool hasSanitizerMetadata() const { return HasSanitizerMetadata; } + const SanitizerMetadata &getSanitizerMetadata() const; + void setSanitizerMetadata(const SanitizerMetadata &Meta); + static LinkageTypes getLinkOnceLinkage(bool ODR) { return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage; } Index: llvm/include/llvm/AsmParser/LLToken.h =================================================================== --- llvm/include/llvm/AsmParser/LLToken.h +++ llvm/include/llvm/AsmParser/LLToken.h @@ -423,7 +423,27 @@ Type, APFloat, // APFloatVal - APSInt // APSInt + APSInt, // APSInt + +// Extra sanitizer attributes that are used for global variables (GV's). Some +// of the attributes are inherited from Attributes.td, but we have some +// GV-specific additions. +#define DEFINED_IN_ATTRIBUTES_TD_NO_OP(var) + // GV's mentioned in -fsanitize-ignorelist=<file>. + kw_no_sanitize, + DEFINED_IN_ATTRIBUTES_TD_NO_OP(kw_sanitize_address) + // GV's with __attribute__((no_sanitize("address"))). + kw_no_sanitize_address, + // GV's where the clang++ frontend (when ASan is used) notes that this is + // dynamically initialized, and thus needs ODR detection. + kw_sanitize_address_dyninit, + DEFINED_IN_ATTRIBUTES_TD_NO_OP(kw_sanitize_hwaddress) + // GV's with __attribute__((no_sanitize("hwaddress"))). + kw_no_sanitize_hwaddress, + DEFINED_IN_ATTRIBUTES_TD_NO_OP(kw_sanitize_memtag) + // GV's with __attribute__((no_sanitize("memtag"))). + kw_no_sanitize_memtag, + }; } // end namespace lltok } // end namespace llvm Index: llvm/include/llvm/AsmParser/LLParser.h =================================================================== --- llvm/include/llvm/AsmParser/LLParser.h +++ llvm/include/llvm/AsmParser/LLParser.h @@ -514,6 +514,7 @@ bool parseGlobalValueVector(SmallVectorImpl<Constant *> &Elts, Optional<unsigned> *InRangeOp = nullptr); bool parseOptionalComdat(StringRef GlobalName, Comdat *&C); + bool parseSanitizer(GlobalVariable *GV); bool parseMetadataAsValue(Value *&V, PerFunctionState &PFS); bool parseValueAsMetadata(Metadata *&MD, const Twine &TypeMsg, PerFunctionState *PFS); Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -746,6 +746,10 @@ <global | constant> <Type> [<InitializerConstant>] [, section "name"] [, partition "name"] [, comdat [($name)]] [, align <Alignment>] + [, no_sanitize] [, sanitize_address] + [, no_sanitize_address] [, sanitize_hwaddress] + [, no_sanitize_hwaddress] [, sanitize_memtag] + [, no_sanitize_memtag] [, sanitize_address_dyninit] (, !name !N)* For example, the following defines a global in a numbered address space @@ -1570,9 +1574,9 @@ Specify the desired alignment, which must be a power of two, in parentheses. ``"alloc-family"="FAMILY"`` - This indicates which "family" an allocator function is part of. To avoid - collisions, the family name should match the mangled name of the primary - allocator function, that is "malloc" for malloc/calloc/realloc/free, + This indicates which "family" an allocator function is part of. To avoid + collisions, the family name should match the mangled name of the primary + allocator function, that is "malloc" for malloc/calloc/realloc/free, "_Znwm" for ``::operator::new`` and ``::operator::delete``, and "_ZnwmSt11align_val_t" for aligned ``::operator::new`` and ``::operator::delete``. Matching malloc/realloc/free calls within a family @@ -20461,7 +20465,7 @@ The '``llvm.vp.fpext``' intrinsic extends the ``value`` from a smaller :ref:`floating-point <t_floating>` type to a larger :ref:`floating-point <t_floating>` type. The '``llvm.vp.fpext``' cannot be used to make a -*no-op cast* because it always changes bits. Use ``bitcast`` to make a +*no-op cast* because it always changes bits. Use ``bitcast`` to make a *no-op cast* for a floating-point cast. The conversion is performed on lane positions below the explicit vector length and where the vector mask is true. Masked-off lanes are undefined. Index: clang/test/CodeGen/asan-strings.c =================================================================== --- clang/test/CodeGen/asan-strings.c +++ clang/test/CodeGen/asan-strings.c @@ -10,8 +10,8 @@ const char *foo(void) { return "asdf"; } -// LINUX: @.str = private unnamed_addr constant [5 x i8] c"asdf\00", align 1 +// LINUX: @.str = private unnamed_addr constant [5 x i8] c"asdf\00", sanitize_address, align 1 -// WINDOWS: @"??_C@_04JIHMPGLA@asdf?$AA@" = linkonce_odr dso_local unnamed_addr constant [5 x i8] c"asdf\00", comdat, align 1 +// WINDOWS: @"??_C@_04JIHMPGLA@asdf?$AA@" = linkonce_odr dso_local unnamed_addr constant [5 x i8] c"asdf\00", sanitize_address, comdat, align 1 -// WINWRITE: @.str = private unnamed_addr global [5 x i8] c"asdf\00", align 1 +// WINWRITE: @.str = private unnamed_addr global [5 x i8] c"asdf\00", sanitize_address, align 1 Index: clang/test/CodeGen/asan-static-odr.cpp =================================================================== --- clang/test/CodeGen/asan-static-odr.cpp +++ clang/test/CodeGen/asan-static-odr.cpp @@ -11,7 +11,7 @@ // CHECK-NOT: __odr_asan_gen // CHECK-NOT: private alias -// CHECK: [[VAR:@.*global.*]] ={{.*}} global { i32, [28 x i8] } zeroinitializer, align 32 +// CHECK: [[VAR:@.*global.*]] ={{.*}} global { i32, [28 x i8] } zeroinitializer, sanitize_address, align 32 // CHECK: @0 = internal global {{.*}} [[VAR]] to i64), {{.*}}, i64 -1 }] // CHECK: call void @__asan_register_globals(i64 ptrtoint ([1 x { i64, i64, i64, i64, i64, i64, i64, i64 }]* @0 to i64), i64 1) // CHECK: call void @__asan_unregister_globals(i64 ptrtoint ([1 x { i64, i64, i64, i64, i64, i64, i64, i64 }]* @0 to i64), i64 1) Index: clang/test/CodeGen/asan-globals-odr.cpp =================================================================== --- clang/test/CodeGen/asan-globals-odr.cpp +++ clang/test/CodeGen/asan-globals-odr.cpp @@ -14,7 +14,7 @@ return global; } -// CHECK: [[VAR:@.*global.*]] ={{.*}} global { i32, [28 x i8] } zeroinitializer, align 32 +// CHECK: [[VAR:@.*global.*]] ={{.*}} global { i32, [28 x i8] } zeroinitializer, sanitize_address, align 32 // INDICATOR0-NOT: __odr_asan_gen // INDICATOR1: [[ODR:@.*__odr_asan_gen_.*global.*]] = global i8 0, align 1 Index: clang/test/CodeGen/asan-globals-alias.cpp =================================================================== --- clang/test/CodeGen/asan-globals-alias.cpp +++ clang/test/CodeGen/asan-globals-alias.cpp @@ -22,12 +22,12 @@ struct input_device_id joydev_ids[] = { { {1}, 1234 } }; // KASAN ignored extern struct input_device_id __attribute__((alias("joydev_ids"))) __mod_joydev_ids_device_table; -// ASAN: @aliased_global{{.*}} global { i32, [28 x i8] }{{.*}}, align 32 -// ASAN: @aliased_global_2{{.*}} global { i32, [28 x i8] }{{.*}}, align 32 -// ASAN: @joydev_ids{{.*}} global { {{.*}}[56 x i8] zeroinitializer }, align 32 +// ASAN: @aliased_global{{.*}} global { i32, [28 x i8] }{{.*}}, sanitize_address, align 32 +// ASAN: @aliased_global_2{{.*}} global { i32, [28 x i8] }{{.*}}, sanitize_address, align 32 +// ASAN: @joydev_ids{{.*}} global { {{.*}}[56 x i8] zeroinitializer }, sanitize_address, align 32 // KASAN: @aliased_global{{.*}} global i32 // KASAN: @aliased_global_2{{.*}} global i32 -// KASAN: @joydev_ids{{.*}} global [1 x {{.*}}i64 1234 }], align 16 +// KASAN: @joydev_ids{{.*}} global [1 x {{.*}}i64 1234 }], sanitize_address, align 16 // Check the aliases exist: // CHECK: @__global_alias ={{.*}} alias 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 setASanSpecificMetadata(llvm::GlobalVariable::SanitizerMetadata &Meta, + llvm::GlobalVariable *GV, SourceLocation Loc, + QualType Ty, bool IsDynInit = false); void disableSanitizerForGlobal(llvm::GlobalVariable *GV); void disableSanitizerForInstruction(llvm::Instruction *I); + private: llvm::MDNode *getLocationMetadata(SourceLocation Loc); }; -} // 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,90 @@ #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.AddSanitizer(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.HasSanitizer(GlobalSanitizer::NoAddress)) { + Meta.AddSanitizer(GlobalSanitizer::NoAddress); + IsExcluded = true; + } else if (!IsExcluded) { + Meta.AddSanitizer(GlobalSanitizer::Address); + } + setASanSpecificMetadata(Meta, GV, Loc, Ty, IsDynInit); + } + if (SanTarget.hasOneOf(SanitizerKind::HWAddress | + SanitizerKind::KernelHWAddress)) { + if (NoSanitizeSet.hasOneOf(SanitizerKind::HWAddress | + SanitizerKind::KernelHWAddress) || + Meta.HasSanitizer(GlobalSanitizer::NoHWAddress)) { + Meta.AddSanitizer(GlobalSanitizer::NoHWAddress); + IsExcluded = true; + } else if (!IsExcluded) { + Meta.AddSanitizer(GlobalSanitizer::HWAddress); + } + } + if (SanTarget.hasOneOf(SanitizerKind::MemTag)) { + if (NoSanitizeSet.hasOneOf(SanitizerKind::MemTag) || + Meta.HasSanitizer(GlobalSanitizer::NoMemtag)) { + Meta.AddSanitizer(GlobalSanitizer::NoMemtag); + IsExcluded = true; + } else if (!IsExcluded) { + Meta.AddSanitizer(GlobalSanitizer::Memtag); + } + } 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. @@ -48,10 +109,12 @@ GlobalName = llvm::MDString::get(VMContext, Name); } + GV->setSanitizerMetadata(Meta); + 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 +124,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