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
SanitizerMask(uint64_t mask1,uint64_t mask2)48 constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
49 : maskLoToHigh{mask1, mask2} {}
50
51 public:
52 SanitizerMask() = default;
53
checkBitPos(const unsigned Pos)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.
bitPosToMask(const unsigned 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
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 template <typename HasherT, llvm::endianness Endianness>
addHash(llvm::HashBuilder<HasherT,Endianness> & HBuilder,const SanitizerMask & SM)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 class SanitizerMaskCutoffs {
158 std::vector<double> Cutoffs;
159
160 public:
161 std::optional<double> operator[](unsigned Kind) const;
162
163 void set(SanitizerMask K, double V);
164 void clear(SanitizerMask K = SanitizerKind::All);
165
166 // Returns nullopt if all the values are zero.
167 // Otherwise, return value contains a vector of all the scaled values.
168 std::optional<std::vector<unsigned>>
169 getAllScaled(unsigned ScalingFactor) const;
170 };
171
172 struct SanitizerSet {
173 /// Check if a certain (single) sanitizer is enabled.
hasSanitizerSet174 bool has(SanitizerMask K) const {
175 assert(K.isPowerOf2() && "Has to be a single sanitizer.");
176 return static_cast<bool>(Mask & K);
177 }
178
hasSanitizerSet179 bool has(SanitizerKind::SanitizerOrdinal O) const {
180 return has(SanitizerMask::bitPosToMask(O));
181 }
182
183 /// Check if one or more sanitizers are enabled.
hasOneOfSanitizerSet184 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
185
186 /// Enable or disable a certain (single) sanitizer.
setSanitizerSet187 void set(SanitizerMask K, bool Value) {
188 assert(K.isPowerOf2() && "Has to be a single sanitizer.");
189 Mask = Value ? (Mask | K) : (Mask & ~K);
190 }
191
setSanitizerSet192 void set(SanitizerMask K) { Mask = K; }
193
194 /// Disable the sanitizers specified in \p K.
195 void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
196
197 /// Returns true if no sanitizers are enabled.
emptySanitizerSet198 bool empty() const { return !Mask; }
199
200 /// Bitmask of enabled sanitizers.
201 SanitizerMask Mask;
202 };
203
204 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
205 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
206 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
207
208 /// Parse a single weighted value (e.g., 'undefined=0.05') from a -fsanitize= or
209 /// -fno-sanitize= value list.
210 /// The relevant weight(s) are updated in the passed Cutoffs parameter.
211 /// Individual Cutoffs are never reset to zero unless explicitly set
212 /// (e.g., 'null=0.0').
213 /// Returns \c false if \p Value is not known or the weight is not valid.
214 bool parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
215 SanitizerMaskCutoffs &Cutoffs);
216
217 /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
218 void serializeSanitizerSet(SanitizerSet Set,
219 SmallVectorImpl<StringRef> &Values);
220
221 /// Serialize a SanitizerMaskCutoffs into command line arguments.
222 void serializeSanitizerMaskCutoffs(const SanitizerMaskCutoffs &Cutoffs,
223 SmallVectorImpl<std::string> &Values);
224
225 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
226 /// this group enables.
227 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
228
229 /// Return the sanitizers which do not affect preprocessing.
getPPTransparentSanitizers()230 inline SanitizerMask getPPTransparentSanitizers() {
231 return SanitizerKind::CFI | SanitizerKind::Integer |
232 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
233 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
234 }
235
236 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
237
238 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
239
240 StringRef AsanDetectStackUseAfterReturnModeToString(
241 llvm::AsanDetectStackUseAfterReturnMode mode);
242
243 llvm::AsanDetectStackUseAfterReturnMode
244 AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr);
245
246 } // namespace clang
247
248 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
249