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