diff options
Diffstat (limited to 'include/clang/Basic/Sanitizers.h')
| -rw-r--r-- | include/clang/Basic/Sanitizers.h | 154 |
1 files changed, 127 insertions, 27 deletions
diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h index fe9e76a1e325a..5961abf2aa191 100644 --- a/include/clang/Basic/Sanitizers.h +++ b/include/clang/Basic/Sanitizers.h @@ -1,9 +1,8 @@ //===- Sanitizers.h - C Language Family Language Options --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -21,45 +20,146 @@ #include <cassert> #include <cstdint> +namespace llvm { +class hash_code; +} + namespace clang { -using SanitizerMask = uint64_t; +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. -namespace SanitizerKind { + /// 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; -// 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 + 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. -#define SANITIZER(NAME, ID) \ - const SanitizerMask ID = 1ULL << SO_##ID; -#define SANITIZER_GROUP(NAME, ID, ALIAS) \ - const SanitizerMask ID = ALIAS; \ - const SanitizerMask ID##Group = 1ULL << SO_##ID##Group; +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" - -} // namespace SanitizerKind + 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(llvm::isPowerOf2_64(K)); - return Mask & K; + assert(K.isPowerOf2() && "Has to be a single sanitizer."); + return static_cast<bool>(Mask & K); } /// Check if one or more sanitizers are enabled. - bool hasOneOf(SanitizerMask K) const { return Mask & K; } + bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); } /// Enable or disable a certain (single) sanitizer. void set(SanitizerMask K, bool Value) { - assert(llvm::isPowerOf2_64(K)); + assert(K.isPowerOf2() && "Has to be a single sanitizer."); Mask = Value ? (Mask | K) : (Mask & ~K); } @@ -67,10 +167,10 @@ struct SanitizerSet { void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; } /// Returns true if no sanitizers are enabled. - bool empty() const { return Mask == 0; } + bool empty() const { return !Mask; } /// Bitmask of enabled sanitizers. - SanitizerMask Mask = 0; + SanitizerMask Mask; }; /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. @@ -85,7 +185,7 @@ SanitizerMask expandSanitizerGroups(SanitizerMask Kinds); inline SanitizerMask getPPTransparentSanitizers() { return SanitizerKind::CFI | SanitizerKind::Integer | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | - SanitizerKind::Undefined; + SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero; } } // namespace clang |
