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
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
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.
127llvm::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.
131struct 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
153struct 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.
181SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
182
183/// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
184void 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.
189SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
190
191/// Return the sanitizers which do not affect preprocessing.
192inline SanitizerMask getPPTransparentSanitizers() {
193  return SanitizerKind::CFI | SanitizerKind::Integer |
194         SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
195         SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
196}
197
198StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
199
200llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
201
202StringRef AsanDetectStackUseAfterReturnModeToString(
203    llvm::AsanDetectStackUseAfterReturnMode mode);
204
205llvm::AsanDetectStackUseAfterReturnMode
206AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr);
207
208} // namespace clang
209
210#endif // LLVM_CLANG_BASIC_SANITIZERS_H
211