1 //===- Sanitizers.h - C Language Family Language Options --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file
10 /// Defines the clang::SanitizerKind enum.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_CLANG_BASIC_SANITIZERS_H
15 #define LLVM_CLANG_BASIC_SANITIZERS_H
16
17 #include "clang/Basic/LLVM.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/MathExtras.h"
20 #include <cassert>
21 #include <cstdint>
22
23 namespace llvm {
24 class hash_code;
25 }
26
27 namespace clang {
28
29 class SanitizerMask {
30 // NOTE: this class assumes kNumElem == 2 in most of the constexpr functions,
31 // in order to work within the C++11 constexpr function constraints. If you
32 // change kNumElem, you'll need to update those member functions as well.
33
34 /// Number of array elements.
35 static constexpr unsigned kNumElem = 2;
36 /// Mask value initialized to 0.
37 uint64_t maskLoToHigh[kNumElem]{};
38 /// Number of bits in a mask.
39 static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8;
40 /// Number of bits in a mask element.
41 static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8;
42
SanitizerMask(uint64_t mask1,uint64_t mask2)43 constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
44 : maskLoToHigh{mask1, mask2} {}
45
46 public:
47 SanitizerMask() = default;
48
checkBitPos(const unsigned Pos)49 static constexpr bool checkBitPos(const unsigned Pos) {
50 return Pos < kNumBits;
51 }
52
53 /// Create a mask with a bit enabled at position Pos.
bitPosToMask(const unsigned Pos)54 static constexpr SanitizerMask bitPosToMask(const unsigned Pos) {
55 uint64_t mask1 = (Pos < kNumBitElem) ? 1ULL << (Pos % kNumBitElem) : 0;
56 uint64_t mask2 = (Pos >= kNumBitElem && Pos < (kNumBitElem * 2))
57 ? 1ULL << (Pos % kNumBitElem)
58 : 0;
59 return SanitizerMask(mask1, mask2);
60 }
61
countPopulation()62 unsigned countPopulation() const {
63 unsigned total = 0;
64 for (const auto &Val : maskLoToHigh)
65 total += llvm::countPopulation(Val);
66 return total;
67 }
68
flipAllBits()69 void flipAllBits() {
70 for (auto &Val : maskLoToHigh)
71 Val = ~Val;
72 }
73
isPowerOf2()74 bool isPowerOf2() const {
75 return countPopulation() == 1;
76 }
77
78 llvm::hash_code hash_value() const;
79
80 constexpr explicit operator bool() const {
81 return maskLoToHigh[0] || maskLoToHigh[1];
82 }
83
84 constexpr bool operator==(const SanitizerMask &V) const {
85 return maskLoToHigh[0] == V.maskLoToHigh[0] &&
86 maskLoToHigh[1] == V.maskLoToHigh[1];
87 }
88
89 SanitizerMask &operator&=(const SanitizerMask &RHS) {
90 for (unsigned k = 0; k < kNumElem; k++)
91 maskLoToHigh[k] &= RHS.maskLoToHigh[k];
92 return *this;
93 }
94
95 SanitizerMask &operator|=(const SanitizerMask &RHS) {
96 for (unsigned k = 0; k < kNumElem; k++)
97 maskLoToHigh[k] |= RHS.maskLoToHigh[k];
98 return *this;
99 }
100
101 constexpr bool operator!() const { return !bool(*this); }
102
103 constexpr bool operator!=(const SanitizerMask &RHS) const {
104 return !((*this) == RHS);
105 }
106
107 friend constexpr inline SanitizerMask operator~(SanitizerMask v) {
108 return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]);
109 }
110
111 friend constexpr inline SanitizerMask operator&(SanitizerMask a,
112 const SanitizerMask &b) {
113 return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0],
114 a.maskLoToHigh[1] & b.maskLoToHigh[1]);
115 }
116
117 friend constexpr inline SanitizerMask operator|(SanitizerMask a,
118 const SanitizerMask &b) {
119 return SanitizerMask(a.maskLoToHigh[0] | b.maskLoToHigh[0],
120 a.maskLoToHigh[1] | b.maskLoToHigh[1]);
121 }
122 };
123
124 // Declaring in clang namespace so that it can be found by ADL.
125 llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
126
127 // Define the set of sanitizer kinds, as well as the set of sanitizers each
128 // sanitizer group expands into.
129 struct SanitizerKind {
130 // Assign ordinals to possible values of -fsanitize= flag, which we will use
131 // as bit positions.
132 enum SanitizerOrdinal : uint64_t {
133 #define SANITIZER(NAME, ID) SO_##ID,
134 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
135 #include "clang/Basic/Sanitizers.def"
136 SO_Count
137 };
138
139 #define SANITIZER(NAME, ID) \
140 static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID); \
141 static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
142 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
143 static constexpr SanitizerMask ID = SanitizerMask(ALIAS); \
144 static constexpr SanitizerMask ID##Group = \
145 SanitizerMask::bitPosToMask(SO_##ID##Group); \
146 static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \
147 "Bit position too big.");
148 #include "clang/Basic/Sanitizers.def"
149 }; // SanitizerKind
150
151 struct SanitizerSet {
152 /// Check if a certain (single) sanitizer is enabled.
hasSanitizerSet153 bool has(SanitizerMask K) const {
154 assert(K.isPowerOf2() && "Has to be a single sanitizer.");
155 return static_cast<bool>(Mask & K);
156 }
157
158 /// Check if one or more sanitizers are enabled.
hasOneOfSanitizerSet159 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
160
161 /// Enable or disable a certain (single) sanitizer.
setSanitizerSet162 void set(SanitizerMask K, bool Value) {
163 assert(K.isPowerOf2() && "Has to be a single sanitizer.");
164 Mask = Value ? (Mask | K) : (Mask & ~K);
165 }
166
167 /// Disable the sanitizers specified in \p K.
168 void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
169
170 /// Returns true if no sanitizers are enabled.
emptySanitizerSet171 bool empty() const { return !Mask; }
172
173 /// Bitmask of enabled sanitizers.
174 SanitizerMask Mask;
175 };
176
177 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
178 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
179 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
180
181 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
182 /// this group enables.
183 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
184
185 /// Return the sanitizers which do not affect preprocessing.
getPPTransparentSanitizers()186 inline SanitizerMask getPPTransparentSanitizers() {
187 return SanitizerKind::CFI | SanitizerKind::Integer |
188 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
189 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
190 }
191
192 } // namespace clang
193
194 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
195