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::support::endianness Endianness> 81 friend void addHash(llvm::HashBuilderImpl<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 struct SanitizerSet { 158 /// Check if a certain (single) sanitizer is enabled. 159 bool has(SanitizerMask K) const { 160 assert(K.isPowerOf2() && "Has to be a single sanitizer."); 161 return static_cast<bool>(Mask & K); 162 } 163 164 /// Check if one or more sanitizers are enabled. 165 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); } 166 167 /// Enable or disable a certain (single) sanitizer. 168 void set(SanitizerMask K, bool Value) { 169 assert(K.isPowerOf2() && "Has to be a single sanitizer."); 170 Mask = Value ? (Mask | K) : (Mask & ~K); 171 } 172 173 /// Disable the sanitizers specified in \p K. 174 void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } 175 176 /// Returns true if no sanitizers are enabled. 177 bool empty() const { return !Mask; } 178 179 /// Bitmask of enabled sanitizers. 180 SanitizerMask Mask; 181 }; 182 183 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. 184 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known. 185 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); 186 187 /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=. 188 void serializeSanitizerSet(SanitizerSet Set, 189 SmallVectorImpl<StringRef> &Values); 190 191 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers 192 /// this group enables. 193 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); 194 195 /// Return the sanitizers which do not affect preprocessing. 196 inline SanitizerMask getPPTransparentSanitizers() { 197 return SanitizerKind::CFI | SanitizerKind::Integer | 198 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | 199 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero; 200 } 201 202 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind); 203 204 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind); 205 206 StringRef AsanDetectStackUseAfterReturnModeToString( 207 llvm::AsanDetectStackUseAfterReturnMode mode); 208 209 llvm::AsanDetectStackUseAfterReturnMode 210 AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr); 211 212 } // namespace clang 213 214 #endif // LLVM_CLANG_BASIC_SANITIZERS_H 215