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,109 @@ #include namespace clang { +struct SanitizerMask; +} + +namespace llvm { +class hashcode; +hash_code hash_value(const clang::SanitizerMask &Arg); +} // namespace llvm + +namespace clang { + +namespace SanitizerKind { +enum SanitizerOrdinal : uint64_t; +} + +struct SanitizerMask { +private: + // Number of bits in a mask. + static const int kNumBits = 128; + // Low bits of mask value. + uint64_t maskLo; + // High bits of mask value. + uint64_t maskHi; + + explicit SanitizerMask(uint64_t lo, uint64_t hi) : maskLo(lo), maskHi(hi) {} + +public: + static_assert(kNumBits <= ((sizeof(maskLo) + sizeof(maskHi)) * 8), + "Too many bits."); + static_assert(llvm::isPowerOf2_32(kNumBits), + "kNumBits should be power of 2."); + + SanitizerMask() : maskLo(0), maskHi(0) {} + + 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); + SanitizerMask mask; + if (Pos < kNumBits / 2) { + mask.maskLo = 1ULL << Pos; + mask.maskHi = 0; + } else { + mask.maskLo = 0; + mask.maskHi = 1ULL << (Pos - kNumBits / 2); + } + return mask; + } + + unsigned countPopulation() const { + return llvm::countPopulation(maskLo) + llvm::countPopulation(maskHi); + } + + void flipAllBits() { maskLo = ~maskLo; maskHi = ~maskHi; } -using SanitizerMask = uint64_t; + bool isPowerOf2() const { + return (llvm::isPowerOf2_64(maskLo) && !maskHi) || + (llvm::isPowerOf2_64(maskHi) && !maskLo); + } + + llvm::hash_code hash_value() const; + + explicit operator bool() { return maskLo || maskHi; }; + + bool operator==(const SanitizerMask &V) const { + return maskLo == V.maskLo && maskHi == V.maskHi; + } + + SanitizerMask &operator&=(const SanitizerMask &RHS) { + maskLo &= RHS.maskLo; + maskHi &= RHS.maskHi; + return *this; + } + + SanitizerMask &operator|=(const SanitizerMask &RHS) { + maskLo |= RHS.maskLo; + maskHi |= RHS.maskHi; + return *this; + } + + bool operator!() const { return !maskLo && !maskHi; } + + 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; +} namespace SanitizerKind { @@ -37,11 +138,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 +154,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()); + 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()); Mask = Value ? (Mask | K) : (Mask & ~K); } @@ -66,10 +171,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(maskLo, maskHi); +} + +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, -}; +SanitizerMask NeedsUbsanRt = + Undefined | Integer | ImplicitConversion | Nullability | CFI; +SanitizerMask NeedsUbsanCxxRt = Vptr | CFI; +SanitizerMask NotAllowedWithTrap = Vptr; +SanitizerMask NotAllowedWithMinimalRuntime = Vptr; +SanitizerMask RequiresPIE = DataFlow | HWAddress | Scudo; +SanitizerMask NeedsUnwindTables = + Address | HWAddress | Thread | Memory | DataFlow; +SanitizerMask SupportsCoverage = + Address | HWAddress | KernelAddress | KernelHWAddress | Memory | + KernelMemory | Leak | Undefined | Integer | ImplicitConversion | + Nullability | DataFlow | Fuzzer | FuzzerNoLink; +SanitizerMask RecoverableByDefault = + Undefined | Integer | ImplicitConversion | Nullability; +SanitizerMask Unrecoverable = Unreachable | Return; +SanitizerMask AlwaysRecoverable = KernelAddress | KernelHWAddress; +SanitizerMask LegacyFsanitizeRecoverMask = Undefined | Integer; +SanitizerMask NeedsLTO = CFI; +SanitizerMask TrappingSupported = (Undefined & ~Vptr) | + UnsignedIntegerOverflow | ImplicitConversion | + Nullability | LocalBounds | CFI; +SanitizerMask TrappingDefault = CFI; +SanitizerMask CFIClasses = + CFIVCall | CFINVCall | CFIMFCall | CFIDerivedCast | CFIUnrelatedCast; +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)