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