xref: /netbsd-src/external/apache2/llvm/dist/clang/include/clang/Basic/Sanitizers.h (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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 
SanitizerMask(uint64_t mask1,uint64_t mask2)44   constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
45       : maskLoToHigh{mask1, mask2} {}
46 
47 public:
48   SanitizerMask() = default;
49 
checkBitPos(const unsigned Pos)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.
bitPosToMask(const unsigned 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 
countPopulation()63   unsigned countPopulation() const {
64     unsigned total = 0;
65     for (const auto &Val : maskLoToHigh)
66       total += llvm::countPopulation(Val);
67     return total;
68   }
69 
flipAllBits()70   void flipAllBits() {
71     for (auto &Val : maskLoToHigh)
72       Val = ~Val;
73   }
74 
isPowerOf2()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.
hasSanitizerSet154   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.
hasOneOfSanitizerSet160   bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
161 
162   /// Enable or disable a certain (single) sanitizer.
setSanitizerSet163   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.
emptySanitizerSet172   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.
getPPTransparentSanitizers()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