//===- Sanitizers.h - C Language Family Language Options --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // /// \file /// Defines the clang::SanitizerKind enum. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_SANITIZERS_H #define LLVM_CLANG_BASIC_SANITIZERS_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MathExtras.h" #include #include namespace llvm { class hash_code; } namespace clang { class SanitizerMask { // NOTE: this class assumes kNumElem == 2 in most of the constexpr functions, // in order to work within the C++11 constexpr function constraints. If you // change kNumElem, you'll need to update those member functions as well. /// Number of array elements. static constexpr unsigned kNumElem = 2; /// Mask value initialized to 0. uint64_t maskLoToHigh[kNumElem]{}; /// Number of bits in a mask. static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8; /// Number of bits in a mask element. static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8; constexpr SanitizerMask(uint64_t mask1, uint64_t mask2) : maskLoToHigh{mask1, mask2} {} public: SanitizerMask() = default; static constexpr bool checkBitPos(const unsigned Pos) { return Pos < kNumBits; } /// Create a mask with a bit enabled at position Pos. static constexpr SanitizerMask bitPosToMask(const unsigned Pos) { return SanitizerMask((Pos < kNumBitElem) ? 1ULL << Pos % kNumBitElem : 0, (Pos >= kNumBitElem && Pos < kNumBitElem * 2) ? 1ULL << Pos % kNumBitElem : 0); } unsigned countPopulation() const { unsigned total = 0; for (const auto &Val : maskLoToHigh) total += llvm::countPopulation(Val); return total; } void flipAllBits() { for (auto &Val : maskLoToHigh) Val = ~Val; } bool isPowerOf2() const { return countPopulation() == 1; } llvm::hash_code hash_value() const; constexpr explicit operator bool() const { return maskLoToHigh[0] || maskLoToHigh[1]; } constexpr bool operator==(const SanitizerMask &V) const { return maskLoToHigh[0] == V.maskLoToHigh[0] && maskLoToHigh[1] == V.maskLoToHigh[1]; } SanitizerMask &operator&=(const SanitizerMask &RHS) { for (unsigned k = 0; k < kNumElem; k++) maskLoToHigh[k] &= RHS.maskLoToHigh[k]; return *this; } SanitizerMask &operator|=(const SanitizerMask &RHS) { for (unsigned k = 0; k < kNumElem; k++) maskLoToHigh[k] |= RHS.maskLoToHigh[k]; return *this; } constexpr bool operator!() const { return !bool(*this); } constexpr bool operator!=(const SanitizerMask &RHS) const { return !((*this) == RHS); } friend constexpr inline SanitizerMask operator~(SanitizerMask v) { return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]); } friend constexpr inline SanitizerMask operator&(SanitizerMask a, const SanitizerMask &b) { return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0], a.maskLoToHigh[1] & b.maskLoToHigh[1]); } friend constexpr inline SanitizerMask operator|(SanitizerMask a, const SanitizerMask &b) { return SanitizerMask(a.maskLoToHigh[0] | b.maskLoToHigh[0], a.maskLoToHigh[1] | b.maskLoToHigh[1]); } }; // Declaring in clang namespace so that it can be found by ADL. llvm::hash_code hash_value(const clang::SanitizerMask &Arg); // Define the set of sanitizer kinds, as well as the set of sanitizers each // sanitizer group expands into. struct SanitizerKind { // Assign ordinals to possible values of -fsanitize= flag, which we will use // as bit positions. enum SanitizerOrdinal : uint64_t { #define SANITIZER(NAME, ID) SO_##ID, #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group, #include "clang/Basic/Sanitizers.def" SO_Count }; #define SANITIZER(NAME, ID) \ static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID); \ static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big."); #define SANITIZER_GROUP(NAME, ID, ALIAS) \ static constexpr SanitizerMask ID = SanitizerMask(ALIAS); \ static constexpr SanitizerMask ID##Group = \ SanitizerMask::bitPosToMask(SO_##ID##Group); \ static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \ "Bit position too big."); #include "clang/Basic/Sanitizers.def" }; // SanitizerKind struct SanitizerSet { /// Check if a certain (single) sanitizer is enabled. bool has(SanitizerMask K) const { assert(K.isPowerOf2() && "Has to be a single sanitizer."); return static_cast(Mask & K); } /// Check if one or more sanitizers are enabled. bool hasOneOf(SanitizerMask K) const { return static_cast(Mask & K); } /// Enable or disable a certain (single) sanitizer. void set(SanitizerMask K, bool Value) { assert(K.isPowerOf2() && "Has to be a single sanitizer."); Mask = Value ? (Mask | K) : (Mask & ~K); } /// Disable the sanitizers specified in \p K. void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } /// Returns true if no sanitizers are enabled. bool empty() const { return !Mask; } /// Bitmask of enabled sanitizers. SanitizerMask Mask; }; /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known. SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers /// this group enables. SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); /// Return the sanitizers which do not affect preprocessing. inline SanitizerMask getPPTransparentSanitizers() { return SanitizerKind::CFI | SanitizerKind::Integer | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero; } } // namespace clang #endif // LLVM_CLANG_BASIC_SANITIZERS_H