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 23namespace llvm { 24class hash_code; 25} 26 27namespace clang { 28 29class 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 46public: 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. 125llvm::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. 129struct 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 151struct 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. 179SanitizerMask 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. 183SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); 184 185/// Return the sanitizers which do not affect preprocessing. 186inline 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