Home | History | Annotate | Line # | Download | only in Basic
      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 "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     unsigned total = 0;
     65     for (const auto &Val : maskLoToHigh)
     66       total += llvm::countPopulation(Val);
     67     return total;
     68   }
     69 
     70   void flipAllBits() {
     71     for (auto &Val : maskLoToHigh)
     72       Val = ~Val;
     73   }
     74 
     75   bool isPowerOf2() const {
     76     return countPopulation() == 1;
     77   }
     78 
     79   llvm::hash_code hash_value() const;
     80 
     81   constexpr explicit operator bool() const {
     82     return maskLoToHigh[0] || maskLoToHigh[1];
     83   }
     84 
     85   constexpr bool operator==(const SanitizerMask &V) const {
     86     return maskLoToHigh[0] == V.maskLoToHigh[0] &&
     87            maskLoToHigh[1] == V.maskLoToHigh[1];
     88   }
     89 
     90   SanitizerMask &operator&=(const SanitizerMask &RHS) {
     91     for (unsigned k = 0; k < kNumElem; k++)
     92       maskLoToHigh[k] &= RHS.maskLoToHigh[k];
     93     return *this;
     94   }
     95 
     96   SanitizerMask &operator|=(const SanitizerMask &RHS) {
     97     for (unsigned k = 0; k < kNumElem; k++)
     98       maskLoToHigh[k] |= RHS.maskLoToHigh[k];
     99     return *this;
    100   }
    101 
    102   constexpr bool operator!() const { return !bool(*this); }
    103 
    104   constexpr bool operator!=(const SanitizerMask &RHS) const {
    105     return !((*this) == RHS);
    106   }
    107 
    108   friend constexpr inline SanitizerMask operator~(SanitizerMask v) {
    109     return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]);
    110   }
    111 
    112   friend constexpr inline SanitizerMask operator&(SanitizerMask a,
    113                                                   const SanitizerMask &b) {
    114     return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0],
    115                          a.maskLoToHigh[1] & b.maskLoToHigh[1]);
    116   }
    117 
    118   friend constexpr inline SanitizerMask operator|(SanitizerMask a,
    119                                                   const SanitizerMask &b) {
    120     return SanitizerMask(a.maskLoToHigh[0] | b.maskLoToHigh[0],
    121                          a.maskLoToHigh[1] | b.maskLoToHigh[1]);
    122   }
    123 };
    124 
    125 // Declaring in clang namespace so that it can be found by ADL.
    126 llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
    127 
    128 // Define the set of sanitizer kinds, as well as the set of sanitizers each
    129 // sanitizer group expands into.
    130 struct SanitizerKind {
    131   // Assign ordinals to possible values of -fsanitize= flag, which we will use
    132   // as bit positions.
    133   enum SanitizerOrdinal : uint64_t {
    134 #define SANITIZER(NAME, ID) SO_##ID,
    135 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
    136 #include "clang/Basic/Sanitizers.def"
    137     SO_Count
    138   };
    139 
    140 #define SANITIZER(NAME, ID)                                                    \
    141   static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID);    \
    142   static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
    143 #define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \
    144   static constexpr SanitizerMask ID = SanitizerMask(ALIAS);                    \
    145   static constexpr SanitizerMask ID##Group =                                   \
    146       SanitizerMask::bitPosToMask(SO_##ID##Group);                             \
    147   static_assert(SanitizerMask::checkBitPos(SO_##ID##Group),                    \
    148                 "Bit position too big.");
    149 #include "clang/Basic/Sanitizers.def"
    150 }; // SanitizerKind
    151 
    152 struct SanitizerSet {
    153   /// Check if a certain (single) sanitizer is enabled.
    154   bool has(SanitizerMask K) const {
    155     assert(K.isPowerOf2() && "Has to be a single sanitizer.");
    156     return static_cast<bool>(Mask & K);
    157   }
    158 
    159   /// Check if one or more sanitizers are enabled.
    160   bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
    161 
    162   /// Enable or disable a certain (single) sanitizer.
    163   void set(SanitizerMask K, bool Value) {
    164     assert(K.isPowerOf2() && "Has to be a single sanitizer.");
    165     Mask = Value ? (Mask | K) : (Mask & ~K);
    166   }
    167 
    168   /// Disable the sanitizers specified in \p K.
    169   void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
    170 
    171   /// Returns true if no sanitizers are enabled.
    172   bool empty() const { return !Mask; }
    173 
    174   /// Bitmask of enabled sanitizers.
    175   SanitizerMask Mask;
    176 };
    177 
    178 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
    179 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
    180 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
    181 
    182 /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
    183 void serializeSanitizerSet(SanitizerSet Set,
    184                            SmallVectorImpl<StringRef> &Values);
    185 
    186 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
    187 /// this group enables.
    188 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
    189 
    190 /// Return the sanitizers which do not affect preprocessing.
    191 inline SanitizerMask getPPTransparentSanitizers() {
    192   return SanitizerKind::CFI | SanitizerKind::Integer |
    193          SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
    194          SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
    195 }
    196 
    197 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
    198 
    199 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
    200 
    201 } // namespace clang
    202 
    203 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
    204