//===- Sanitizers.h - C Language Family Language Options --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the clang::SanitizerKind enum.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_SANITIZERS_H
#define LLVM_CLANG_BASIC_SANITIZERS_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MathExtras.h"
#include <cassert>
#include <cstdint>
namespace llvm {
class hash_code;
}
namespace clang {
class SanitizerMask {
// NOTE: this class assumes kNumElem == 2 in most of the constexpr functions,
// in order to work within the C++11 constexpr function constraints. If you
// change kNumElem, you'll need to update those member functions as well.
/// Number of array elements.
static constexpr unsigned kNumElem = 2;
/// Mask value initialized to 0.
uint64_t maskLoToHigh[kNumElem]{};
/// Number of bits in a mask.
static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8;
/// Number of bits in a mask element.
static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8;
constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
: maskLoToHigh{mask1, mask2} {}
public:
SanitizerMask() = default;
static constexpr bool checkBitPos(const unsigned Pos) {
return Pos < kNumBits;
}
/// Create a mask with a bit enabled at position Pos.
static constexpr SanitizerMask bitPosToMask(const unsigned Pos) {
uint64_t mask1 = (Pos < kNumBitElem) ? 1ULL << (Pos % kNumBitElem) : 0;
uint64_t mask2 = (Pos >= kNumBitElem && Pos < (kNumBitElem * 2))
? 1ULL << (Pos % kNumBitElem)
: 0;
return SanitizerMask(mask1, mask2);
}
unsigned countPopulation() const {
unsigned total = 0;
for (const auto &Val : maskLoToHigh)
total += llvm::countPopulation(Val);
return total;
}
void flipAllBits() {
for (auto &Val : maskLoToHigh)
Val = ~Val;
}
bool isPowerOf2() const {
return countPopulation() == 1;
}
llvm::hash_code hash_value() const;
constexpr explicit operator bool() const {
return maskLoToHigh[0] || maskLoToHigh[1];
}
constexpr bool operator==(const SanitizerMask &V) const {
return maskLoToHigh[0] == V.maskLoToHigh[0] &&
maskLoToHigh[1] == V.maskLoToHigh[1];
}
SanitizerMask &operator&=(const SanitizerMask &RHS) {
for (unsigned k = 0; k < kNumElem; k++)
maskLoToHigh[k] &= RHS.maskLoToHigh[k];
return *this;
}
SanitizerMask &operator|=(const SanitizerMask &RHS) {
for (unsigned k = 0; k < kNumElem; k++)
maskLoToHigh[k] |= RHS.maskLoToHigh[k];
return *this;
}
constexpr bool operator!() const { return !bool(*this); }
constexpr bool operator!=(const SanitizerMask &RHS) const {
return !((*this) == RHS);
}
friend constexpr inline SanitizerMask operator~(SanitizerMask v) {
return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]);
}
friend constexpr inline SanitizerMask operator&(SanitizerMask a,
const SanitizerMask &b) {
return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0],
a.maskLoToHigh[1] & b.maskLoToHigh[1]);
}
friend constexpr inline SanitizerMask operator|(SanitizerMask a,
const SanitizerMask &b) {
return SanitizerMask(a.maskLoToHigh[0] | b.maskLoToHigh[0],
a.maskLoToHigh[1] | b.maskLoToHigh[1]);
}
};
// Declaring in clang namespace so that it can be found by ADL.
llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
// Define the set of sanitizer kinds, as well as the set of sanitizers each
// sanitizer group expands into.
struct SanitizerKind {
// Assign ordinals to possible values of -fsanitize= flag, which we will use
// as bit positions.
enum SanitizerOrdinal : uint64_t {
#define SANITIZER(NAME, ID) SO_##ID,
#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
#include "clang/Basic/Sanitizers.def"
SO_Count
};
#define SANITIZER(NAME, ID) \
static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID); \
static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
static constexpr SanitizerMask ID = SanitizerMask(ALIAS); \
static constexpr SanitizerMask ID##Group = \
SanitizerMask::bitPosToMask(SO_##ID##Group); \
static_assert(SanitizerMask::checkBitPos(SO_##ID##Group), \
"Bit position too big.");
#include "clang/Basic/Sanitizers.def"
}; // SanitizerKind
struct SanitizerSet {
/// Check if a certain (single) sanitizer is enabled.
bool has(SanitizerMask K) const {
assert(K.isPowerOf2() && "Has to be a single sanitizer.");
return static_cast<bool>(Mask & K);
}
/// Check if one or more sanitizers are enabled.
bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
/// Enable or disable a certain (single) sanitizer.
void set(SanitizerMask K, bool Value) {
assert(K.isPowerOf2() && "Has to be a single sanitizer.");
Mask = Value ? (Mask | K) : (Mask & ~K);
}
/// Disable the sanitizers specified in \p K.
void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
/// Returns true if no sanitizers are enabled.
bool empty() const { return !Mask; }
/// Bitmask of enabled sanitizers.
SanitizerMask Mask;
};
/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
/// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
/// this group enables.
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
/// Return the sanitizers which do not affect preprocessing.
inline SanitizerMask getPPTransparentSanitizers() {
return SanitizerKind::CFI | SanitizerKind::Integer |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
}
} // namespace clang
#endif // LLVM_CLANG_BASIC_SANITIZERS_H