Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2360,7 +2360,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,8 +21,114 @@ #include namespace clang { +class SanitizerMask; +} + +namespace llvm { +class hashcode; +hash_code hash_value(const clang::SanitizerMask &Arg); +} // namespace llvm + +namespace clang { + +namespace SanitizerKind { +enum SanitizerOrdinal : uint64_t; +} + +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(maskLoToHigh) * 8; + /// Number of bits in a mask element. + static constexpr unsigned kNumBitElem = sizeof(maskLoToHigh[0]) * 8; + +public: + static constexpr bool + checkBitPos(const SanitizerKind::SanitizerOrdinal Pos) { + return Pos < kNumBits; + } + + /// Create a mask with a bit enabled at position Pos. + static SanitizerMask + bitPosToMask(const SanitizerKind::SanitizerOrdinal 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() { + 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; +} -using SanitizerMask = uint64_t; +inline SanitizerMask operator|(SanitizerMask a, const SanitizerMask &b) { + a |= b; + return a; +} namespace SanitizerKind { @@ -37,11 +143,15 @@ // 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; +#define SANITIZER(NAME, ID) \ + static_assert(SanitizerMask::checkBitPos(SO_##ID), \ + "Bit position too big."); \ + const SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID); +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \ + "Bit position too big."); \ + const SanitizerMask ID = SanitizerMask(ALIAS); \ + const SanitizerMask ID##Group = SanitizerMask::bitPosToMask(SO_##ID##Group); #include "clang/Basic/Sanitizers.def" } // namespace SanitizerKind @@ -49,16 +159,16 @@ 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 +176,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 @@ -563,7 +563,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 @@ -2856,16 +2856,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 @@ -25,29 +25,32 @@ 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, -}; +const SanitizerMask NeedsUbsanRt = + Undefined | Integer | ImplicitConversion | Nullability | CFI; +const SanitizerMask NeedsUbsanCxxRt = Vptr | CFI; +const SanitizerMask NotAllowedWithTrap = Vptr; +const SanitizerMask NotAllowedWithMinimalRuntime = Vptr; +const SanitizerMask RequiresPIE = DataFlow | HWAddress | Scudo; +const SanitizerMask NeedsUnwindTables = + Address | HWAddress | Thread | Memory | DataFlow; +const SanitizerMask SupportsCoverage = + Address | HWAddress | KernelAddress | KernelHWAddress | Memory | + KernelMemory | Leak | Undefined | Integer | ImplicitConversion | + Nullability | DataFlow | Fuzzer | FuzzerNoLink; +const SanitizerMask RecoverableByDefault = + Undefined | Integer | ImplicitConversion | Nullability; +const SanitizerMask Unrecoverable = Unreachable | Return; +const SanitizerMask AlwaysRecoverable = KernelAddress | KernelHWAddress; +const SanitizerMask LegacyFsanitizeRecoverMask = Undefined | Integer; +const SanitizerMask NeedsLTO = CFI; +const SanitizerMask TrappingSupported = + (Undefined & ~Vptr) | UnsignedIntegerOverflow | ImplicitConversion | + Nullability | LocalBounds | CFI; +const SanitizerMask TrappingDefault = CFI; +const SanitizerMask CFIClasses = + CFIVCall | CFINVCall | CFIMFCall | CFIDerivedCast | CFIUnrelatedCast; +const SanitizerMask CompatibleWithMinimalRuntime = + TrappingSupported | Scudo | ShadowCallStack; enum CoverageFeature { CoverageFunc = 1 << 0, @@ -136,10 +139,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(); @@ -203,24 +206,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, @@ -455,8 +460,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)) { @@ -959,18 +964,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/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 @@ -6199,7 +6199,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)