Skip to content

Commit ae5303d

Browse files
committed
[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". 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
1 parent afb3398 commit ae5303d

File tree

11 files changed

+323
-145
lines changed

11 files changed

+323
-145
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2366,7 +2366,7 @@ def NoSanitize : InheritableAttr {
23662366
let Documentation = [NoSanitizeDocs];
23672367
let AdditionalMembers = [{
23682368
SanitizerMask getMask() const {
2369-
SanitizerMask Mask = 0;
2369+
SanitizerMask Mask;
23702370
for (auto SanitizerName : sanitizers()) {
23712371
SanitizerMask ParsedMask =
23722372
parseSanitizerValue(SanitizerName, /*AllowGroups=*/true);

clang/include/clang/Basic/Sanitizers.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ SANITIZER("scudo", Scudo)
177177

178178
// Magic group, containing all sanitizers. For example, "-fno-sanitize=all"
179179
// can be used to disable all the sanitizers.
180-
SANITIZER_GROUP("all", All, ~0ULL)
180+
SANITIZER_GROUP("all", All, ~SanitizerMask())
181181

182182
#undef SANITIZER
183183
#undef SANITIZER_GROUP

clang/include/clang/Basic/Sanitizers.h

Lines changed: 142 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,56 +20,177 @@
2020
#include <cassert>
2121
#include <cstdint>
2222

23+
namespace llvm {
24+
class hash_code;
25+
}
26+
2327
namespace clang {
2428

25-
using SanitizerMask = uint64_t;
29+
class SanitizerMask {
30+
/// Number of array elements.
31+
static constexpr unsigned kNumElem = 2;
32+
/// Mask value initialized to 0.
33+
uint64_t maskLoToHigh[kNumElem]{};
34+
/// Number of bits in a mask.
35+
static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8;
36+
/// Number of bits in a mask element.
37+
static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8;
38+
39+
public:
40+
static constexpr bool checkBitPos(const unsigned Pos) {
41+
return Pos < kNumBits;
42+
}
2643

27-
namespace SanitizerKind {
44+
/// Create a mask with a bit enabled at position Pos.
45+
static SanitizerMask bitPosToMask(const unsigned Pos) {
46+
assert(Pos < kNumBits && "Bit position too big.");
47+
SanitizerMask mask;
48+
mask.maskLoToHigh[Pos / kNumBitElem] = 1ULL << Pos % kNumBitElem;
49+
return mask;
50+
}
2851

29-
// Assign ordinals to possible values of -fsanitize= flag, which we will use as
30-
// bit positions.
31-
enum SanitizerOrdinal : uint64_t {
32-
#define SANITIZER(NAME, ID) SO_##ID,
33-
#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
34-
#include "clang/Basic/Sanitizers.def"
35-
SO_Count
52+
unsigned countPopulation() const {
53+
unsigned total = 0;
54+
for (const auto &Val : maskLoToHigh)
55+
total += llvm::countPopulation(Val);
56+
return total;
57+
}
58+
59+
void flipAllBits() {
60+
for (auto &Val : maskLoToHigh)
61+
Val = ~Val;
62+
}
63+
64+
bool isPowerOf2() const {
65+
return countPopulation() == 1;
66+
}
67+
68+
llvm::hash_code hash_value() const;
69+
70+
explicit operator bool() const {
71+
for (const auto &Val : maskLoToHigh)
72+
if (Val)
73+
return true;
74+
return false;
75+
};
76+
77+
bool operator==(const SanitizerMask &V) const {
78+
for (unsigned k = 0; k < kNumElem; k++) {
79+
if (maskLoToHigh[k] != V.maskLoToHigh[k])
80+
return false;
81+
}
82+
return true;
83+
}
84+
85+
SanitizerMask &operator&=(const SanitizerMask &RHS) {
86+
for (unsigned k = 0; k < kNumElem; k++)
87+
maskLoToHigh[k] &= RHS.maskLoToHigh[k];
88+
return *this;
89+
}
90+
91+
SanitizerMask &operator|=(const SanitizerMask &RHS) {
92+
for (unsigned k = 0; k < kNumElem; k++)
93+
maskLoToHigh[k] |= RHS.maskLoToHigh[k];
94+
return *this;
95+
}
96+
97+
bool operator!() const {
98+
for (const auto &Val : maskLoToHigh)
99+
if (Val)
100+
return false;
101+
return true;
102+
}
103+
104+
bool operator!=(const SanitizerMask &RHS) const { return !((*this) == RHS); }
36105
};
37106

107+
// Declaring in clang namespace so that it can be found by ADL.
108+
llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
109+
110+
inline SanitizerMask operator~(SanitizerMask v) {
111+
v.flipAllBits();
112+
return v;
113+
}
114+
115+
inline SanitizerMask operator&(SanitizerMask a, const SanitizerMask &b) {
116+
a &= b;
117+
return a;
118+
}
119+
120+
inline SanitizerMask operator|(SanitizerMask a, const SanitizerMask &b) {
121+
a |= b;
122+
return a;
123+
}
124+
38125
// Define the set of sanitizer kinds, as well as the set of sanitizers each
39126
// sanitizer group expands into.
40-
#define SANITIZER(NAME, ID) \
41-
const SanitizerMask ID = 1ULL << SO_##ID;
42-
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
43-
const SanitizerMask ID = ALIAS; \
44-
const SanitizerMask ID##Group = 1ULL << SO_##ID##Group;
127+
// Uses static data member of a class template as recommended in second
128+
// workaround from n4424 to avoid odr issues.
129+
// FIXME: Can be marked as constexpr once c++14 can be used in llvm.
130+
// FIXME: n4424 workaround can be replaced by c++17 inline variable.
131+
template <typename T = void> struct SanitizerMasks {
132+
133+
// Assign ordinals to possible values of -fsanitize= flag, which we will use
134+
// as bit positions.
135+
enum SanitizerOrdinal : uint64_t {
136+
#define SANITIZER(NAME, ID) SO_##ID,
137+
#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
138+
#include "clang/Basic/Sanitizers.def"
139+
SO_Count
140+
};
141+
142+
#define SANITIZER(NAME, ID) \
143+
static const SanitizerMask ID; \
144+
static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
145+
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
146+
static const SanitizerMask ID; \
147+
static const SanitizerMask ID##Group; \
148+
static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \
149+
"Bit position too big.");
45150
#include "clang/Basic/Sanitizers.def"
151+
}; // SanitizerMasks
152+
153+
#define SANITIZER(NAME, ID) \
154+
template <typename T> \
155+
const SanitizerMask SanitizerMasks<T>::ID = \
156+
SanitizerMask::bitPosToMask(SO_##ID);
157+
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
158+
template <typename T> \
159+
const SanitizerMask SanitizerMasks<T>::ID = SanitizerMask(ALIAS); \
160+
template <typename T> \
161+
const SanitizerMask SanitizerMasks<T>::ID##Group = \
162+
SanitizerMask::bitPosToMask(SO_##ID##Group);
163+
#include "clang/Basic/Sanitizers.def"
164+
165+
// Explicit instantiation here to ensure correct initialization order.
166+
template struct SanitizerMasks<>;
46167

47-
} // namespace SanitizerKind
168+
using SanitizerKind = SanitizerMasks<>;
48169

49170
struct SanitizerSet {
50171
/// Check if a certain (single) sanitizer is enabled.
51172
bool has(SanitizerMask K) const {
52-
assert(llvm::isPowerOf2_64(K));
53-
return Mask & K;
173+
assert(K.isPowerOf2() && "Has to be a single sanitizer.");
174+
return static_cast<bool>(Mask & K);
54175
}
55176

56177
/// Check if one or more sanitizers are enabled.
57-
bool hasOneOf(SanitizerMask K) const { return Mask & K; }
178+
bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
58179

59180
/// Enable or disable a certain (single) sanitizer.
60181
void set(SanitizerMask K, bool Value) {
61-
assert(llvm::isPowerOf2_64(K));
182+
assert(K.isPowerOf2() && "Has to be a single sanitizer.");
62183
Mask = Value ? (Mask | K) : (Mask & ~K);
63184
}
64185

65186
/// Disable the sanitizers specified in \p K.
66187
void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
67188

68189
/// Returns true if no sanitizers are enabled.
69-
bool empty() const { return Mask == 0; }
190+
bool empty() const { return !Mask; }
70191

71192
/// Bitmask of enabled sanitizers.
72-
SanitizerMask Mask = 0;
193+
SanitizerMask Mask;
73194
};
74195

75196
/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.

clang/include/clang/Driver/ToolChain.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,9 @@ class ToolChain {
563563
virtual SanitizerMask getSupportedSanitizers() const;
564564

565565
/// Return sanitizers which are enabled by default.
566-
virtual SanitizerMask getDefaultSanitizers() const { return 0; }
566+
virtual SanitizerMask getDefaultSanitizers() const {
567+
return SanitizerMask();
568+
}
567569
};
568570

569571
/// Set a ToolChain's effective triple. Reset it when the registration object

clang/lib/Basic/SanitizerSpecialCaseList.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
3636

3737
void SanitizerSpecialCaseList::createSanitizerSections() {
3838
for (auto &S : Sections) {
39-
SanitizerMask Mask = 0;
39+
SanitizerMask Mask;
4040

4141
#define SANITIZER(NAME, ID) \
4242
if (S.SectionMatcher->match(NAME)) \

clang/lib/Basic/Sanitizers.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "clang/Basic/Sanitizers.h"
14+
#include "llvm/ADT/Hashing.h"
1415
#include "llvm/ADT/StringSwitch.h"
1516

1617
using namespace clang;
@@ -19,9 +20,9 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
1920
SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
2021
#define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID)
2122
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
22-
.Case(NAME, AllowGroups ? SanitizerKind::ID##Group : 0)
23+
.Case(NAME, AllowGroups ? SanitizerKind::ID##Group : SanitizerMask())
2324
#include "clang/Basic/Sanitizers.def"
24-
.Default(0);
25+
.Default(SanitizerMask());
2526
return ParsedKind;
2627
}
2728

@@ -33,3 +34,13 @@ SanitizerMask clang::expandSanitizerGroups(SanitizerMask Kinds) {
3334
#include "clang/Basic/Sanitizers.def"
3435
return Kinds;
3536
}
37+
38+
llvm::hash_code SanitizerMask::hash_value() const {
39+
return llvm::hash_combine_range(&maskLoToHigh[0], &maskLoToHigh[kNumElem]);
40+
}
41+
42+
namespace clang {
43+
llvm::hash_code hash_value(const clang::SanitizerMask &Arg) {
44+
return Arg.hash_value();
45+
}
46+
} // namespace clang

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,16 +2855,13 @@ enum class CheckRecoverableKind {
28552855
}
28562856

28572857
static CheckRecoverableKind getRecoverableKind(SanitizerMask Kind) {
2858-
assert(llvm::countPopulation(Kind) == 1);
2859-
switch (Kind) {
2860-
case SanitizerKind::Vptr:
2858+
assert(Kind.countPopulation() == 1);
2859+
if (Kind == SanitizerKind::Vptr)
28612860
return CheckRecoverableKind::AlwaysRecoverable;
2862-
case SanitizerKind::Return:
2863-
case SanitizerKind::Unreachable:
2861+
else if (Kind == SanitizerKind::Return || Kind == SanitizerKind::Unreachable)
28642862
return CheckRecoverableKind::Unrecoverable;
2865-
default:
2863+
else
28662864
return CheckRecoverableKind::Recoverable;
2867-
}
28682865
}
28692866

28702867
namespace {

0 commit comments

Comments
 (0)