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 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 167 struct SanitizerSet { 168 /// Check if a certain (single) sanitizer is enabled. 169 bool has(SanitizerMask K) const { 170 assert(K.isPowerOf2() && "Has to be a single sanitizer."); 171 return static_cast<bool>(Mask & K); 172 } 173 174 bool has(SanitizerKind::SanitizerOrdinal O) const { 175 return has(SanitizerMask::bitPosToMask(O)); 176 } 177 178 /// Check if one or more sanitizers are enabled. 179 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); } 180 181 /// Enable or disable a certain (single) sanitizer. 182 void set(SanitizerMask K, bool Value) { 183 assert(K.isPowerOf2() && "Has to be a single sanitizer."); 184 Mask = Value ? (Mask | K) : (Mask & ~K); 185 } 186 187 void set(SanitizerMask K) { Mask = K; } 188 189 /// Disable the sanitizers specified in \p K. 190 void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } 191 192 /// Returns true if no sanitizers are enabled. 193 bool empty() const { return !Mask; } 194 195 /// Bitmask of enabled sanitizers. 196 SanitizerMask Mask; 197 }; 198 199 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. 200 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known. 201 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); 202 203 /// Parse a single weighted value (e.g., 'undefined=0.05') from a -fsanitize= or 204 /// -fno-sanitize= value list. 205 /// The relevant weight(s) are updated in the passed Cutoffs parameter. 206 /// Individual Cutoffs are never reset to zero unless explicitly set 207 /// (e.g., 'null=0.0'). 208 /// Returns \c false if \p Value is not known or the weight is not valid. 209 bool parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, 210 SanitizerMaskCutoffs &Cutoffs); 211 212 /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=. 213 void serializeSanitizerSet(SanitizerSet Set, 214 SmallVectorImpl<StringRef> &Values); 215 216 /// Serialize a SanitizerMaskCutoffs into values for -fsanitize= or 217 /// -fno-sanitize=. 218 void serializeSanitizerMaskCutoffs(const SanitizerMaskCutoffs &Cutoffs, 219 SmallVectorImpl<std::string> &Values); 220 221 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers 222 /// this group enables. 223 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); 224 225 /// Return the sanitizers which do not affect preprocessing. 226 inline SanitizerMask getPPTransparentSanitizers() { 227 return SanitizerKind::CFI | SanitizerKind::Integer | 228 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | 229 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero; 230 } 231 232 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind); 233 234 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind); 235 236 StringRef AsanDetectStackUseAfterReturnModeToString( 237 llvm::AsanDetectStackUseAfterReturnMode mode); 238 239 llvm::AsanDetectStackUseAfterReturnMode 240 AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr); 241 242 } // namespace clang 243 244 #endif // LLVM_CLANG_BASIC_SANITIZERS_H 245