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