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