diff options
author | Pierre Gousseau <pierregousseau14@gmail.com> | 2019-02-26 13:30:14 +0000 |
---|---|---|
committer | Pierre Gousseau <pierregousseau14@gmail.com> | 2019-02-26 13:30:14 +0000 |
commit | 9965c063dc20292a7711353ca9ce8f0ed2949929 (patch) | |
tree | 574726c406d6e0ed7fbff14b41c8083f829a6470 /include/clang/Basic/Sanitizers.h | |
parent | ee7f333417faa3ce635561782f9a52efabd7ccd7 (diff) | |
download | clang-9965c063dc20292a7711353ca9ce8f0ed2949929.tar.gz |
[Driver] Allow enum SanitizerOrdinal to represent more than 64 different sanitizer checks, NFC.
enum SanitizerOrdinal has reached maximum capacity, this change extends the capacity to 128 sanitizer checks.
This can eventually allow us to add gcc 8's options "-fsanitize=pointer-substract" and "-fsanitize=pointer-compare".
Fixes: https://llvm.org/PR39425
Differential Revision: https://reviews.llvm.org/D57914
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@354873 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang/Basic/Sanitizers.h')
-rw-r--r-- | include/clang/Basic/Sanitizers.h | 165 |
1 files changed, 144 insertions, 21 deletions
diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h index f2cfadbee0..afbdf63840 100644 --- a/include/clang/Basic/Sanitizers.h +++ b/include/clang/Basic/Sanitizers.h @@ -21,44 +21,167 @@ #include <cstdint> 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 <typename T = void> 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 <typename T> \ + const SanitizerMask SanitizerMasks<T>::ID = \ + SanitizerMask::bitPosToMask(SO_##ID); +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + template <typename T> \ + const SanitizerMask SanitizerMasks<T>::ID = SanitizerMask(ALIAS); \ + template <typename T> \ + const SanitizerMask SanitizerMasks<T>::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<bool>(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<bool>(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 @@ struct SanitizerSet { 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. |