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