1 //===- Sanitizers.cpp - C Language Family Language Options ----------------===// 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 // This file defines the classes from Sanitizers.h 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Basic/Sanitizers.h" 14 #include "llvm/ADT/Hashing.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringSwitch.h" 17 #include "llvm/Support/Format.h" 18 #include "llvm/Support/MathExtras.h" 19 #include "llvm/Support/raw_ostream.h" 20 #include <algorithm> 21 #include <optional> 22 23 using namespace clang; 24 25 static const double SanitizerMaskCutoffsEps = 0.000000001f; 26 27 void SanitizerMaskCutoffs::set(SanitizerMask K, double V) { 28 if (V < SanitizerMaskCutoffsEps && Cutoffs.empty()) 29 return; 30 for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) 31 if (K & SanitizerMask::bitPosToMask(i)) { 32 Cutoffs.resize(SanitizerKind::SO_Count); 33 Cutoffs[i] = V; 34 } 35 } 36 37 std::optional<double> SanitizerMaskCutoffs::operator[](unsigned Kind) const { 38 if (Cutoffs.empty() || Cutoffs[Kind] < SanitizerMaskCutoffsEps) 39 return std::nullopt; 40 41 return Cutoffs[Kind]; 42 } 43 44 void SanitizerMaskCutoffs::clear(SanitizerMask K) { set(K, 0); } 45 46 // Once LLVM switches to C++17, the constexpr variables can be inline and we 47 // won't need this. 48 #define SANITIZER(NAME, ID) constexpr SanitizerMask SanitizerKind::ID; 49 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 50 constexpr SanitizerMask SanitizerKind::ID; \ 51 constexpr SanitizerMask SanitizerKind::ID##Group; 52 #include "clang/Basic/Sanitizers.def" 53 54 SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { 55 SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value) 56 #define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) 57 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 58 .Case(NAME, AllowGroups ? SanitizerKind::ID##Group : SanitizerMask()) 59 #include "clang/Basic/Sanitizers.def" 60 .Default(SanitizerMask()); 61 return ParsedKind; 62 } 63 64 bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, 65 SanitizerMaskCutoffs &Cutoffs) { 66 SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value) 67 #define SANITIZER(NAME, ID) .StartsWith(NAME "=", SanitizerKind::ID) 68 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 69 .StartsWith(NAME "=", \ 70 AllowGroups ? SanitizerKind::ID##Group : SanitizerMask()) 71 #include "clang/Basic/Sanitizers.def" 72 .Default(SanitizerMask()); 73 74 if (!ParsedKind) 75 return false; 76 auto [N, W] = Value.split('='); 77 double A; 78 if (W.getAsDouble(A)) 79 return false; 80 A = std::clamp(A, 0.0, 1.0); 81 // AllowGroups is already taken into account for ParsedKind, 82 // hence we unconditionally expandSanitizerGroups. 83 Cutoffs.set(expandSanitizerGroups(ParsedKind), A); 84 return true; 85 } 86 87 void clang::serializeSanitizerSet(SanitizerSet Set, 88 SmallVectorImpl<StringRef> &Values) { 89 #define SANITIZER(NAME, ID) \ 90 if (Set.has(SanitizerKind::ID)) \ 91 Values.push_back(NAME); 92 #include "clang/Basic/Sanitizers.def" 93 } 94 95 void clang::serializeSanitizerMaskCutoffs( 96 const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl<std::string> &Values) { 97 #define SANITIZER(NAME, ID) \ 98 if (auto C = Cutoffs[SanitizerKind::SO_##ID]) { \ 99 std::string Str; \ 100 llvm::raw_string_ostream OS(Str); \ 101 OS << NAME "=" << llvm::format("%.8f", *C); \ 102 Values.emplace_back(StringRef(Str).rtrim('0')); \ 103 } 104 #include "clang/Basic/Sanitizers.def" 105 } 106 107 SanitizerMask clang::expandSanitizerGroups(SanitizerMask Kinds) { 108 #define SANITIZER(NAME, ID) 109 #define SANITIZER_GROUP(NAME, ID, ALIAS) \ 110 if (Kinds & SanitizerKind::ID##Group) \ 111 Kinds |= SanitizerKind::ID; 112 #include "clang/Basic/Sanitizers.def" 113 return Kinds; 114 } 115 116 llvm::hash_code SanitizerMask::hash_value() const { 117 return llvm::hash_combine_range(&maskLoToHigh[0], &maskLoToHigh[kNumElem]); 118 } 119 120 namespace clang { 121 unsigned SanitizerMask::countPopulation() const { 122 unsigned total = 0; 123 for (const auto &Val : maskLoToHigh) 124 total += llvm::popcount(Val); 125 return total; 126 } 127 128 llvm::hash_code hash_value(const clang::SanitizerMask &Arg) { 129 return Arg.hash_value(); 130 } 131 132 StringRef AsanDtorKindToString(llvm::AsanDtorKind kind) { 133 switch (kind) { 134 case llvm::AsanDtorKind::None: 135 return "none"; 136 case llvm::AsanDtorKind::Global: 137 return "global"; 138 case llvm::AsanDtorKind::Invalid: 139 return "invalid"; 140 } 141 return "invalid"; 142 } 143 144 llvm::AsanDtorKind AsanDtorKindFromString(StringRef kindStr) { 145 return llvm::StringSwitch<llvm::AsanDtorKind>(kindStr) 146 .Case("none", llvm::AsanDtorKind::None) 147 .Case("global", llvm::AsanDtorKind::Global) 148 .Default(llvm::AsanDtorKind::Invalid); 149 } 150 151 StringRef AsanDetectStackUseAfterReturnModeToString( 152 llvm::AsanDetectStackUseAfterReturnMode mode) { 153 switch (mode) { 154 case llvm::AsanDetectStackUseAfterReturnMode::Always: 155 return "always"; 156 case llvm::AsanDetectStackUseAfterReturnMode::Runtime: 157 return "runtime"; 158 case llvm::AsanDetectStackUseAfterReturnMode::Never: 159 return "never"; 160 case llvm::AsanDetectStackUseAfterReturnMode::Invalid: 161 return "invalid"; 162 } 163 return "invalid"; 164 } 165 166 llvm::AsanDetectStackUseAfterReturnMode 167 AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr) { 168 return llvm::StringSwitch<llvm::AsanDetectStackUseAfterReturnMode>(modeStr) 169 .Case("always", llvm::AsanDetectStackUseAfterReturnMode::Always) 170 .Case("runtime", llvm::AsanDetectStackUseAfterReturnMode::Runtime) 171 .Case("never", llvm::AsanDetectStackUseAfterReturnMode::Never) 172 .Default(llvm::AsanDetectStackUseAfterReturnMode::Invalid); 173 } 174 175 } // namespace clang 176