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(0); 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 @@ -15,14 +15,89 @@ #define LLVM_CLANG_BASIC_SANITIZERS_H #include "clang/Basic/LLVM.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MathExtras.h" #include #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: + llvm::APInt mask; + +public: + // Size of SanitizerMask's bit mask in bits. + static const int kNumBits = 128; + + SanitizerMask() : mask(kNumBits, 0) {} + + explicit SanitizerMask(uint64_t val) : mask(kNumBits, val) {} + + explicit SanitizerMask(const llvm::APInt &v) : mask(v) {} + + void flipAllBits() { mask.flipAllBits(); } + + bool isPowerOf2() const { return mask.isPowerOf2(); } + + unsigned countPopulation() const { return mask.countPopulation(); } + + llvm::hash_code hash_value() const; + + explicit operator bool() { return mask.getBoolValue(); }; -using SanitizerMask = uint64_t; + SanitizerMask operator<<(const SanitizerKind::SanitizerOrdinal &Bits) const { + assert(Bits < kNumBits && "Bit shift too big."); + return SanitizerMask(mask << Bits); + } + + bool operator==(const SanitizerMask &V) const { return mask == V.mask; } + + bool operator==(uint64_t Val) const { return mask == Val; } + + SanitizerMask &operator&=(const SanitizerMask &RHS) { + mask &= RHS.mask; + return *this; + } + + SanitizerMask &operator|=(const SanitizerMask &RHS) { + mask |= RHS.mask; + return *this; + } + + bool operator!() const { return !mask; } + + 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 SanitizerMask(a); +} namespace SanitizerKind { @@ -37,11 +112,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(SO_##ID < SanitizerMask::kNumBits, \ + "Bit shift value too big."); \ + const SanitizerMask ID = SanitizerMask(1ULL) << SO_##ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + static_assert(SO_##ID##Group < SanitizerMask::kNumBits, \ + "Bit shift value too big."); \ + const SanitizerMask ID = SanitizerMask(ALIAS); \ + const SanitizerMask ID##Group = SanitizerMask(1ULL) << SO_##ID##Group; #include "clang/Basic/Sanitizers.def" } // namespace SanitizerKind @@ -49,16 +128,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); } @@ -69,7 +148,7 @@ bool empty() const { return Mask == 0; } /// Bitmask of enabled sanitizers. - SanitizerMask Mask = 0; + SanitizerMask Mask = SanitizerMask(0); }; /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. 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(0); + } }; /// 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(0); #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(0)) #include "clang/Basic/Sanitizers.def" - .Default(0); + .Default(SanitizerMask(0)); return ParsedKind; } @@ -33,3 +34,13 @@ #include "clang/Basic/Sanitizers.def" return Kinds; } + +llvm::hash_code SanitizerMask::hash_value() const { + return llvm::hash_value(mask); +} + +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(0); // 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(0); 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(0); // 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(0); // 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(0); // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. - SanitizerMask Kinds = 0; + SanitizerMask Kinds(0); 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(0); + SanitizerMask DiagnosedAlwaysRecoverableKinds(0); 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(0); 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(0); // 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(0); else Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);