Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2366,7 +2366,7 @@ let Documentation = [NoSanitizeDocs]; let AdditionalMembers = [{ SanitizerMask getMask() const { - SanitizerMask Mask = 0; + SanitizerMask Mask; for (auto SanitizerName : sanitizers()) { SanitizerMask ParsedMask = parseSanitizerValue(SanitizerName, /*AllowGroups=*/true); Index: include/clang/Basic/Sanitizers.h =================================================================== --- include/clang/Basic/Sanitizers.h +++ include/clang/Basic/Sanitizers.h @@ -21,44 +21,167 @@ #include namespace clang { +class SanitizerMask; +} -using SanitizerMask = uint64_t; +namespace llvm { +class hashcode; +hash_code hash_value(const clang::SanitizerMask &Arg); +} // namespace llvm -namespace SanitizerKind { +namespace clang { -// Assign ordinals to possible values of -fsanitize= flag, which we will use as -// bit positions. -enum SanitizerOrdinal : uint64_t { -#define SANITIZER(NAME, ID) SO_##ID, -#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, -#include "clang/Basic/Sanitizers.def" - SO_Count +class SanitizerMask { + /// Number of array elements. + static constexpr unsigned kNumElem = 2; + /// Mask value initialized to 0. + uint64_t maskLoToHigh[kNumElem]{}; + /// Number of bits in a mask. + static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8; + /// Number of bits in a mask element. + static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8; + +public: + static constexpr bool checkBitPos(const unsigned Pos) { + return Pos < kNumBits; + } + + /// Create a mask with a bit enabled at position Pos. + static SanitizerMask bitPosToMask(const unsigned Pos) { + assert(Pos < kNumBits && "Bit position too big."); + SanitizerMask mask; + mask.maskLoToHigh[Pos / kNumBitElem] = 1ULL << Pos % kNumBitElem; + return mask; + } + + unsigned countPopulation() const { + unsigned total = 0; + for (const auto &Val : maskLoToHigh) + total += llvm::countPopulation(Val); + return total; + } + + void flipAllBits() { + for (auto &Val : maskLoToHigh) + Val = ~Val; + } + + bool isPowerOf2() const { + return countPopulation() == 1; + } + + llvm::hash_code hash_value() const; + + explicit operator bool() const { + for (const auto &Val : maskLoToHigh) + if (Val) + return true; + return false; + }; + + bool operator==(const SanitizerMask &V) const { + for (unsigned k = 0; k < kNumElem; k++) { + if (maskLoToHigh[k] != V.maskLoToHigh[k]) + return false; + } + return true; + } + + SanitizerMask &operator&=(const SanitizerMask &RHS) { + for (unsigned k = 0; k < kNumElem; k++) + maskLoToHigh[k] &= RHS.maskLoToHigh[k]; + return *this; + } + + SanitizerMask &operator|=(const SanitizerMask &RHS) { + for (unsigned k = 0; k < kNumElem; k++) + maskLoToHigh[k] |= RHS.maskLoToHigh[k]; + return *this; + } + + bool operator!() const { + for (const auto &Val : maskLoToHigh) + if (Val) + return false; + return true; + } + + bool operator!=(const SanitizerMask &RHS) const { return !((*this) == RHS); } }; +inline SanitizerMask operator~(SanitizerMask v) { + v.flipAllBits(); + return v; +} + +inline SanitizerMask operator&(SanitizerMask a, const SanitizerMask &b) { + a &= b; + return a; +} + +inline SanitizerMask operator|(SanitizerMask a, const SanitizerMask &b) { + a |= b; + return a; +} + // Define the set of sanitizer kinds, as well as the set of sanitizers each // sanitizer group expands into. -#define SANITIZER(NAME, ID) \ - const SanitizerMask ID = 1ULL << SO_##ID; -#define SANITIZER_GROUP(NAME, ID, ALIAS) \ - const SanitizerMask ID = ALIAS; \ - const SanitizerMask ID##Group = 1ULL << SO_##ID##Group; +// Uses static data member of a class template as recommended in second +// workaround from n4424 to avoid odr issues. +// FIXME: Can be marked as constexpr once c++14 can be used in llvm. +// FIXME: n4424 workaround can be replaced by c++17 inline variable. +template struct SanitizerMasks { + + // Assign ordinals to possible values of -fsanitize= flag, which we will use + // as bit positions. + enum SanitizerOrdinal : uint64_t { +#define SANITIZER(NAME, ID) SO_##ID, +#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, #include "clang/Basic/Sanitizers.def" + SO_Count + }; + +#define SANITIZER(NAME, ID) \ + static const SanitizerMask ID; \ + static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big."); +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + static const SanitizerMask ID; \ + static const SanitizerMask ID##Group; \ + static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \ + "Bit position too big."); +#include "clang/Basic/Sanitizers.def" +}; // SanitizerMasks + +#define SANITIZER(NAME, ID) \ + template \ + const SanitizerMask SanitizerMasks::ID = \ + SanitizerMask::bitPosToMask(SO_##ID); +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + template \ + const SanitizerMask SanitizerMasks::ID = SanitizerMask(ALIAS); \ + template \ + const SanitizerMask SanitizerMasks::ID##Group = \ + SanitizerMask::bitPosToMask(SO_##ID##Group); +#include "clang/Basic/Sanitizers.def" + +// Explicit instantiation here to ensure correct initialization order. +template struct SanitizerMasks<>; -} // namespace SanitizerKind +using SanitizerKind = SanitizerMasks<>; struct SanitizerSet { /// Check if a certain (single) sanitizer is enabled. bool has(SanitizerMask K) const { - assert(llvm::isPowerOf2_64(K)); - return Mask & K; + assert(K.isPowerOf2() && "Has to be a single sanitizer."); + return static_cast(Mask & K); } /// Check if one or more sanitizers are enabled. - bool hasOneOf(SanitizerMask K) const { return Mask & K; } + bool hasOneOf(SanitizerMask K) const { return static_cast(Mask & K); } /// Enable or disable a certain (single) sanitizer. void set(SanitizerMask K, bool Value) { - assert(llvm::isPowerOf2_64(K)); + assert(K.isPowerOf2() && "Has to be a single sanitizer."); Mask = Value ? (Mask | K) : (Mask & ~K); } @@ -66,10 +189,10 @@ void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } /// Returns true if no sanitizers are enabled. - bool empty() const { return Mask == 0; } + bool empty() const { return !Mask; } /// Bitmask of enabled sanitizers. - SanitizerMask Mask = 0; + SanitizerMask Mask; }; /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. Index: include/clang/Basic/Sanitizers.def =================================================================== --- include/clang/Basic/Sanitizers.def +++ include/clang/Basic/Sanitizers.def @@ -177,7 +177,7 @@ // Magic group, containing all sanitizers. For example, "-fno-sanitize=all" // can be used to disable all the sanitizers. -SANITIZER_GROUP("all", All, ~0ULL) +SANITIZER_GROUP("all", All, ~SanitizerMask()) #undef SANITIZER #undef SANITIZER_GROUP Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -565,7 +565,9 @@ virtual SanitizerMask getSupportedSanitizers() const; /// Return sanitizers which are enabled by default. - virtual SanitizerMask getDefaultSanitizers() const { return 0; } + virtual SanitizerMask getDefaultSanitizers() const { + return SanitizerMask(); + } }; /// Set a ToolChain's effective triple. Reset it when the registration object Index: lib/Basic/SanitizerSpecialCaseList.cpp =================================================================== --- lib/Basic/SanitizerSpecialCaseList.cpp +++ lib/Basic/SanitizerSpecialCaseList.cpp @@ -36,7 +36,7 @@ void SanitizerSpecialCaseList::createSanitizerSections() { for (auto &S : Sections) { - SanitizerMask Mask = 0; + SanitizerMask Mask; #define SANITIZER(NAME, ID) \ if (S.SectionMatcher->match(NAME)) \ Index: lib/Basic/Sanitizers.cpp =================================================================== --- lib/Basic/Sanitizers.cpp +++ lib/Basic/Sanitizers.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Sanitizers.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -19,9 +20,9 @@ SanitizerMask ParsedKind = llvm::StringSwitch(Value) #define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) #define SANITIZER_GROUP(NAME, ID, ALIAS) \ - .Case(NAME, AllowGroups ? SanitizerKind::ID##Group : 0) + .Case(NAME, AllowGroups ? SanitizerKind::ID##Group : SanitizerMask()) #include "clang/Basic/Sanitizers.def" - .Default(0); + .Default(SanitizerMask()); return ParsedKind; } @@ -33,3 +34,13 @@ #include "clang/Basic/Sanitizers.def" return Kinds; } + +llvm::hash_code SanitizerMask::hash_value() const { + return llvm::hash_combine_range(&maskLoToHigh[0], &maskLoToHigh[kNumElem]); +} + +namespace llvm { +hash_code hash_value(const clang::SanitizerMask &Arg) { + return Arg.hash_value(); +} +} // namespace llvm Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -2855,16 +2855,13 @@ } static CheckRecoverableKind getRecoverableKind(SanitizerMask Kind) { - assert(llvm::countPopulation(Kind) == 1); - switch (Kind) { - case SanitizerKind::Vptr: + assert(Kind.countPopulation() == 1); + if (Kind == SanitizerKind::Vptr) return CheckRecoverableKind::AlwaysRecoverable; - case SanitizerKind::Return: - case SanitizerKind::Unreachable: + else if (Kind == SanitizerKind::Return || Kind == SanitizerKind::Unreachable) return CheckRecoverableKind::Unrecoverable; - default: + else return CheckRecoverableKind::Recoverable; - } } namespace { Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -21,33 +21,52 @@ #include using namespace clang; -using namespace clang::SanitizerKind; using namespace clang::driver; using namespace llvm::opt; -enum : SanitizerMask { - NeedsUbsanRt = Undefined | Integer | ImplicitConversion | Nullability | CFI, - NeedsUbsanCxxRt = Vptr | CFI, - NotAllowedWithTrap = Vptr, - NotAllowedWithMinimalRuntime = Vptr, - RequiresPIE = DataFlow | HWAddress | Scudo, - NeedsUnwindTables = Address | HWAddress | Thread | Memory | DataFlow, - SupportsCoverage = Address | HWAddress | KernelAddress | KernelHWAddress | - Memory | KernelMemory | Leak | Undefined | Integer | - ImplicitConversion | Nullability | DataFlow | Fuzzer | - FuzzerNoLink, - RecoverableByDefault = Undefined | Integer | ImplicitConversion | Nullability, - Unrecoverable = Unreachable | Return, - AlwaysRecoverable = KernelAddress | KernelHWAddress, - LegacyFsanitizeRecoverMask = Undefined | Integer, - NeedsLTO = CFI, - TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow | - ImplicitConversion | Nullability | LocalBounds | CFI, - TrappingDefault = CFI, - CFIClasses = - CFIVCall | CFINVCall | CFIMFCall | CFIDerivedCast | CFIUnrelatedCast, - CompatibleWithMinimalRuntime = TrappingSupported | Scudo | ShadowCallStack, -}; +static const SanitizerMask NeedsUbsanRt = + SanitizerKind::Undefined | SanitizerKind::Integer | + SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | + SanitizerKind::CFI; +static const SanitizerMask NeedsUbsanCxxRt = + SanitizerKind::Vptr | SanitizerKind::CFI; +static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; +static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr; +static const SanitizerMask RequiresPIE = + SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo; +static const SanitizerMask NeedsUnwindTables = + SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::DataFlow; +static const SanitizerMask SupportsCoverage = + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | + SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak | + SanitizerKind::Undefined | SanitizerKind::Integer | + SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | + SanitizerKind::DataFlow | SanitizerKind::Fuzzer | + SanitizerKind::FuzzerNoLink; +static const SanitizerMask RecoverableByDefault = + SanitizerKind::Undefined | SanitizerKind::Integer | + SanitizerKind::ImplicitConversion | SanitizerKind::Nullability; +static const SanitizerMask Unrecoverable = + SanitizerKind::Unreachable | SanitizerKind::Return; +static const SanitizerMask AlwaysRecoverable = + SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress; +static const SanitizerMask LegacyFsanitizeRecoverMask = + SanitizerKind::Undefined | SanitizerKind::Integer; +static const SanitizerMask NeedsLTO = SanitizerKind::CFI; +static const SanitizerMask TrappingSupported = + (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | + SanitizerKind::UnsignedIntegerOverflow | SanitizerKind::ImplicitConversion | + SanitizerKind::Nullability | SanitizerKind::LocalBounds | + SanitizerKind::CFI; +static const SanitizerMask TrappingDefault = SanitizerKind::CFI; +static const SanitizerMask CFIClasses = + SanitizerKind::CFIVCall | SanitizerKind::CFINVCall | + SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast | + SanitizerKind::CFIUnrelatedCast; +static const SanitizerMask CompatibleWithMinimalRuntime = + TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack; enum CoverageFeature { CoverageFunc = 1 << 0, @@ -100,13 +119,15 @@ struct Blacklist { const char *File; SanitizerMask Mask; - } Blacklists[] = {{"asan_blacklist.txt", Address}, - {"hwasan_blacklist.txt", HWAddress}, - {"msan_blacklist.txt", Memory}, - {"tsan_blacklist.txt", Thread}, - {"dfsan_abilist.txt", DataFlow}, - {"cfi_blacklist.txt", CFI}, - {"ubsan_blacklist.txt", Undefined | Integer | Nullability}}; + } Blacklists[] = {{"asan_blacklist.txt", SanitizerKind::Address}, + {"hwasan_blacklist.txt", SanitizerKind::HWAddress}, + {"msan_blacklist.txt", SanitizerKind::Memory}, + {"tsan_blacklist.txt", SanitizerKind::Thread}, + {"dfsan_abilist.txt", SanitizerKind::DataFlow}, + {"cfi_blacklist.txt", SanitizerKind::CFI}, + {"ubsan_blacklist.txt", SanitizerKind::Undefined | + SanitizerKind::Integer | + SanitizerKind::Nullability}}; for (auto BL : Blacklists) { if (!(Kinds & BL.Mask)) @@ -116,7 +137,7 @@ llvm::sys::path::append(Path, "share", BL.File); if (llvm::sys::fs::exists(Path)) BlacklistFiles.push_back(Path.str()); - else if (BL.Mask == CFI) + else if (BL.Mask == SanitizerKind::CFI) // If cfi_blacklist.txt cannot be found in the resource dir, driver // should fail. D.Diag(clang::diag::err_drv_no_such_file) << Path; @@ -136,10 +157,10 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, const llvm::opt::ArgList &Args) { - SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of + SanitizerMask TrapRemove; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. - SanitizerMask TrappingKinds = 0; + SanitizerMask TrappingKinds; SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); @@ -163,11 +184,12 @@ options::OPT_fsanitize_undefined_trap_on_error)) { Arg->claim(); TrappingKinds |= - expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove; + expandSanitizerGroups(SanitizerKind::UndefinedGroup & ~TrapRemove) & + ~TrapRemove; } else if (Arg->getOption().matches( options::OPT_fno_sanitize_undefined_trap_on_error)) { Arg->claim(); - TrapRemove |= expandSanitizerGroups(UndefinedGroup); + TrapRemove |= expandSanitizerGroups(SanitizerKind::UndefinedGroup); } } @@ -189,13 +211,13 @@ } bool SanitizerArgs::needsCfiRt() const { - return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso && - !ImplicitCfiRuntime; + return !(Sanitizers.Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) && + CfiCrossDso && !ImplicitCfiRuntime; } bool SanitizerArgs::needsCfiDiagRt() const { - return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso && - !ImplicitCfiRuntime; + return (Sanitizers.Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) && + CfiCrossDso && !ImplicitCfiRuntime; } bool SanitizerArgs::requiresPIE() const { @@ -203,24 +225,26 @@ } bool SanitizerArgs::needsUnwindTables() const { - return Sanitizers.Mask & NeedsUnwindTables; + return static_cast(Sanitizers.Mask & NeedsUnwindTables); } -bool SanitizerArgs::needsLTO() const { return Sanitizers.Mask & NeedsLTO; } +bool SanitizerArgs::needsLTO() const { + return static_cast(Sanitizers.Mask & NeedsLTO); +} SanitizerArgs::SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args) { - SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of + SanitizerMask AllRemove; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. - SanitizerMask AllAddedKinds = 0; // Mask of all sanitizers ever enabled by + SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by // -fsanitize= flags (directly or via group // expansion), some of which may be disabled // later. Used to carefully prune // unused-argument diagnostics. - SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. + SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. - SanitizerMask Kinds = 0; + SanitizerMask Kinds; const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, @@ -295,12 +319,12 @@ // identifiers. // Fixing both of those may require changes to the cross-DSO CFI // interface. - if (CfiCrossDso && (Add & CFIMFCall & ~DiagnosedKinds)) { + if (CfiCrossDso && (Add & SanitizerKind::CFIMFCall & ~DiagnosedKinds)) { D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize=cfi-mfcall" << "-fsanitize-cfi-cross-dso"; - Add &= ~CFIMFCall; - DiagnosedKinds |= CFIMFCall; + Add &= ~SanitizerKind::CFIMFCall; + DiagnosedKinds |= SanitizerKind::CFIMFCall; } if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { @@ -314,7 +338,7 @@ // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups // so we don't error out if -fno-rtti and -fsanitize=undefined were // passed. - if ((Add & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { + if ((Add & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) { assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) && "RTTI disabled without -fno-rtti option?"); @@ -329,7 +353,7 @@ } // Take out the Vptr sanitizer from the enabled sanitizers - AllRemove |= Vptr; + AllRemove |= SanitizerKind::Vptr; } Add = expandSanitizerGroups(Add); @@ -342,14 +366,14 @@ Add &= ~NotAllowedWithMinimalRuntime; } if (CfiCrossDso) - Add &= ~CFIMFCall; + Add &= ~SanitizerKind::CFIMFCall; Add &= Supported; - if (Add & Fuzzer) - Add |= FuzzerNoLink; + if (Add & SanitizerKind::Fuzzer) + Add |= SanitizerKind::FuzzerNoLink; // Enable coverage if the fuzzing flag is set. - if (Add & FuzzerNoLink) { + if (Add & SanitizerKind::FuzzerNoLink) { CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall | CoverageTraceCmp | CoveragePCTable; // Due to TLS differences, stack depth tracking is only enabled on Linux @@ -366,23 +390,42 @@ } std::pair IncompatibleGroups[] = { - std::make_pair(Address, Thread | Memory), - std::make_pair(Thread, Memory), - std::make_pair(Leak, Thread | Memory), - std::make_pair(KernelAddress, Address | Leak | Thread | Memory), - std::make_pair(HWAddress, Address | Thread | Memory | KernelAddress), - std::make_pair(Efficiency, Address | HWAddress | Leak | Thread | Memory | - KernelAddress), - std::make_pair(Scudo, Address | HWAddress | Leak | Thread | Memory | - KernelAddress | Efficiency), - std::make_pair(SafeStack, Address | HWAddress | Leak | Thread | Memory | - KernelAddress | Efficiency), - std::make_pair(KernelHWAddress, Address | HWAddress | Leak | Thread | - Memory | KernelAddress | Efficiency | - SafeStack), - std::make_pair(KernelMemory, Address | HWAddress | Leak | Thread | - Memory | KernelAddress | Efficiency | - Scudo | SafeStack)}; + std::make_pair(SanitizerKind::Address, + SanitizerKind::Thread | SanitizerKind::Memory), + std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory), + std::make_pair(SanitizerKind::Leak, + SanitizerKind::Thread | SanitizerKind::Memory), + std::make_pair(SanitizerKind::KernelAddress, + SanitizerKind::Address | SanitizerKind::Leak | + SanitizerKind::Thread | SanitizerKind::Memory), + std::make_pair(SanitizerKind::HWAddress, + SanitizerKind::Address | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress), + std::make_pair(SanitizerKind::Efficiency, + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::Leak | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress), + std::make_pair(SanitizerKind::Scudo, + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::Leak | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress | + SanitizerKind::Efficiency), + std::make_pair(SanitizerKind::SafeStack, + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::Leak | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress | + SanitizerKind::Efficiency), + std::make_pair(SanitizerKind::KernelHWAddress, + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::Leak | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress | + SanitizerKind::Efficiency | SanitizerKind::SafeStack), + std::make_pair(SanitizerKind::KernelMemory, + SanitizerKind::Address | SanitizerKind::HWAddress | + SanitizerKind::Leak | SanitizerKind::Thread | + SanitizerKind::Memory | SanitizerKind::KernelAddress | + SanitizerKind::Efficiency | SanitizerKind::Scudo | + SanitizerKind::SafeStack)}; // Enable toolchain specific default sanitizers if not explicitly disabled. SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove; @@ -398,8 +441,8 @@ // We disable the vptr sanitizer if it was enabled by group expansion but RTTI // is disabled. - if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { - Kinds &= ~Vptr; + if ((Kinds & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { + Kinds &= ~SanitizerKind::Vptr; } // Check that LTO is enabled if we need it. @@ -408,12 +451,12 @@ << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } - if ((Kinds & ShadowCallStack) && + if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().getArch() == llvm::Triple::aarch64 && !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && !Args.hasArg(options::OPT_ffixed_x18)) { D.Diag(diag::err_drv_argument_only_allowed_with) - << lastArgumentForMask(D, Args, Kinds & ShadowCallStack) + << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack) << "-ffixed-x18"; } @@ -421,12 +464,12 @@ // c++abi-specific parts of UBSan runtime, and they are not provided by the // toolchain. We don't have a good way to check the latter, so we just // check if the toolchan supports vptr. - if (~Supported & Vptr) { + if (~Supported & SanitizerKind::Vptr) { SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; // The runtime library supports the Microsoft C++ ABI, but only well enough // for CFI. FIXME: Remove this once we support vptr on Windows. if (TC.getTriple().isOSWindows()) - KindsToDiagnose &= ~CFI; + KindsToDiagnose &= ~SanitizerKind::CFI; if (KindsToDiagnose) { SanitizerSet S; S.Mask = KindsToDiagnose; @@ -455,8 +498,8 @@ // Parse -f(no-)?sanitize-recover flags. SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable; - SanitizerMask DiagnosedUnrecoverableKinds = 0; - SanitizerMask DiagnosedAlwaysRecoverableKinds = 0; + SanitizerMask DiagnosedUnrecoverableKinds; + SanitizerMask DiagnosedAlwaysRecoverableKinds; for (const auto *Arg : Args) { const char *DeprecatedReplacement = nullptr; if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { @@ -539,7 +582,7 @@ } // Parse -f[no-]sanitize-memory-track-origins[=level] options. - if (AllAddedKinds & Memory) { + if (AllAddedKinds & SanitizerKind::Memory) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, options::OPT_fsanitize_memory_track_origins, @@ -567,19 +610,19 @@ MsanUseAfterDtor = false; } - if (AllAddedKinds & Thread) { - TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access, - options::OPT_fno_sanitize_thread_memory_access, - TsanMemoryAccess); - TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit, - options::OPT_fno_sanitize_thread_func_entry_exit, - TsanFuncEntryExit); - TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics, - options::OPT_fno_sanitize_thread_atomics, - TsanAtomics); + if (AllAddedKinds & SanitizerKind::Thread) { + TsanMemoryAccess = Args.hasFlag( + options::OPT_fsanitize_thread_memory_access, + options::OPT_fno_sanitize_thread_memory_access, TsanMemoryAccess); + TsanFuncEntryExit = Args.hasFlag( + options::OPT_fsanitize_thread_func_entry_exit, + options::OPT_fno_sanitize_thread_func_entry_exit, TsanFuncEntryExit); + TsanAtomics = + Args.hasFlag(options::OPT_fsanitize_thread_atomics, + options::OPT_fno_sanitize_thread_atomics, TsanAtomics); } - if (AllAddedKinds & CFI) { + if (AllAddedKinds & SanitizerKind::CFI) { // Without PIE, external function address may resolve to a PLT record, which // can not be verified by the target module. NeedPIE |= CfiCrossDso; @@ -603,7 +646,7 @@ << "-fsanitize-minimal-runtime" << lastArgumentForMask(D, Args, IncompatibleMask); - SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds; + SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds; if (NonTrappingCfi) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "fsanitize-minimal-runtime" @@ -691,7 +734,7 @@ ImplicitCfiRuntime = TC.getTriple().isAndroid(); - if (AllAddedKinds & Address) { + if (AllAddedKinds & SanitizerKind::Address) { NeedPIE |= TC.getTriple().isOSFuchsia(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { @@ -713,7 +756,7 @@ case options::OPT__SLASH_LDd: D.Diag(clang::diag::err_drv_argument_not_allowed_with) << WindowsDebugRTArg->getAsString(Args) - << lastArgumentForMask(D, Args, Address); + << lastArgumentForMask(D, Args, SanitizerKind::Address); D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); } } @@ -742,7 +785,7 @@ AsanUseAfterScope = false; } - if (AllAddedKinds & HWAddress) { + if (AllAddedKinds & SanitizerKind::HWAddress) { if (Arg *HwasanAbiArg = Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) { HwasanAbi = HwasanAbiArg->getValue(); @@ -754,7 +797,7 @@ } } - if (AllAddedKinds & SafeStack) { + if (AllAddedKinds & SanitizerKind::SafeStack) { // SafeStack runtime is built into the system on Fuchsia. SafeStackRuntime = !TC.getTriple().isOSFuchsia(); } @@ -774,7 +817,7 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) { std::string Res; #define SANITIZER(NAME, ID) \ - if (Sanitizers.has(ID)) { \ + if (Sanitizers.has(SanitizerKind::ID)) { \ if (!Res.empty()) \ Res += ","; \ Res += NAME; \ @@ -936,7 +979,8 @@ // https://github.com/google/sanitizers/issues/373 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't // affect compilation. - if (Sanitizers.has(Memory) || Sanitizers.has(Address)) + if (Sanitizers.has(SanitizerKind::Memory) || + Sanitizers.has(SanitizerKind::Address)) CmdArgs.push_back("-fno-assume-sane-operator-new"); // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is @@ -959,18 +1003,18 @@ A->getOption().matches(options::OPT_fsanitize_trap_EQ) || A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && "Invalid argument in parseArgValues!"); - SanitizerMask Kinds = 0; + SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); SanitizerMask Kind; // Special case: don't accept -fsanitize=all. if (A->getOption().matches(options::OPT_fsanitize_EQ) && 0 == strcmp("all", Value)) - Kind = 0; + Kind = SanitizerMask(); // Similarly, don't accept -fsanitize=efficiency-all. else if (A->getOption().matches(options::OPT_fsanitize_EQ) && 0 == strcmp("efficiency-all", Value)) - Kind = 0; + Kind = SanitizerMask(); else Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -818,21 +818,23 @@ // Return sanitizers which don't require runtime support and are not // platform dependent. - using namespace SanitizerKind; - - SanitizerMask Res = (Undefined & ~Vptr & ~Function) | (CFI & ~CFIICall) | - CFICastStrict | UnsignedIntegerOverflow | - ImplicitConversion | Nullability | LocalBounds; + SanitizerMask Res = (SanitizerKind::Undefined & ~SanitizerKind::Vptr & + ~SanitizerKind::Function) | + (SanitizerKind::CFI & ~SanitizerKind::CFIICall) | + SanitizerKind::CFICastStrict | + SanitizerKind::UnsignedIntegerOverflow | + SanitizerKind::ImplicitConversion | + SanitizerKind::Nullability | SanitizerKind::LocalBounds; if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64 || getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::wasm32 || getTriple().getArch() == llvm::Triple::wasm64) - Res |= CFIICall; + Res |= SanitizerKind::CFIICall; if (getTriple().getArch() == llvm::Triple::x86_64 || getTriple().getArch() == llvm::Triple::aarch64) - Res |= ShadowCallStack; + Res |= SanitizerKind::ShadowCallStack; return Res; } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -551,7 +551,7 @@ DiagnosticsEngine &Diags, SanitizerSet &S) { for (const auto &Sanitizer : Sanitizers) { SanitizerMask K = parseSanitizerValue(Sanitizer, /*AllowGroups=*/false); - if (K == 0) + if (K == SanitizerMask()) Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer; else S.set(K, true); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -6211,7 +6211,8 @@ if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc)) return; - if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) + if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == + SanitizerMask()) S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)