pgousseau created this revision.
pgousseau added reviewers: rsmith, probinson, gbedwell, filcab, lebedev.ri, 
wristow.
Herald added subscribers: cfe-commits, cryptoad.
Herald added a project: clang.

enum SanitizerOrdinal has reached maximum capacity, this change extends the 
capacity to 128 sanitizer checks.
Uses APInt to represent the bit mask.
This can eventually allow us to add gcc 8's options 
"-fsanitize=pointer-substract" and "-fsanitize=pointer-compare".

Fixes: https://llvm.org/PR39425


Repository:
  rC Clang

https://reviews.llvm.org/D57914

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/Sanitizers.h
  include/clang/Driver/ToolChain.h
  lib/Basic/SanitizerSpecialCaseList.cpp
  lib/Basic/Sanitizers.cpp
  lib/CodeGen/CGExpr.cpp
  lib/Driver/SanitizerArgs.cpp

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<bool>(Sanitizers.Mask & NeedsUnwindTables);
 }
 
-bool SanitizerArgs::needsLTO() const { return Sanitizers.Mask & NeedsLTO; }
+bool SanitizerArgs::needsLTO() const {
+  return static_cast<bool>(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);
 
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/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<SanitizerMask>(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/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: 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: 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 <cassert>
 #include <cstdint>
 
 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;
+}
+
+// Size of SanitizerMask's bit mask in bits.
+static const int kNumBits = 128;
+
+struct SanitizerMask {
+private:
+  llvm::APInt mask;
+
+public:
+  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,13 @@
 
 // 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 < kNumBits, "Bit shift value too big.");               \
+  const SanitizerMask ID = SanitizerMask(1ULL) << SO_##ID;
+#define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \
+  static_assert(SO_##ID##Group < 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 +126,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<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());
     Mask = Value ? (Mask | K) : (Mask & ~K);
   }
 
@@ -69,7 +146,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/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);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to