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