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 }
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
SanitizerMask(uint64_t mask1,uint64_t mask2)44 constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
45 : maskLoToHigh{mask1, mask2} {}
46
47 public:
48 SanitizerMask() = default;
49
checkBitPos(const unsigned Pos)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.
bitPosToMask(const unsigned 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
flipAllBits()65 void flipAllBits() {
66 for (auto &Val : maskLoToHigh)
67 Val = ~Val;
68 }
69
isPowerOf2()70 bool isPowerOf2() const {
71 return countPopulation() == 1;
72 }
73
74 llvm::hash_code hash_value() const;
75
76 template <typename HasherT, llvm::support::endianness Endianness>
addHash(llvm::HashBuilderImpl<HasherT,Endianness> & HBuilder,const SanitizerMask & SM)77 friend void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder,
78 const SanitizerMask &SM) {
79 HBuilder.addRange(&SM.maskLoToHigh[0], &SM.maskLoToHigh[kNumElem]);
80 }
81
82 constexpr explicit operator bool() const {
83 return maskLoToHigh[0] || maskLoToHigh[1];
84 }
85
86 constexpr bool operator==(const SanitizerMask &V) const {
87 return maskLoToHigh[0] == V.maskLoToHigh[0] &&
88 maskLoToHigh[1] == V.maskLoToHigh[1];
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 SanitizerMask &operator|=(const SanitizerMask &RHS) {
98 for (unsigned k = 0; k < kNumElem; k++)
99 maskLoToHigh[k] |= RHS.maskLoToHigh[k];
100 return *this;
101 }
102
103 constexpr bool operator!() const { return !bool(*this); }
104
105 constexpr bool operator!=(const SanitizerMask &RHS) const {
106 return !((*this) == RHS);
107 }
108
109 friend constexpr inline SanitizerMask operator~(SanitizerMask v) {
110 return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]);
111 }
112
113 friend constexpr inline SanitizerMask operator&(SanitizerMask a,
114 const SanitizerMask &b) {
115 return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0],
116 a.maskLoToHigh[1] & b.maskLoToHigh[1]);
117 }
118
119 friend constexpr inline SanitizerMask operator|(SanitizerMask a,
120 const SanitizerMask &b) {
121 return SanitizerMask(a.maskLoToHigh[0] | b.maskLoToHigh[0],
122 a.maskLoToHigh[1] | b.maskLoToHigh[1]);
123 }
124 };
125
126 // Declaring in clang namespace so that it can be found by ADL.
127 llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
128
129 // Define the set of sanitizer kinds, as well as the set of sanitizers each
130 // sanitizer group expands into.
131 struct SanitizerKind {
132 // Assign ordinals to possible values of -fsanitize= flag, which we will use
133 // as bit positions.
134 enum SanitizerOrdinal : uint64_t {
135 #define SANITIZER(NAME, ID) SO_##ID,
136 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
137 #include "clang/Basic/Sanitizers.def"
138 SO_Count
139 };
140
141 #define SANITIZER(NAME, ID) \
142 static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID); \
143 static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
144 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
145 static constexpr SanitizerMask ID = SanitizerMask(ALIAS); \
146 static constexpr SanitizerMask ID##Group = \
147 SanitizerMask::bitPosToMask(SO_##ID##Group); \
148 static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \
149 "Bit position too big.");
150 #include "clang/Basic/Sanitizers.def"
151 }; // SanitizerKind
152
153 struct SanitizerSet {
154 /// Check if a certain (single) sanitizer is enabled.
hasSanitizerSet155 bool has(SanitizerMask K) const {
156 assert(K.isPowerOf2() && "Has to be a single sanitizer.");
157 return static_cast<bool>(Mask & K);
158 }
159
160 /// Check if one or more sanitizers are enabled.
hasOneOfSanitizerSet161 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
162
163 /// Enable or disable a certain (single) sanitizer.
setSanitizerSet164 void set(SanitizerMask K, bool Value) {
165 assert(K.isPowerOf2() && "Has to be a single sanitizer.");
166 Mask = Value ? (Mask | K) : (Mask & ~K);
167 }
168
169 /// Disable the sanitizers specified in \p K.
170 void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
171
172 /// Returns true if no sanitizers are enabled.
emptySanitizerSet173 bool empty() const { return !Mask; }
174
175 /// Bitmask of enabled sanitizers.
176 SanitizerMask Mask;
177 };
178
179 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
180 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
181 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
182
183 /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
184 void serializeSanitizerSet(SanitizerSet Set,
185 SmallVectorImpl<StringRef> &Values);
186
187 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
188 /// this group enables.
189 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
190
191 /// Return the sanitizers which do not affect preprocessing.
getPPTransparentSanitizers()192 inline SanitizerMask getPPTransparentSanitizers() {
193 return SanitizerKind::CFI | SanitizerKind::Integer |
194 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
195 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
196 }
197
198 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
199
200 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
201
202 StringRef AsanDetectStackUseAfterReturnModeToString(
203 llvm::AsanDetectStackUseAfterReturnMode mode);
204
205 llvm::AsanDetectStackUseAfterReturnMode
206 AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr);
207
208 } // namespace clang
209
210 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
211