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 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 65 void flipAllBits() { 66 for (auto &Val : maskLoToHigh) 67 Val = ~Val; 68 } 69 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> 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. 155 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. 161 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); } 162 163 /// Enable or disable a certain (single) sanitizer. 164 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. 173 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. 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