10b57cec5SDimitry Andric //===- Sanitizers.h - C Language Family Language Options --------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// Defines the clang::SanitizerKind enum.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_CLANG_BASIC_SANITIZERS_H
150b57cec5SDimitry Andric #define LLVM_CLANG_BASIC_SANITIZERS_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
19349cc55cSDimitry Andric #include "llvm/Support/HashBuilder.h"
20fe6060f1SDimitry Andric #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
210b57cec5SDimitry Andric #include <cassert>
220b57cec5SDimitry Andric #include <cstdint>
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace llvm {
250b57cec5SDimitry Andric class hash_code;
268a4dda33SDimitry Andric class Triple;
278a4dda33SDimitry Andric namespace opt {
288a4dda33SDimitry Andric class ArgList;
290b57cec5SDimitry Andric }
308a4dda33SDimitry Andric } // namespace llvm
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric namespace clang {
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric class SanitizerMask {
350b57cec5SDimitry Andric   // NOTE: this class assumes kNumElem == 2 in most of the constexpr functions,
360b57cec5SDimitry Andric   // in order to work within the C++11 constexpr function constraints. If you
370b57cec5SDimitry Andric   // change kNumElem, you'll need to update those member functions as well.
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   /// Number of array elements.
400b57cec5SDimitry Andric   static constexpr unsigned kNumElem = 2;
410b57cec5SDimitry Andric   /// Mask value initialized to 0.
420b57cec5SDimitry Andric   uint64_t maskLoToHigh[kNumElem]{};
430b57cec5SDimitry Andric   /// Number of bits in a mask.
440b57cec5SDimitry Andric   static constexpr unsigned kNumBits = sizeof(decltype(maskLoToHigh)) * 8;
450b57cec5SDimitry Andric   /// Number of bits in a mask element.
460b57cec5SDimitry Andric   static constexpr unsigned kNumBitElem = sizeof(decltype(maskLoToHigh[0])) * 8;
470b57cec5SDimitry Andric 
SanitizerMask(uint64_t mask1,uint64_t mask2)480b57cec5SDimitry Andric   constexpr SanitizerMask(uint64_t mask1, uint64_t mask2)
490b57cec5SDimitry Andric       : maskLoToHigh{mask1, mask2} {}
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric public:
520b57cec5SDimitry Andric   SanitizerMask() = default;
530b57cec5SDimitry Andric 
checkBitPos(const unsigned Pos)540b57cec5SDimitry Andric   static constexpr bool checkBitPos(const unsigned Pos) {
550b57cec5SDimitry Andric     return Pos < kNumBits;
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   /// Create a mask with a bit enabled at position Pos.
bitPosToMask(const unsigned Pos)590b57cec5SDimitry Andric   static constexpr SanitizerMask bitPosToMask(const unsigned Pos) {
60480093f4SDimitry Andric     uint64_t mask1 = (Pos < kNumBitElem) ? 1ULL << (Pos % kNumBitElem) : 0;
61480093f4SDimitry Andric     uint64_t mask2 = (Pos >= kNumBitElem && Pos < (kNumBitElem * 2))
62480093f4SDimitry Andric                          ? 1ULL << (Pos % kNumBitElem)
63480093f4SDimitry Andric                          : 0;
64480093f4SDimitry Andric     return SanitizerMask(mask1, mask2);
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
67fe6060f1SDimitry Andric   unsigned countPopulation() const;
680b57cec5SDimitry Andric 
flipAllBits()690b57cec5SDimitry Andric   void flipAllBits() {
700b57cec5SDimitry Andric     for (auto &Val : maskLoToHigh)
710b57cec5SDimitry Andric       Val = ~Val;
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric 
isPowerOf2()740b57cec5SDimitry Andric   bool isPowerOf2() const {
750b57cec5SDimitry Andric     return countPopulation() == 1;
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   llvm::hash_code hash_value() const;
790b57cec5SDimitry Andric 
805f757f3fSDimitry Andric   template <typename HasherT, llvm::endianness Endianness>
addHash(llvm::HashBuilder<HasherT,Endianness> & HBuilder,const SanitizerMask & SM)815f757f3fSDimitry Andric   friend void addHash(llvm::HashBuilder<HasherT, Endianness> &HBuilder,
82349cc55cSDimitry Andric                       const SanitizerMask &SM) {
83349cc55cSDimitry Andric     HBuilder.addRange(&SM.maskLoToHigh[0], &SM.maskLoToHigh[kNumElem]);
84349cc55cSDimitry Andric   }
85349cc55cSDimitry Andric 
860b57cec5SDimitry Andric   constexpr explicit operator bool() const {
870b57cec5SDimitry Andric     return maskLoToHigh[0] || maskLoToHigh[1];
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   constexpr bool operator==(const SanitizerMask &V) const {
910b57cec5SDimitry Andric     return maskLoToHigh[0] == V.maskLoToHigh[0] &&
920b57cec5SDimitry Andric            maskLoToHigh[1] == V.maskLoToHigh[1];
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   SanitizerMask &operator&=(const SanitizerMask &RHS) {
960b57cec5SDimitry Andric     for (unsigned k = 0; k < kNumElem; k++)
970b57cec5SDimitry Andric       maskLoToHigh[k] &= RHS.maskLoToHigh[k];
980b57cec5SDimitry Andric     return *this;
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   SanitizerMask &operator|=(const SanitizerMask &RHS) {
1020b57cec5SDimitry Andric     for (unsigned k = 0; k < kNumElem; k++)
1030b57cec5SDimitry Andric       maskLoToHigh[k] |= RHS.maskLoToHigh[k];
1040b57cec5SDimitry Andric     return *this;
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   constexpr bool operator!() const { return !bool(*this); }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   constexpr bool operator!=(const SanitizerMask &RHS) const {
1100b57cec5SDimitry Andric     return !((*this) == RHS);
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   friend constexpr inline SanitizerMask operator~(SanitizerMask v) {
1140b57cec5SDimitry Andric     return SanitizerMask(~v.maskLoToHigh[0], ~v.maskLoToHigh[1]);
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   friend constexpr inline SanitizerMask operator&(SanitizerMask a,
1180b57cec5SDimitry Andric                                                   const SanitizerMask &b) {
1190b57cec5SDimitry Andric     return SanitizerMask(a.maskLoToHigh[0] & b.maskLoToHigh[0],
1200b57cec5SDimitry Andric                          a.maskLoToHigh[1] & b.maskLoToHigh[1]);
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   friend constexpr inline SanitizerMask operator|(SanitizerMask a,
1240b57cec5SDimitry Andric                                                   const SanitizerMask &b) {
1250b57cec5SDimitry Andric     return SanitizerMask(a.maskLoToHigh[0] | b.maskLoToHigh[0],
1260b57cec5SDimitry Andric                          a.maskLoToHigh[1] | b.maskLoToHigh[1]);
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric };
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric // Declaring in clang namespace so that it can be found by ADL.
1310b57cec5SDimitry Andric llvm::hash_code hash_value(const clang::SanitizerMask &Arg);
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric // Define the set of sanitizer kinds, as well as the set of sanitizers each
1340b57cec5SDimitry Andric // sanitizer group expands into.
1350b57cec5SDimitry Andric struct SanitizerKind {
1360b57cec5SDimitry Andric   // Assign ordinals to possible values of -fsanitize= flag, which we will use
1370b57cec5SDimitry Andric   // as bit positions.
1380b57cec5SDimitry Andric   enum SanitizerOrdinal : uint64_t {
1390b57cec5SDimitry Andric #define SANITIZER(NAME, ID) SO_##ID,
1400b57cec5SDimitry Andric #define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
1410b57cec5SDimitry Andric #include "clang/Basic/Sanitizers.def"
1420b57cec5SDimitry Andric     SO_Count
1430b57cec5SDimitry Andric   };
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric #define SANITIZER(NAME, ID)                                                    \
1460b57cec5SDimitry Andric   static constexpr SanitizerMask ID = SanitizerMask::bitPosToMask(SO_##ID);    \
1470b57cec5SDimitry Andric   static_assert(SanitizerMask::checkBitPos(SO_##ID), "Bit position too big.");
1480b57cec5SDimitry Andric #define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \
1490b57cec5SDimitry Andric   static constexpr SanitizerMask ID = SanitizerMask(ALIAS);                    \
1500b57cec5SDimitry Andric   static constexpr SanitizerMask ID##Group =                                   \
1510b57cec5SDimitry Andric       SanitizerMask::bitPosToMask(SO_##ID##Group);                             \
1520b57cec5SDimitry Andric   static_assert(SanitizerMask::checkBitPos(SO_##ID##Group),                    \
1530b57cec5SDimitry Andric                 "Bit position too big.");
1540b57cec5SDimitry Andric #include "clang/Basic/Sanitizers.def"
1550b57cec5SDimitry Andric }; // SanitizerKind
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric struct SanitizerSet {
1580b57cec5SDimitry Andric   /// Check if a certain (single) sanitizer is enabled.
hasSanitizerSet1590b57cec5SDimitry Andric   bool has(SanitizerMask K) const {
1600b57cec5SDimitry Andric     assert(K.isPowerOf2() && "Has to be a single sanitizer.");
1610b57cec5SDimitry Andric     return static_cast<bool>(Mask & K);
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   /// Check if one or more sanitizers are enabled.
hasOneOfSanitizerSet1650b57cec5SDimitry Andric   bool hasOneOf(SanitizerMask K) const { return static_cast<bool>(Mask & K); }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   /// Enable or disable a certain (single) sanitizer.
setSanitizerSet1680b57cec5SDimitry Andric   void set(SanitizerMask K, bool Value) {
1690b57cec5SDimitry Andric     assert(K.isPowerOf2() && "Has to be a single sanitizer.");
1700b57cec5SDimitry Andric     Mask = Value ? (Mask | K) : (Mask & ~K);
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
setSanitizerSet1735f757f3fSDimitry Andric   void set(SanitizerMask K) { Mask = K; }
1745f757f3fSDimitry Andric 
1750b57cec5SDimitry Andric   /// Disable the sanitizers specified in \p K.
1760b57cec5SDimitry Andric   void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   /// Returns true if no sanitizers are enabled.
emptySanitizerSet1790b57cec5SDimitry Andric   bool empty() const { return !Mask; }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   /// Bitmask of enabled sanitizers.
1820b57cec5SDimitry Andric   SanitizerMask Mask;
1830b57cec5SDimitry Andric };
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
1860b57cec5SDimitry Andric /// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
1870b57cec5SDimitry Andric SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
1880b57cec5SDimitry Andric 
189fe6060f1SDimitry Andric /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
190fe6060f1SDimitry Andric void serializeSanitizerSet(SanitizerSet Set,
191fe6060f1SDimitry Andric                            SmallVectorImpl<StringRef> &Values);
192fe6060f1SDimitry Andric 
1930b57cec5SDimitry Andric /// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
1940b57cec5SDimitry Andric /// this group enables.
1950b57cec5SDimitry Andric SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric /// Return the sanitizers which do not affect preprocessing.
getPPTransparentSanitizers()1980b57cec5SDimitry Andric inline SanitizerMask getPPTransparentSanitizers() {
1990b57cec5SDimitry Andric   return SanitizerKind::CFI | SanitizerKind::Integer |
2000b57cec5SDimitry Andric          SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
2010b57cec5SDimitry Andric          SanitizerKind::Undefined | SanitizerKind::FloatDivideByZero;
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
204fe6060f1SDimitry Andric StringRef AsanDtorKindToString(llvm::AsanDtorKind kind);
205fe6060f1SDimitry Andric 
206fe6060f1SDimitry Andric llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind);
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric StringRef AsanDetectStackUseAfterReturnModeToString(
209fe6060f1SDimitry Andric     llvm::AsanDetectStackUseAfterReturnMode mode);
210fe6060f1SDimitry Andric 
211fe6060f1SDimitry Andric llvm::AsanDetectStackUseAfterReturnMode
212fe6060f1SDimitry Andric AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr);
213fe6060f1SDimitry Andric 
2140b57cec5SDimitry Andric } // namespace clang
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric #endif // LLVM_CLANG_BASIC_SANITIZERS_H
217