Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 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 |