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 <cassert> 21 #include <cstdint> 22 23 namespace llvm { 24 class hash_code; 25 } 26 27 namespace clang { 28 29 class SanitizerMask { 30 // NOTE: this class assumes kNumElem == 2 in most of the constexpr functions, 31 // in order to work within the C++11 constexpr function constraints. If you 32 // change kNumElem, you'll need to update those member functions as well. 33 34 /// Number of array elements. 35 static constexpr unsigned kNumElem = 2; 36 /// Mask value initialized to 0. 37 uint64_t maskLoToHigh[kNumElem]{}; 38 /// Number of bits in a mask. 39 static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8; 40 /// Number of bits in a mask element. 41 static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8; 42 43 constexpr SanitizerMask(uint64_t mask1, uint64_t mask2) 44 : maskLoToHigh{mask1, mask2} {} 45 46 public: 47 SanitizerMask() = default; 48 49 static constexpr bool checkBitPos(const unsigned Pos) { 50 return Pos < kNumBits; 51 } 52 53 /// Create a mask with a bit enabled at position Pos. 54 static constexpr SanitizerMask bitPosToMask(const unsigned Pos) { 55 uint64_t mask1 = (Pos < kNumBitElem) ? 1ULL << (Pos % kNumBitElem) : 0; 56 uint64_t mask2 = (Pos >= kNumBitElem && Pos < (kNumBitElem * 2)) 57 ? 1ULL << (Pos % kNumBitElem) 58 : 0; 59 return SanitizerMask(mask1, mask2); 60 } 61 62 unsigned countPopulation() const { 63 unsigned total = 0; 64 for (const auto &Val : maskLoToHigh) 65 total += llvm::countPopulation(Val); 66 return total; 67 } 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 constexpr explicit operator bool() const { 81 return maskLoToHigh[0] || maskLoToHigh[1]; 82 } 83 84 constexpr bool operator==(const SanitizerMask &V) const { 85 return maskLoToHigh[0] == V.maskLoToHigh[0] && 86 maskLoToHigh[1] == V.maskLoToHigh[1]; 87 } 88 89 SanitizerMask &operator&=(const SanitizerMask &RHS) { 90 for (unsigned k = 0; k < kNumElem; k++) 91 maskLoToHigh[k] &= RHS.maskLoToHigh[k]; 92 return *this; 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 constexpr bool operator!() const { return !bool(*this); } 102 103 constexpr bool operator!=(const SanitizerMask &RHS) const { 104 return !((*this) == RHS); 105 } 106 107 friend constexpr inline SanitizerMask operator~(SanitizerMask v) { 108 return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]); 109 } 110 111 friend constexpr inline SanitizerMask operator&(SanitizerMask a, 112 const SanitizerMask &b) { 113 return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0], 114 a.maskLoToHigh[1] & b.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 124 // Declaring in clang namespace so that it can be found by ADL. 125 llvm::hash_code hash_value(const clang::SanitizerMask &Arg); 126 127 // Define the set of sanitizer kinds, as well as the set of sanitizers each 128 // sanitizer group expands into. 129 struct SanitizerKind { 130 // Assign ordinals to possible values of -fsanitize= flag, which we will use 131 // as bit positions. 132 enum SanitizerOrdinal : uint64_t { 133 #define SANITIZER(NAME, ID) SO_##ID, 134 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, 135 #include "clang/Basic/Sanitizers.def" 136 SO_Count 137 }; 138 139 #define SANITIZER(NAME, ID) \ 140 static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID); \ 141 static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big."); 142 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 143 static constexpr SanitizerMask ID = SanitizerMask(ALIAS); \ 144 static constexpr SanitizerMask ID##Group = \ 145 SanitizerMask::bitPosToMask(SO_##ID##Group); \ 146 static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \ 147 "Bit position too big."); 148 #include "clang/Basic/Sanitizers.def" 149 }; // SanitizerKind 150 151 struct SanitizerSet { 152 /// Check if a certain (single) sanitizer is enabled. 153 bool has(SanitizerMask K) const { 154 assert(K.isPowerOf2() && "Has to be a single sanitizer."); 155 return static_cast<bool>(Mask & K); 156 } 157 158 /// Check if one or more sanitizers are enabled. 159 bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); } 160 161 /// Enable or disable a certain (single) sanitizer. 162 void set(SanitizerMask K, bool Value) { 163 assert(K.isPowerOf2() && "Has to be a single sanitizer."); 164 Mask = Value ? (Mask | K) : (Mask & ~K); 165 } 166 167 /// Disable the sanitizers specified in \p K. 168 void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } 169 170 /// Returns true if no sanitizers are enabled. 171 bool empty() const { return !Mask; } 172 173 /// Bitmask of enabled sanitizers. 174 SanitizerMask Mask; 175 }; 176 177 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. 178 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known. 179 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); 180 181 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers 182 /// this group enables. 183 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); 184 185 /// Return the sanitizers which do not affect preprocessing. 186 inline SanitizerMask getPPTransparentSanitizers() { 187 return SanitizerKind::CFI | SanitizerKind::Integer | 188 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | 189 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero; 190 } 191 192 } // namespace clang 193 194 #endif // LLVM_CLANG_BASIC_SANITIZERS_H 195