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/Transforms/Instrumentation/AddressSanitizerOptions.h"
20 #include <cassert>
21 #include <cstdint>
22 
23 namespace llvm {
24 class hash_code;
25 }
26 
27 namespace clang {
28 
29 class SanitizerMask {
30   // NOTE: this class assumes kNumElem == 2 in most of the constexpr functions,
31   // in order to work within the C++11 constexpr function constraints. If you
32   // change kNumElem, you'll need to update those member functions as well.
33 
34   /// Number of array elements.
35   static constexpr unsigned kNumElem = 2;
36   /// Mask value initialized to 0.
37   uint64_t maskLoToHigh[kNumElem]{};
38   /// Number of bits in a mask.
39   static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8;
40   /// Number of bits in a mask element.
41   static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8;
42 
SanitizerMask(uint64_t mask1,uint64_t mask2)43   constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
44       : maskLoToHigh{mask1, mask2} {}
45 
46 public:
47   SanitizerMask() = default;
48 
checkBitPos(const unsigned Pos)49   static constexpr bool checkBitPos(const unsigned Pos) {
50     return Pos < kNumBits;
51   }
52 
53   /// Create a mask with a bit enabled at position Pos.
bitPosToMask(const unsigned Pos)54   static constexpr SanitizerMask bitPosToMask(const unsigned Pos) {
55     uint64_t mask1 = (Pos < kNumBitElem) ? 1ULL << (Pos % kNumBitElem) : 0;
56     uint64_t mask2 = (Pos >= kNumBitElem && Pos < (kNumBitElem * 2))
57                          ? 1ULL << (Pos % kNumBitElem)
58                          : 0;
59     return SanitizerMask(mask1, mask2);
60   }
61 
62   unsigned countPopulation() const;
63 
flipAllBits()64   void flipAllBits() {
65     for (auto &Val : maskLoToHigh)
66       Val = ~Val;
67   }
68 
isPowerOf2()69   bool isPowerOf2() const {
70     return countPopulation() == 1;
71   }
72 
73   llvm::hash_code hash_value() const;
74 
75   constexpr explicit operator bool() const {
76     return maskLoToHigh[0] || maskLoToHigh[1];
77   }
78 
79   constexpr bool operator==(const SanitizerMask &V) const {
80     return maskLoToHigh[0] == V.maskLoToHigh[0] &&
81            maskLoToHigh[1] == V.maskLoToHigh[1];
82   }
83 
84   SanitizerMask &operator&=(const SanitizerMask &RHS) {
85     for (unsigned k = 0; k < kNumElem; k++)
86       maskLoToHigh[k] &= RHS.maskLoToHigh[k];
87     return *this;
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   constexpr bool operator!() const { return !bool(*this); }
97 
98   constexpr bool operator!=(const SanitizerMask &RHS) const {
99     return !((*this) == RHS);
100   }
101 
102   friend constexpr inline SanitizerMask operator~(SanitizerMask v) {
103     return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]);
104   }
105 
106   friend constexpr inline SanitizerMask operator&(SanitizerMask a,
107                                                   const SanitizerMask &b) {
108     return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0],
109                          a.maskLoToHigh[1] & b.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 
119 // Declaring in clang namespace so that it can be found by ADL.
120 llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
121 
122 // Define the set of sanitizer kinds, as well as the set of sanitizers each
123 // sanitizer group expands into.
124 struct SanitizerKind {
125   // Assign ordinals to possible values of -fsanitize= flag, which we will use
126   // as bit positions.
127   enum SanitizerOrdinal : uint64_t {
128 #define SANITIZER(NAME, ID) SO_##ID,
129 #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
130 #include "clang/Basic/Sanitizers.def"
131     SO_Count
132   };
133 
134 #define SANITIZER(NAME, ID)                                                    \
135   static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID);    \
136   static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
137 #define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \
138   static constexpr SanitizerMask ID = SanitizerMask(ALIAS);                    \
139   static constexpr SanitizerMask ID##Group =                                   \
140       SanitizerMask::bitPosToMask(SO_##ID##Group);                             \
141   static_assert(SanitizerMask::checkBitPos(SO_##ID##Group),                    \
142                 "Bit position too big.");
143 #include "clang/Basic/Sanitizers.def"
144 }; // SanitizerKind
145 
146 struct SanitizerSet {
147   /// Check if a certain (single) sanitizer is enabled.
hasSanitizerSet148   bool has(SanitizerMask K) const {
149     assert(K.isPowerOf2() && "Has to be a single sanitizer.");
150     return static_cast<bool>(Mask & K);
151   }
152 
153   /// Check if one or more sanitizers are enabled.
hasOneOfSanitizerSet154   bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
155 
156   /// Enable or disable a certain (single) sanitizer.
setSanitizerSet157   void set(SanitizerMask K, bool Value) {
158     assert(K.isPowerOf2() && "Has to be a single sanitizer.");
159     Mask = Value ? (Mask | K) : (Mask & ~K);
160   }
161 
162   /// Disable the sanitizers specified in \p K.
163   void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
164 
165   /// Returns true if no sanitizers are enabled.
emptySanitizerSet166   bool empty() const { return !Mask; }
167 
168   /// Bitmask of enabled sanitizers.
169   SanitizerMask Mask;
170 };
171 
172 /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
173 /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
174 SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
175 
176 /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
177 void serializeSanitizerSet(SanitizerSet Set,
178                            SmallVectorImpl<StringRef> &Values);
179 
180 /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
181 /// this group enables.
182 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
183 
184 /// Return the sanitizers which do not affect preprocessing.
getPPTransparentSanitizers()185 inline SanitizerMask getPPTransparentSanitizers() {
186   return SanitizerKind::CFI | SanitizerKind::Integer |
187          SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
188          SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
189 }
190 
191 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
192 
193 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
194 
195 StringRef AsanDetectStackUseAfterReturnModeToString(
196     llvm::AsanDetectStackUseAfterReturnMode mode);
197 
198 llvm::AsanDetectStackUseAfterReturnMode
199 AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr);
200 
201 } // namespace clang
202 
203 #endif // LLVM_CLANG_BASIC_SANITIZERS_H
204