Skip to content

Commit

Permalink
[Driver] Allow enum SanitizerOrdinal to represent more than 64 differ…
Browse files Browse the repository at this point in the history
…ent 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".

This is a recommit of r354873 but with a fix for unqualified lookup error in lldb cmake build bot.

Fixes: https://llvm.org/PR39425

Differential Revision: https://reviews.llvm.org/D57914

llvm-svn: 355190
  • Loading branch information
goussepi committed Mar 1, 2019
1 parent afb3398 commit ae5303d
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 145 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2366,7 +2366,7 @@ def NoSanitize : InheritableAttr {
let Documentation = [NoSanitizeDocs];
let AdditionalMembers = [{
SanitizerMask getMask() const {
SanitizerMask Mask = 0;
SanitizerMask Mask;
for (auto SanitizerName : sanitizers()) {
SanitizerMask ParsedMask =
parseSanitizerValue(SanitizerName, /*AllowGroups=*/true);
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Sanitizers.def
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ SANITIZER("scudo", Scudo)

// 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
163 changes: 142 additions & 21 deletions clang/include/clang/Basic/Sanitizers.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,56 +20,177 @@
#include <cassert>
#include <cstdint>

namespace llvm {
class hash_code;
}

namespace clang {

using SanitizerMask = 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(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;
}

namespace SanitizerKind {
/// 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;
}

// 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
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); }
};

// Declaring in clang namespace so that it can be found by ADL.
llvm::hash_code hash_value(const clang::SanitizerMask &Arg);

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);
}

/// Disable the sanitizers specified in \p K.
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.
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Driver/ToolChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,9 @@ class ToolChain {
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
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/SanitizerSpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {

void SanitizerSpecialCaseList::createSanitizerSections() {
for (auto &S : Sections) {
SanitizerMask Mask = 0;
SanitizerMask Mask;

#define SANITIZER(NAME, ID) \
if (S.SectionMatcher->match(NAME)) \
Expand Down
15 changes: 13 additions & 2 deletions clang/lib/Basic/Sanitizers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "clang/Basic/Sanitizers.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringSwitch.h"

using namespace clang;
Expand All @@ -19,9 +20,9 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
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())
#include "clang/Basic/Sanitizers.def"
.Default(0);
.Default(SanitizerMask());
return ParsedKind;
}

Expand All @@ -33,3 +34,13 @@ SanitizerMask clang::expandSanitizerGroups(SanitizerMask Kinds) {
#include "clang/Basic/Sanitizers.def"
return Kinds;
}

llvm::hash_code SanitizerMask::hash_value() const {
return llvm::hash_combine_range(&maskLoToHigh[0], &maskLoToHigh[kNumElem]);
}

namespace clang {
llvm::hash_code hash_value(const clang::SanitizerMask &Arg) {
return Arg.hash_value();
}
} // namespace clang
11 changes: 4 additions & 7 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2855,16 +2855,13 @@ enum class CheckRecoverableKind {
}

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 {
Expand Down
Loading

0 comments on commit ae5303d

Please sign in to comment.