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
24namespace llvm {
25class hash_code;
26}
27
28namespace clang {
29
30class 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
47public:
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.
126llvm::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.
130struct 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
152struct 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.
180SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
181
182/// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
183void 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.
188SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
189
190/// Return the sanitizers which do not affect preprocessing.
191inline SanitizerMask getPPTransparentSanitizers() {
192 return SanitizerKind::CFI | SanitizerKind::Integer |
193 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
194 SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
195}
196
197StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
198
199llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
200
201} // namespace clang
202
203#endif // LLVM_CLANG_BASIC_SANITIZERS_H
204