clang 20.0.0git
Sanitizers.cpp
Go to the documentation of this file.
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
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
23using namespace clang;
24
25static const double SanitizerMaskCutoffsEps = 0.000000001f;
26
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
37std::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
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
54SanitizerMask 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
64bool 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
89#define SANITIZER(NAME, ID) \
90 if (Set.has(SanitizerKind::ID)) \
91 Values.push_back(NAME);
92#include "clang/Basic/Sanitizers.def"
93}
94
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
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
116llvm::hash_code SanitizerMask::hash_value() const {
117 return llvm::hash_combine_range(&maskLoToHigh[0], &maskLoToHigh[kNumElem]);
118}
119
120namespace clang {
122 unsigned total = 0;
123 for (const auto &Val : maskLoToHigh)
124 total += llvm::popcount(Val);
125 return total;
126}
127
128llvm::hash_code hash_value(const clang::SanitizerMask &Arg) {
129 return Arg.hash_value();
130}
131
132StringRef 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
144llvm::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
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
166llvm::AsanDetectStackUseAfterReturnMode
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
#define V(N, I)
Definition: ASTContext.h:3453
static const double SanitizerMaskCutoffsEps
Definition: Sanitizers.cpp:25
Defines the clang::SanitizerKind enum.
void clear(SanitizerMask K=SanitizerKind::All)
Definition: Sanitizers.cpp:44
void set(SanitizerMask K, double V)
Definition: Sanitizers.cpp:27
std::optional< double > operator[](unsigned Kind) const
Definition: Sanitizers.cpp:37
llvm::hash_code hash_value() const
Definition: Sanitizers.cpp:116
unsigned countPopulation() const
Definition: Sanitizers.cpp:121
static constexpr SanitizerMask bitPosToMask(const unsigned Pos)
Create a mask with a bit enabled at position Pos.
Definition: Sanitizers.h:59
The JSON file list parser is used to communicate input to InstallAPI.
StringRef AsanDtorKindToString(llvm::AsanDtorKind kind)
Definition: Sanitizers.cpp:132
void serializeSanitizerSet(SanitizerSet Set, SmallVectorImpl< StringRef > &Values)
Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
Definition: Sanitizers.cpp:87
bool parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskCutoffs &Cutoffs)
Parse a single weighted value (e.g., 'undefined=0.05') from a -fsanitize= or -fno-sanitize= value lis...
Definition: Sanitizers.cpp:64
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds)
For each sanitizer group bit set in Kinds, set the bits for sanitizers this group enables.
Definition: Sanitizers.cpp:107
void serializeSanitizerMaskCutoffs(const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl< std::string > &Values)
Serialize a SanitizerMaskCutoffs into values for -fsanitize= or -fno-sanitize=.
Definition: Sanitizers.cpp:95
SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups)
Parse a single value from a -fsanitize= or -fno-sanitize= value list.
Definition: Sanitizers.cpp:54
llvm::hash_code hash_value(const CustomizableOptional< T > &O)
llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind)
Definition: Sanitizers.cpp:144
llvm::AsanDetectStackUseAfterReturnMode AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr)
Definition: Sanitizers.cpp:167
StringRef AsanDetectStackUseAfterReturnModeToString(llvm::AsanDetectStackUseAfterReturnMode mode)
Definition: Sanitizers.cpp:151