[clang] [sanitizer] Parse weighted sanitizer args and -fno-sanitize-top-hot (PR #121619)
Thurston Dang via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 6 15:57:30 PST 2025
https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/121619
>From ca1fabc5ea75af0acdd1969c0ad505e04103e1c9 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sat, 4 Jan 2025 02:53:00 +0000
Subject: [PATCH 1/9] [sanitizer] Parse weighted sanitizer args and
-fno-sanitize-top-hot
This adds a function to parse weighted sanitizer flags (e.g.,
-fsanitize-blah=undefined=0.5,null=0.3) and adds the plumbing to
apply that to -fno-sanitize-top-hot from the frontend to backend.
-fno-sanitize-top-hot currently has no effect; future work will
use it to generalize ubsan-guard-checks (originaly introduced in 5f9ed2ff8364ff3e4fac410472f421299dafa793).
---
clang/include/clang/Basic/CodeGenOptions.h | 4 ++
clang/include/clang/Basic/Sanitizers.h | 14 +++++
clang/include/clang/Driver/Options.td | 7 +++
clang/include/clang/Driver/SanitizerArgs.h | 1 +
clang/lib/Basic/Sanitizers.cpp | 38 ++++++++++++
clang/lib/Driver/SanitizerArgs.cpp | 69 +++++++++++++++++-----
clang/lib/Frontend/CompilerInvocation.cpp | 5 ++
7 files changed, 124 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 8097c9ef772bc7..f69f52e49a2fe9 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -384,6 +384,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// the expense of debuggability).
SanitizerSet SanitizeMergeHandlers;
+ /// Set of top hotness thresholds, specifying the fraction of code that is
+ /// excluded from sanitization (0 = skip none, 0.1 = skip hottest 10%, 1.0 = skip all).
+ SanitizerMaskWeights NoSanitizeTopHot = {0};
+
/// List of backend command-line options for -fembed-bitcode.
std::vector<uint8_t> CmdArgs;
diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h
index c890242269b334..fa6b557819a1a1 100644
--- a/clang/include/clang/Basic/Sanitizers.h
+++ b/clang/include/clang/Basic/Sanitizers.h
@@ -154,6 +154,8 @@ struct SanitizerKind {
#include "clang/Basic/Sanitizers.def"
}; // SanitizerKind
+typedef double SanitizerMaskWeights[SanitizerKind::SO_Count];
+
struct SanitizerSet {
/// Check if a certain (single) sanitizer is enabled.
bool has(SanitizerMask K) const {
@@ -186,10 +188,22 @@ struct SanitizerSet {
/// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
+/// Parse a single weighted value (e.g., 'undefined=0.05') from a -fsanitize= or
+/// -fno-sanitize= value list.
+/// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
+/// The relevant weight(s) are updated in the passed array.
+/// Individual weights are never reset to zero unless explicitly set
+/// (e.g., 'null=0.0').
+SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskWeights Weights);
+
/// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
void serializeSanitizerSet(SanitizerSet Set,
SmallVectorImpl<StringRef> &Values);
+/// Serialize a SanitizerMaskWeights into values for -fsanitize= or -fno-sanitize=.
+void serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
+ SmallVectorImpl<StringRef> &Values);
+
/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
/// this group enables.
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d922709db17786..631a6099781e6c 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2649,6 +2649,13 @@ def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-unde
HelpText<"Strip (or keep only, if negative) a given number of path components "
"when emitting check metadata.">,
MarshallingInfoInt<CodeGenOpts<"EmitCheckPathComponentsToStrip">, "0", "int">;
+def fno_sanitize_top_hot_EQ
+ : CommaJoined<["-"], "fno-sanitize-top-hot=">,
+ Group<f_clang_Group>,
+ HelpText<"Skip sanitization for the fraction of top hottest code "
+ "(0.0 [default] = do not skip any sanitization; "
+ "0.1 = skip the hottest 10% of code; "
+ "1.0 = skip all sanitization)">;
} // end -f[no-]sanitize* flags
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 3b275092bbbe86..854893269e8543 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -26,6 +26,7 @@ class SanitizerArgs {
SanitizerSet RecoverableSanitizers;
SanitizerSet TrapSanitizers;
SanitizerSet MergeHandlers;
+ SanitizerMaskWeights TopHot = {0};
std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index 62ccdf8e9bbf28..adfab2d3afab01 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -36,6 +36,36 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
return ParsedKind;
}
+SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskWeights Weights) {
+ SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
+#define SANITIZER(NAME, ID) .StartsWith(NAME"=", SanitizerKind::ID)
+#define SANITIZER_GROUP(NAME, ID, ALIAS) \
+ .StartsWith(NAME"=", AllowGroups ? SanitizerKind::ID##Group : SanitizerMask())
+#include "clang/Basic/Sanitizers.def"
+ .Default(SanitizerMask());
+
+ if (ParsedKind && Weights) {
+ size_t equalsIndex = Value.find_first_of('=');
+ if (equalsIndex != llvm::StringLiteral::npos) {
+ double arg;
+ if ( (Value.size() > (equalsIndex + 1))
+ && !Value.substr(equalsIndex + 1).getAsDouble(arg)) {
+ // AllowGroups is already taken into account for ParsedKind,
+ // hence we unconditionally expandSanitizerGroups.
+ SanitizerMask ExpandedKind = expandSanitizerGroups(ParsedKind);
+
+ for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
+ if(ExpandedKind & SanitizerMask::bitPosToMask(i)) {
+ Weights[i] = arg;
+ }
+ }
+ }
+ }
+ }
+
+ return ParsedKind;
+}
+
void clang::serializeSanitizerSet(SanitizerSet Set,
SmallVectorImpl<StringRef> &Values) {
#define SANITIZER(NAME, ID) \
@@ -44,6 +74,14 @@ void clang::serializeSanitizerSet(SanitizerSet Set,
#include "clang/Basic/Sanitizers.def"
}
+void clang::serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
+ SmallVectorImpl<StringRef> &Values) {
+#define SANITIZER(NAME, ID) \
+ if (Weights[SanitizerKind::SO_##ID]) \
+ Values.push_back(std::string(NAME) + "=" + std::to_string(Weights[SanitizerKind::SO_##ID]));
+#include "clang/Basic/Sanitizers.def"
+}
+
SanitizerMask clang::expandSanitizerGroups(SanitizerMask Kinds) {
#define SANITIZER(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 98116e2c8336b8..0f500ca14c527b 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -111,7 +111,7 @@ enum BinaryMetadataFeature {
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
/// invalid components. Returns a SanitizerMask.
static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
- bool DiagnoseErrors);
+ bool DiagnoseErrors, SanitizerMaskWeights Weights);
/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
/// components. Returns OR of members of \c CoverageFeature enumeration.
@@ -260,7 +260,7 @@ static SanitizerMask
parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
bool DiagnoseErrors, SanitizerMask Default,
SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
- int OptOutID) {
+ int OptOutID, SanitizerMaskWeights Weights) {
assert(!(AlwaysIn & AlwaysOut) &&
"parseSanitizeArgs called with contradictory in/out requirements");
@@ -271,7 +271,7 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
SanitizerMask DiagnosedAlwaysOutViolations;
for (const auto *Arg : Args) {
if (Arg->getOption().matches(OptInID)) {
- SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
+ SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors, Weights);
// Report error if user explicitly tries to opt-in to an always-out
// sanitizer.
if (SanitizerMask KindsToDiagnose =
@@ -287,7 +287,7 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
Output |= expandSanitizerGroups(Add);
Arg->claim();
} else if (Arg->getOption().matches(OptOutID)) {
- SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
+ SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors, Weights);
// Report error if user explicitly tries to opt-out of an always-in
// sanitizer.
if (SanitizerMask KindsToDiagnose =
@@ -320,7 +320,15 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
// (not even in recover mode) in order to avoid the need for a ubsan runtime.
return parseSanitizeArgs(D, Args, DiagnoseErrors, TrappingDefault, AlwaysTrap,
NeverTrap, options::OPT_fsanitize_trap_EQ,
- options::OPT_fno_sanitize_trap_EQ);
+ options::OPT_fno_sanitize_trap_EQ, nullptr);
+}
+
+static SanitizerMask parseNoSanitizeHotArgs(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ bool DiagnoseErrors,
+ SanitizerMaskWeights Weights) {
+ return parseSanitizeArgs(D, Args, DiagnoseErrors, {}, {}, {},
+ options::OPT_fno_sanitize_top_hot_EQ, -1, Weights);
}
bool SanitizerArgs::needsFuzzerInterceptors() const {
@@ -403,7 +411,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
Arg->claim();
- SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
+ SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors, nullptr);
if (RemoveObjectSizeAtO0) {
AllRemove |= SanitizerKind::ObjectSize;
@@ -573,7 +581,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Kinds |= Add;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
Arg->claim();
- SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
+ SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors, nullptr);
AllRemove |= expandSanitizerGroups(Remove);
}
}
@@ -698,7 +706,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask RecoverableKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
Unrecoverable, options::OPT_fsanitize_recover_EQ,
- options::OPT_fno_sanitize_recover_EQ);
+ options::OPT_fno_sanitize_recover_EQ, nullptr);
RecoverableKinds |= AlwaysRecoverable;
RecoverableKinds &= ~Unrecoverable;
RecoverableKinds &= Kinds;
@@ -710,9 +718,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask MergeKinds =
parseSanitizeArgs(D, Args, DiagnoseErrors, MergeDefault, {}, {},
options::OPT_fsanitize_merge_handlers_EQ,
- options::OPT_fno_sanitize_merge_handlers_EQ);
+ options::OPT_fno_sanitize_merge_handlers_EQ, nullptr);
MergeKinds &= Kinds;
+ // Parse -fno-sanitize-top-hot flags
+ SanitizerMask HotMask = parseNoSanitizeHotArgs (D, Args, DiagnoseErrors, TopHot);
+ (void)HotMask;
+
// Setup ignorelist files.
// Add default ignorelist from resource directory for activated sanitizers,
// and validate special case lists format.
@@ -1132,6 +1144,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
"Overlap between recoverable and trapping sanitizers");
MergeHandlers.Mask |= MergeKinds;
+
+ // Zero out TopHot for unused sanitizers
+ for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
+ if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i)))
+ TopHot[i] = 0;
+ }
}
static std::string toString(const clang::SanitizerSet &Sanitizers) {
@@ -1146,6 +1164,18 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) {
return Res;
}
+static std::string toString(const clang::SanitizerMaskWeights &Weights) {
+ std::string Res;
+#define SANITIZER(NAME, ID) \
+ if (Weights[SanitizerKind::SO_##ID]) { \
+ if (!Res.empty()) \
+ Res += ","; \
+ Res += std::string(NAME) + "=" + std::to_string(Weights[SanitizerKind::SO_##ID]); \
+ }
+#include "clang/Basic/Sanitizers.def"
+ return Res;
+}
+
static void addSpecialCaseListOpt(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const char *SCLOptFlag,
@@ -1297,6 +1327,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-fsanitize-merge=" + toString(MergeHandlers)));
+ std::string TopHotStr = toString(TopHot);
+ if (TopHotStr != "")
+ CmdArgs.push_back(
+ Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotStr));
+
addSpecialCaseListOpt(Args, CmdArgs,
"-fsanitize-ignorelist=", UserIgnorelistFiles);
addSpecialCaseListOpt(Args, CmdArgs,
@@ -1463,7 +1498,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
}
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
- bool DiagnoseErrors) {
+ bool DiagnoseErrors, SanitizerMaskWeights Weights) {
assert(
(A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
@@ -1472,7 +1507,8 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
A->getOption().matches(options::OPT_fsanitize_merge_handlers_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ)) &&
+ A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) &&
"Invalid argument in parseArgValues!");
SanitizerMask Kinds;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
@@ -1482,8 +1518,13 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
0 == strcmp("all", Value))
Kind = SanitizerMask();
- else
+ else if (A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) {
+ assert(Weights && "Null weights parameter provided for parsing fno_sanitize_top_hot!");
+ Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Weights);
+ } else {
+ assert((!Weights) && "Non-null weights parameter erroneously provided!");
Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);
+ }
if (Kind)
Kinds |= Kind;
@@ -1586,12 +1627,12 @@ std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
const auto *Arg = *I;
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
SanitizerMask AddKinds =
- expandSanitizerGroups(parseArgValues(D, Arg, false));
+ expandSanitizerGroups(parseArgValues(D, Arg, false, nullptr));
if (AddKinds & Mask)
return describeSanitizeArg(Arg, Mask);
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
SanitizerMask RemoveKinds =
- expandSanitizerGroups(parseArgValues(D, Arg, false));
+ expandSanitizerGroups(parseArgValues(D, Arg, false, nullptr));
Mask &= ~RemoveKinds;
}
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 348c56cc37da3f..c1c11f5a2325c7 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1796,6 +1796,11 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
serializeSanitizerKinds(Opts.SanitizeMergeHandlers))
GenerateArg(Consumer, OPT_fsanitize_merge_handlers_EQ, Sanitizer);
+ SmallVector<StringRef, 4> Values;
+ serializeSanitizerMaskWeights(Opts.NoSanitizeTopHot, Values);
+ for (StringRef Sanitizer : Values)
+ GenerateArg(Consumer, OPT_fno_sanitize_top_hot_EQ, Sanitizer);
+
if (!Opts.EmitVersionIdentMetadata)
GenerateArg(Consumer, OPT_Qn);
>From 770165969c8f14562702fe177d288239720deef2 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sat, 4 Jan 2025 03:22:24 +0000
Subject: [PATCH 2/9] clang-format
---
clang/include/clang/Basic/CodeGenOptions.h | 3 +-
clang/include/clang/Basic/Sanitizers.h | 6 ++-
clang/lib/Basic/Sanitizers.cpp | 46 ++++++++++++----------
clang/lib/Driver/SanitizerArgs.cpp | 46 ++++++++++++----------
4 files changed, 56 insertions(+), 45 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index f69f52e49a2fe9..39eabe0b1effa8 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -385,7 +385,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
SanitizerSet SanitizeMergeHandlers;
/// Set of top hotness thresholds, specifying the fraction of code that is
- /// excluded from sanitization (0 = skip none, 0.1 = skip hottest 10%, 1.0 = skip all).
+ /// excluded from sanitization (0 = skip none, 0.1 = skip hottest 10%, 1.0 =
+ /// skip all).
SanitizerMaskWeights NoSanitizeTopHot = {0};
/// List of backend command-line options for -fembed-bitcode.
diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h
index fa6b557819a1a1..f179fe5027ed0b 100644
--- a/clang/include/clang/Basic/Sanitizers.h
+++ b/clang/include/clang/Basic/Sanitizers.h
@@ -194,13 +194,15 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
/// The relevant weight(s) are updated in the passed array.
/// Individual weights are never reset to zero unless explicitly set
/// (e.g., 'null=0.0').
-SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskWeights Weights);
+SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
+ SanitizerMaskWeights Weights);
/// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
void serializeSanitizerSet(SanitizerSet Set,
SmallVectorImpl<StringRef> &Values);
-/// Serialize a SanitizerMaskWeights into values for -fsanitize= or -fno-sanitize=.
+/// Serialize a SanitizerMaskWeights into values for -fsanitize= or
+/// -fno-sanitize=.
void serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
SmallVectorImpl<StringRef> &Values);
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index adfab2d3afab01..c0e08ccfcdf746 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -36,31 +36,34 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
return ParsedKind;
}
-SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskWeights Weights) {
+SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value,
+ bool AllowGroups,
+ SanitizerMaskWeights Weights) {
SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
-#define SANITIZER(NAME, ID) .StartsWith(NAME"=", SanitizerKind::ID)
+#define SANITIZER(NAME, ID) .StartsWith(NAME "=", SanitizerKind::ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
- .StartsWith(NAME"=", AllowGroups ? SanitizerKind::ID##Group : SanitizerMask())
+ .StartsWith(NAME "=", \
+ AllowGroups ? SanitizerKind::ID##Group : SanitizerMask())
#include "clang/Basic/Sanitizers.def"
- .Default(SanitizerMask());
+ .Default(SanitizerMask());
if (ParsedKind && Weights) {
- size_t equalsIndex = Value.find_first_of('=');
- if (equalsIndex != llvm::StringLiteral::npos) {
- double arg;
- if ( (Value.size() > (equalsIndex + 1))
- && !Value.substr(equalsIndex + 1).getAsDouble(arg)) {
- // AllowGroups is already taken into account for ParsedKind,
- // hence we unconditionally expandSanitizerGroups.
- SanitizerMask ExpandedKind = expandSanitizerGroups(ParsedKind);
-
- for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
- if(ExpandedKind & SanitizerMask::bitPosToMask(i)) {
- Weights[i] = arg;
- }
- }
+ size_t equalsIndex = Value.find_first_of('=');
+ if (equalsIndex != llvm::StringLiteral::npos) {
+ double arg;
+ if ((Value.size() > (equalsIndex + 1)) &&
+ !Value.substr(equalsIndex + 1).getAsDouble(arg)) {
+ // AllowGroups is already taken into account for ParsedKind,
+ // hence we unconditionally expandSanitizerGroups.
+ SanitizerMask ExpandedKind = expandSanitizerGroups(ParsedKind);
+
+ for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
+ if (ExpandedKind & SanitizerMask::bitPosToMask(i)) {
+ Weights[i] = arg;
}
+ }
}
+ }
}
return ParsedKind;
@@ -75,10 +78,11 @@ void clang::serializeSanitizerSet(SanitizerSet Set,
}
void clang::serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
- SmallVectorImpl<StringRef> &Values) {
+ SmallVectorImpl<StringRef> &Values) {
#define SANITIZER(NAME, ID) \
- if (Weights[SanitizerKind::SO_##ID]) \
- Values.push_back(std::string(NAME) + "=" + std::to_string(Weights[SanitizerKind::SO_##ID]));
+ if (Weights[SanitizerKind::SO_##ID]) \
+ Values.push_back(std::string(NAME) + "=" + \
+ std::to_string(Weights[SanitizerKind::SO_##ID]));
#include "clang/Basic/Sanitizers.def"
}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 0f500ca14c527b..bac24dc824671e 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -111,7 +111,8 @@ enum BinaryMetadataFeature {
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
/// invalid components. Returns a SanitizerMask.
static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
- bool DiagnoseErrors, SanitizerMaskWeights Weights);
+ bool DiagnoseErrors,
+ SanitizerMaskWeights Weights);
/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
/// components. Returns OR of members of \c CoverageFeature enumeration.
@@ -722,7 +723,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MergeKinds &= Kinds;
// Parse -fno-sanitize-top-hot flags
- SanitizerMask HotMask = parseNoSanitizeHotArgs (D, Args, DiagnoseErrors, TopHot);
+ SanitizerMask HotMask =
+ parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, TopHot);
(void)HotMask;
// Setup ignorelist files.
@@ -1147,8 +1149,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Zero out TopHot for unused sanitizers
for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
- if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i)))
- TopHot[i] = 0;
+ if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i)))
+ TopHot[i] = 0;
}
}
@@ -1167,10 +1169,11 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) {
static std::string toString(const clang::SanitizerMaskWeights &Weights) {
std::string Res;
#define SANITIZER(NAME, ID) \
- if (Weights[SanitizerKind::SO_##ID]) { \
+ if (Weights[SanitizerKind::SO_##ID]) { \
if (!Res.empty()) \
Res += ","; \
- Res += std::string(NAME) + "=" + std::to_string(Weights[SanitizerKind::SO_##ID]); \
+ Res += std::string(NAME) + "=" + \
+ std::to_string(Weights[SanitizerKind::SO_##ID]); \
}
#include "clang/Basic/Sanitizers.def"
return Res;
@@ -1329,8 +1332,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::string TopHotStr = toString(TopHot);
if (TopHotStr != "")
- CmdArgs.push_back(
- Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotStr));
+ CmdArgs.push_back(Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotStr));
addSpecialCaseListOpt(Args, CmdArgs,
"-fsanitize-ignorelist=", UserIgnorelistFiles);
@@ -1498,18 +1500,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
}
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
- bool DiagnoseErrors, SanitizerMaskWeights Weights) {
- assert(
- (A->getOption().matches(options::OPT_fsanitize_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
- A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
- A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
- A->getOption().matches(options::OPT_fsanitize_merge_handlers_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) &&
- "Invalid argument in parseArgValues!");
+ bool DiagnoseErrors,
+ SanitizerMaskWeights Weights) {
+ assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
+ A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
+ A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
+ A->getOption().matches(options::OPT_fsanitize_merge_handlers_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) &&
+ "Invalid argument in parseArgValues!");
SanitizerMask Kinds;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
const char *Value = A->getValue(i);
@@ -1519,7 +1521,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
0 == strcmp("all", Value))
Kind = SanitizerMask();
else if (A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) {
- assert(Weights && "Null weights parameter provided for parsing fno_sanitize_top_hot!");
+ assert(
+ Weights &&
+ "Null weights parameter provided for parsing fno_sanitize_top_hot!");
Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Weights);
} else {
assert((!Weights) && "Non-null weights parameter erroneously provided!");
>From ade9e63ff7be82c23014db570cdffae8c94c2a78 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 18:41:15 +0000
Subject: [PATCH 3/9] Update flag description Update clang driver test
---
clang/include/clang/Basic/CodeGenOptions.h | 6 +++---
clang/include/clang/Driver/Options.td | 6 ++----
clang/lib/Basic/Sanitizers.cpp | 6 ++----
clang/test/Driver/fsanitize.c | 16 ++++++++++++++++
4 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 39eabe0b1effa8..2cf0197d17c8fa 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -384,9 +384,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// the expense of debuggability).
SanitizerSet SanitizeMergeHandlers;
- /// Set of top hotness thresholds, specifying the fraction of code that is
- /// excluded from sanitization (0 = skip none, 0.1 = skip hottest 10%, 1.0 =
- /// skip all).
+ /// Set of thresholds, specifying the top hottest fraction of code to be
+ /// excluded from sanitization (0.0 = skip none, 0.1 = skip hottest 10%,
+ /// 1.0 = skip all).
SanitizerMaskWeights NoSanitizeTopHot = {0};
/// List of backend command-line options for -fembed-bitcode.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 631a6099781e6c..ecdd4d1655cb78 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2652,10 +2652,8 @@ def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-unde
def fno_sanitize_top_hot_EQ
: CommaJoined<["-"], "fno-sanitize-top-hot=">,
Group<f_clang_Group>,
- HelpText<"Skip sanitization for the fraction of top hottest code "
- "(0.0 [default] = do not skip any sanitization; "
- "0.1 = skip the hottest 10% of code; "
- "1.0 = skip all sanitization)">;
+ HelpText<"Exclude sanitization for the top hottest fraction of code "
+ "(0.0 [default] = skip none; 0.1 = skip hottest 10%; 1.0 = skip all)">;
} // end -f[no-]sanitize* flags
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index c0e08ccfcdf746..924d86b0360518 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -57,11 +57,9 @@ SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value,
// hence we unconditionally expandSanitizerGroups.
SanitizerMask ExpandedKind = expandSanitizerGroups(ParsedKind);
- for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
- if (ExpandedKind & SanitizerMask::bitPosToMask(i)) {
+ for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++)
+ if (ExpandedKind & SanitizerMask::bitPosToMask(i))
Weights[i] = arg;
- }
- }
}
}
}
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index aeae15aada70cc..9c08ad8c40bc69 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -1154,3 +1154,19 @@
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-UBSAN
// CHECK-REALTIME-UBSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=undefined'
+
+
+// -fno-sanitize-top-hot
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TOP-HOT
+// CHECK-UNDEFINED-TOP-HOT: "-fno-sanitize-top-hot={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr)=0.5(0*),?){19}"}}
+
+// If no sanitizers are enabled, -fno-sanitize-top-hot is not passed
+// RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TOP-HOT2
+// CHECK-UNDEFINED-TOP-HOT2-NOT: "-fno-sanitize-top-hot"
+
+// Threshold of 0.0 cancels out the flag
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5,integer=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TOP-HOT3
+// CHECK-UNDEFINED-TOP-HOT3: "-fno-sanitize-top-hot={{((unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr)=0.5(0*),?){15}"}}
+
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5,integer=0.0,signed-integer-overflow=0.7 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TOP-HOT4
+// CHECK-UNDEFINED-TOP-HOT4: "-fno-sanitize-top-hot={{((signed-integer-overflow|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr)=(0.5|0.7)(0*),?){16}"}}
>From 6e20cf8155f957906f6f511f9d9051a81c7d99a3 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 21:44:53 +0000
Subject: [PATCH 4/9] Plumb values through CodeGen
---
clang/include/clang/Basic/CodeGenOptions.h | 5 ++++-
clang/include/clang/Basic/Sanitizers.h | 2 +-
clang/include/clang/Driver/SanitizerArgs.h | 3 ++-
clang/lib/Basic/Sanitizers.cpp | 6 +++---
clang/lib/CodeGen/CGExpr.cpp | 6 +++++-
clang/lib/Driver/SanitizerArgs.cpp | 17 +++++++++-------
clang/lib/Frontend/CompilerInvocation.cpp | 23 +++++++++++++++++++---
clang/test/CodeGen/allow-ubsan-check.c | 4 ++++
clang/test/Driver/fsanitize.c | 3 +++
9 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 2cf0197d17c8fa..e648bc4ea90cdf 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -387,7 +387,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// Set of thresholds, specifying the top hottest fraction of code to be
/// excluded from sanitization (0.0 = skip none, 0.1 = skip hottest 10%,
/// 1.0 = skip all).
- SanitizerMaskWeights NoSanitizeTopHot = {0};
+ SanitizerSet NoSanitizeTopHot;
+ /// N.B. The weights contain strictly more information than the SanitizerSet,
+ /// but the SanitizerSet is more efficient for some calculations.
+ SanitizerMaskWeights NoSanitizeTopHotWeights = {0};
/// List of backend command-line options for -fembed-bitcode.
std::vector<uint8_t> CmdArgs;
diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h
index f179fe5027ed0b..d80e04ca1290cf 100644
--- a/clang/include/clang/Basic/Sanitizers.h
+++ b/clang/include/clang/Basic/Sanitizers.h
@@ -204,7 +204,7 @@ void serializeSanitizerSet(SanitizerSet Set,
/// Serialize a SanitizerMaskWeights into values for -fsanitize= or
/// -fno-sanitize=.
void serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
- SmallVectorImpl<StringRef> &Values);
+ SmallVectorImpl<std::string> &Values);
/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
/// this group enables.
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 854893269e8543..28c067444f2e4c 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -26,7 +26,8 @@ class SanitizerArgs {
SanitizerSet RecoverableSanitizers;
SanitizerSet TrapSanitizers;
SanitizerSet MergeHandlers;
- SanitizerMaskWeights TopHot = {0};
+ SanitizerSet TopHot;
+ SanitizerMaskWeights TopHotWeights = {0};
std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index 924d86b0360518..92d9fb72559614 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -76,11 +76,11 @@ void clang::serializeSanitizerSet(SanitizerSet Set,
}
void clang::serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
- SmallVectorImpl<StringRef> &Values) {
+ SmallVectorImpl<std::string> &Values) {
#define SANITIZER(NAME, ID) \
if (Weights[SanitizerKind::SO_##ID]) \
- Values.push_back(std::string(NAME) + "=" + \
- std::to_string(Weights[SanitizerKind::SO_##ID]));
+ Values.push_back(std::string(NAME "=") \
+ + std::to_string(Weights[SanitizerKind::SO_##ID]));
#include "clang/Basic/Sanitizers.def"
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index ba1cba291553b0..3e14b0ffa7b320 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3602,6 +3602,7 @@ void CodeGenFunction::EmitCheck(
llvm::Value *RecoverableCond = nullptr;
llvm::Value *TrapCond = nullptr;
bool NoMerge = false;
+ bool SanitizeGuardChecks = ClSanitizeGuardChecks;
for (int i = 0, n = Checked.size(); i < n; ++i) {
llvm::Value *Check = Checked[i].first;
// -fsanitize-trap= overrides -fsanitize-recover=.
@@ -3615,9 +3616,12 @@ void CodeGenFunction::EmitCheck(
if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Checked[i].second))
NoMerge = true;
+
+ if (!CGM.getCodeGenOpts().NoSanitizeTopHot.has(Checked[i].second))
+ SanitizeGuardChecks = true;
}
- if (ClSanitizeGuardChecks) {
+ if (SanitizeGuardChecks) {
llvm::Value *Allow =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler));
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index bac24dc824671e..cb1c0801a8c457 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -723,9 +723,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MergeKinds &= Kinds;
// Parse -fno-sanitize-top-hot flags
- SanitizerMask HotMask =
- parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, TopHot);
- (void)HotMask;
+ SanitizerMask TopHotMask =
+ parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, TopHotWeights);
+ (void)TopHotMask;
// Setup ignorelist files.
// Add default ignorelist from resource directory for activated sanitizers,
@@ -1147,10 +1147,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MergeHandlers.Mask |= MergeKinds;
+ TopHotMask &= Sanitizers.Mask;
+ TopHot.Mask = TopHotMask;
+
// Zero out TopHot for unused sanitizers
for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i)))
- TopHot[i] = 0;
+ TopHotWeights[i] = 0;
}
}
@@ -1330,9 +1333,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-fsanitize-merge=" + toString(MergeHandlers)));
- std::string TopHotStr = toString(TopHot);
- if (TopHotStr != "")
- CmdArgs.push_back(Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotStr));
+ std::string TopHotWeightsStr = toString(TopHotWeights);
+ if (TopHotWeightsStr != "")
+ CmdArgs.push_back(Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotWeightsStr));
addSpecialCaseListOpt(Args, CmdArgs,
"-fsanitize-ignorelist=", UserIgnorelistFiles);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index c1c11f5a2325c7..e2705b111fb8db 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1436,6 +1436,18 @@ static SmallVector<StringRef, 4> serializeSanitizerKinds(SanitizerSet S) {
return Values;
}
+static void parseSanitizerWeightedKinds(StringRef FlagName,
+ const std::vector<std::string> &Sanitizers,
+ DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights &Weights) {
+ for (const auto &Sanitizer : Sanitizers) {
+ SanitizerMask K = parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Weights);
+ if (K == SanitizerMask())
+ Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer;
+ else
+ S.set(K, true);
+ }
+}
+
static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle,
ArgList &Args, DiagnosticsEngine &D,
XRayInstrSet &S) {
@@ -1796,9 +1808,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
serializeSanitizerKinds(Opts.SanitizeMergeHandlers))
GenerateArg(Consumer, OPT_fsanitize_merge_handlers_EQ, Sanitizer);
- SmallVector<StringRef, 4> Values;
- serializeSanitizerMaskWeights(Opts.NoSanitizeTopHot, Values);
- for (StringRef Sanitizer : Values)
+ SmallVector<std::string, 4> Values;
+ serializeSanitizerMaskWeights(Opts.NoSanitizeTopHotWeights, Values);
+ for (std::string Sanitizer : Values)
GenerateArg(Consumer, OPT_fno_sanitize_top_hot_EQ, Sanitizer);
if (!Opts.EmitVersionIdentMetadata)
@@ -2282,6 +2294,11 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Args.getAllArgValues(OPT_fsanitize_merge_handlers_EQ),
Diags, Opts.SanitizeMergeHandlers);
+ // Parse -fno-sanitize-top-hot= arguments.
+ parseSanitizerWeightedKinds("-fno-sanitize-top-hot=",
+ Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ),
+ Diags, Opts.NoSanitizeTopHot, Opts.NoSanitizeTopHotWeights);
+
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
if (!LangOpts->CUDAIsDevice)
diff --git a/clang/test/CodeGen/allow-ubsan-check.c b/clang/test/CodeGen/allow-ubsan-check.c
index 5232d240854666..adc56dee9ad02e 100644
--- a/clang/test/CodeGen/allow-ubsan-check.c
+++ b/clang/test/CodeGen/allow-ubsan-check.c
@@ -3,6 +3,10 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -mllvm -ubsan-guard-checks -fsanitize-trap=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=TRAP
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -mllvm -ubsan-guard-checks -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=RECOVER
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -fno-sanitize-top-hot=signed-integer-overflow=1,integer-divide-by-zero=1,null=1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -fno-sanitize-top-hot=signed-integer-overflow=1,integer-divide-by-zero=1,null=1 -fsanitize-trap=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=TRAP
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -fno-sanitize-top-hot=signed-integer-overflow=1,integer-divide-by-zero=1,null=1 -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=RECOVER
+
// CHECK-LABEL: define dso_local i32 @div(
// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] {
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index 9c08ad8c40bc69..211104fd667278 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -1170,3 +1170,6 @@
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5,integer=0.0,signed-integer-overflow=0.7 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TOP-HOT4
// CHECK-UNDEFINED-TOP-HOT4: "-fno-sanitize-top-hot={{((signed-integer-overflow|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|vptr)=(0.5|0.7)(0*),?){16}"}}
+
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TOP-HOT5
+// CHECK-UNDEFINED-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.4(0*),?){4}"}}
>From cc3a2ac63ebe32be52d9f227de182e178a2eac02 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 21:50:26 +0000
Subject: [PATCH 5/9] clang-format
---
clang/lib/Basic/Sanitizers.cpp | 8 ++++----
clang/lib/Driver/SanitizerArgs.cpp | 3 ++-
clang/lib/Frontend/CompilerInvocation.cpp | 14 ++++++++------
3 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index 92d9fb72559614..13f42bd143e084 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -75,12 +75,12 @@ void clang::serializeSanitizerSet(SanitizerSet Set,
#include "clang/Basic/Sanitizers.def"
}
-void clang::serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
- SmallVectorImpl<std::string> &Values) {
+void clang::serializeSanitizerMaskWeights(
+ const SanitizerMaskWeights Weights, SmallVectorImpl<std::string> &Values) {
#define SANITIZER(NAME, ID) \
if (Weights[SanitizerKind::SO_##ID]) \
- Values.push_back(std::string(NAME "=") \
- + std::to_string(Weights[SanitizerKind::SO_##ID]));
+ Values.push_back(std::string(NAME "=") + \
+ std::to_string(Weights[SanitizerKind::SO_##ID]));
#include "clang/Basic/Sanitizers.def"
}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index cb1c0801a8c457..773ebf53b005a5 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -1335,7 +1335,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::string TopHotWeightsStr = toString(TopHotWeights);
if (TopHotWeightsStr != "")
- CmdArgs.push_back(Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotWeightsStr));
+ CmdArgs.push_back(
+ Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotWeightsStr));
addSpecialCaseListOpt(Args, CmdArgs,
"-fsanitize-ignorelist=", UserIgnorelistFiles);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index e2705b111fb8db..df7fac32fec581 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1436,11 +1436,12 @@ static SmallVector<StringRef, 4> serializeSanitizerKinds(SanitizerSet S) {
return Values;
}
-static void parseSanitizerWeightedKinds(StringRef FlagName,
- const std::vector<std::string> &Sanitizers,
- DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights &Weights) {
+static void parseSanitizerWeightedKinds(
+ StringRef FlagName, const std::vector<std::string> &Sanitizers,
+ DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights &Weights) {
for (const auto &Sanitizer : Sanitizers) {
- SanitizerMask K = parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Weights);
+ SanitizerMask K =
+ parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Weights);
if (K == SanitizerMask())
Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer;
else
@@ -2296,8 +2297,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
// Parse -fno-sanitize-top-hot= arguments.
parseSanitizerWeightedKinds("-fno-sanitize-top-hot=",
- Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ),
- Diags, Opts.NoSanitizeTopHot, Opts.NoSanitizeTopHotWeights);
+ Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ),
+ Diags, Opts.NoSanitizeTopHot,
+ Opts.NoSanitizeTopHotWeights);
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
>From 9a2a0e86cf187961be63028e264f5388246a36cb Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 22:43:30 +0000
Subject: [PATCH 6/9] using SanitizerMaskWeights = std::array<float,
SanitizerKind::SO_Count>
---
clang/include/clang/Basic/Sanitizers.h | 4 ++--
clang/lib/Basic/Sanitizers.cpp | 4 ++--
clang/lib/Driver/SanitizerArgs.cpp | 10 +++++-----
clang/lib/Frontend/CompilerInvocation.cpp | 4 ++--
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h
index d80e04ca1290cf..c1242a1a69ef3f 100644
--- a/clang/include/clang/Basic/Sanitizers.h
+++ b/clang/include/clang/Basic/Sanitizers.h
@@ -154,7 +154,7 @@ struct SanitizerKind {
#include "clang/Basic/Sanitizers.def"
}; // SanitizerKind
-typedef double SanitizerMaskWeights[SanitizerKind::SO_Count];
+using SanitizerMaskWeights = std::array<float, SanitizerKind::SO_Count>;
struct SanitizerSet {
/// Check if a certain (single) sanitizer is enabled.
@@ -195,7 +195,7 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
/// Individual weights are never reset to zero unless explicitly set
/// (e.g., 'null=0.0').
SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
- SanitizerMaskWeights Weights);
+ SanitizerMaskWeights *Weights);
/// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
void serializeSanitizerSet(SanitizerSet Set,
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index 13f42bd143e084..179f2ad03714b1 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -38,7 +38,7 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value,
bool AllowGroups,
- SanitizerMaskWeights Weights) {
+ SanitizerMaskWeights *Weights) {
SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
#define SANITIZER(NAME, ID) .StartsWith(NAME "=", SanitizerKind::ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
@@ -59,7 +59,7 @@ SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value,
for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++)
if (ExpandedKind & SanitizerMask::bitPosToMask(i))
- Weights[i] = arg;
+ (*Weights)[i] = arg;
}
}
}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 773ebf53b005a5..44c1b353cf2d9f 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -112,7 +112,7 @@ enum BinaryMetadataFeature {
/// invalid components. Returns a SanitizerMask.
static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors,
- SanitizerMaskWeights Weights);
+ SanitizerMaskWeights *Weights);
/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
/// components. Returns OR of members of \c CoverageFeature enumeration.
@@ -261,7 +261,7 @@ static SanitizerMask
parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
bool DiagnoseErrors, SanitizerMask Default,
SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
- int OptOutID, SanitizerMaskWeights Weights) {
+ int OptOutID, SanitizerMaskWeights* Weights) {
assert(!(AlwaysIn & AlwaysOut) &&
"parseSanitizeArgs called with contradictory in/out requirements");
@@ -327,7 +327,7 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
static SanitizerMask parseNoSanitizeHotArgs(const Driver &D,
const llvm::opt::ArgList &Args,
bool DiagnoseErrors,
- SanitizerMaskWeights Weights) {
+ SanitizerMaskWeights *Weights) {
return parseSanitizeArgs(D, Args, DiagnoseErrors, {}, {}, {},
options::OPT_fno_sanitize_top_hot_EQ, -1, Weights);
}
@@ -724,7 +724,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Parse -fno-sanitize-top-hot flags
SanitizerMask TopHotMask =
- parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, TopHotWeights);
+ parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotWeights);
(void)TopHotMask;
// Setup ignorelist files.
@@ -1505,7 +1505,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors,
- SanitizerMaskWeights Weights) {
+ SanitizerMaskWeights *Weights) {
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index df7fac32fec581..084e62c467535e 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1438,7 +1438,7 @@ static SmallVector<StringRef, 4> serializeSanitizerKinds(SanitizerSet S) {
static void parseSanitizerWeightedKinds(
StringRef FlagName, const std::vector<std::string> &Sanitizers,
- DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights &Weights) {
+ DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights *Weights) {
for (const auto &Sanitizer : Sanitizers) {
SanitizerMask K =
parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Weights);
@@ -2299,7 +2299,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
parseSanitizerWeightedKinds("-fno-sanitize-top-hot=",
Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ),
Diags, Opts.NoSanitizeTopHot,
- Opts.NoSanitizeTopHotWeights);
+ &Opts.NoSanitizeTopHotWeights);
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
>From bfa57c67cd6364533d309c939d4036871601aa65 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 22:43:40 +0000
Subject: [PATCH 7/9] clang-format
---
clang/lib/Basic/Sanitizers.cpp | 6 +++---
clang/lib/Driver/SanitizerArgs.cpp | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index 179f2ad03714b1..b2fc7f8bcf49f0 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -36,9 +36,9 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
return ParsedKind;
}
-SanitizerMask clang::parseSanitizerWeightedValue(StringRef Value,
- bool AllowGroups,
- SanitizerMaskWeights *Weights) {
+SanitizerMask
+clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
+ SanitizerMaskWeights *Weights) {
SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
#define SANITIZER(NAME, ID) .StartsWith(NAME "=", SanitizerKind::ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 44c1b353cf2d9f..faa97f3bc5da79 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -261,7 +261,7 @@ static SanitizerMask
parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
bool DiagnoseErrors, SanitizerMask Default,
SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
- int OptOutID, SanitizerMaskWeights* Weights) {
+ int OptOutID, SanitizerMaskWeights *Weights) {
assert(!(AlwaysIn & AlwaysOut) &&
"parseSanitizeArgs called with contradictory in/out requirements");
>From 346adc1d00a6f8565bd9d1604c90377dd3fcf5d8 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 23:28:45 +0000
Subject: [PATCH 8/9] Rename Weights to Cutoffs
---
clang/include/clang/Basic/CodeGenOptions.h | 10 +++---
clang/include/clang/Basic/Sanitizers.h | 10 +++---
clang/include/clang/Driver/Options.td | 6 ++--
clang/include/clang/Driver/SanitizerArgs.h | 2 +-
clang/lib/Basic/Sanitizers.cpp | 14 ++++----
clang/lib/Driver/SanitizerArgs.cpp | 38 +++++++++++-----------
clang/lib/Frontend/CompilerInvocation.cpp | 8 ++---
7 files changed, 45 insertions(+), 43 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index e648bc4ea90cdf..227bddf831002e 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -384,13 +384,13 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// the expense of debuggability).
SanitizerSet SanitizeMergeHandlers;
- /// Set of thresholds, specifying the top hottest fraction of code to be
- /// excluded from sanitization (0.0 = skip none, 0.1 = skip hottest 10%,
- /// 1.0 = skip all).
+ /// Set of thresholds: the top hottest code responsible for the given
+ /// fraction of PGO counters will be excluded from sanitization
+ /// (0.0 [default] = skip none, 1.0 = skip all).
SanitizerSet NoSanitizeTopHot;
- /// N.B. The weights contain strictly more information than the SanitizerSet,
+ /// N.B. The cutoffs contain strictly more information than the SanitizerSet,
/// but the SanitizerSet is more efficient for some calculations.
- SanitizerMaskWeights NoSanitizeTopHotWeights = {0};
+ SanitizerMaskCutoffs NoSanitizeTopHotCutoffs = {0};
/// List of backend command-line options for -fembed-bitcode.
std::vector<uint8_t> CmdArgs;
diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h
index c1242a1a69ef3f..12c2c93a7f89f6 100644
--- a/clang/include/clang/Basic/Sanitizers.h
+++ b/clang/include/clang/Basic/Sanitizers.h
@@ -154,7 +154,7 @@ struct SanitizerKind {
#include "clang/Basic/Sanitizers.def"
}; // SanitizerKind
-using SanitizerMaskWeights = std::array<float, SanitizerKind::SO_Count>;
+using SanitizerMaskCutoffs = std::array<float, SanitizerKind::SO_Count>;
struct SanitizerSet {
/// Check if a certain (single) sanitizer is enabled.
@@ -192,18 +192,18 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
/// -fno-sanitize= value list.
/// Returns a non-zero SanitizerMask, or \c 0 if \p Value is not known.
/// The relevant weight(s) are updated in the passed array.
-/// Individual weights are never reset to zero unless explicitly set
+/// Individual Cutoffs are never reset to zero unless explicitly set
/// (e.g., 'null=0.0').
SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
- SanitizerMaskWeights *Weights);
+ SanitizerMaskCutoffs *Cutoffs);
/// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=.
void serializeSanitizerSet(SanitizerSet Set,
SmallVectorImpl<StringRef> &Values);
-/// Serialize a SanitizerMaskWeights into values for -fsanitize= or
+/// Serialize a SanitizerMaskCutoffs into values for -fsanitize= or
/// -fno-sanitize=.
-void serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights,
+void serializeSanitizerMaskCutoffs(const SanitizerMaskCutoffs Cutoffs,
SmallVectorImpl<std::string> &Values);
/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index ecdd4d1655cb78..027093157d4c73 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2652,8 +2652,10 @@ def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-unde
def fno_sanitize_top_hot_EQ
: CommaJoined<["-"], "fno-sanitize-top-hot=">,
Group<f_clang_Group>,
- HelpText<"Exclude sanitization for the top hottest fraction of code "
- "(0.0 [default] = skip none; 0.1 = skip hottest 10%; 1.0 = skip all)">;
+ HelpText<"Exclude sanitization for the top hottest code responsible for "
+ "the given fraction of PGO counters "
+ "(0.0 [default] = skip none; 1.0 = skip all). "
+ "Argument format: <sanitizer1>=,<sanitizer2>=,...">;
} // end -f[no-]sanitize* flags
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 28c067444f2e4c..2462228f533746 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -27,7 +27,7 @@ class SanitizerArgs {
SanitizerSet TrapSanitizers;
SanitizerSet MergeHandlers;
SanitizerSet TopHot;
- SanitizerMaskWeights TopHotWeights = {0};
+ SanitizerMaskCutoffs TopHotCutoffs = {0};
std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index b2fc7f8bcf49f0..6711b05c4539dd 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -38,7 +38,7 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
SanitizerMask
clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
- SanitizerMaskWeights *Weights) {
+ SanitizerMaskCutoffs *Cutoffs) {
SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
#define SANITIZER(NAME, ID) .StartsWith(NAME "=", SanitizerKind::ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
@@ -47,7 +47,7 @@ clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
#include "clang/Basic/Sanitizers.def"
.Default(SanitizerMask());
- if (ParsedKind && Weights) {
+ if (ParsedKind && Cutoffs) {
size_t equalsIndex = Value.find_first_of('=');
if (equalsIndex != llvm::StringLiteral::npos) {
double arg;
@@ -59,7 +59,7 @@ clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups,
for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++)
if (ExpandedKind & SanitizerMask::bitPosToMask(i))
- (*Weights)[i] = arg;
+ (*Cutoffs)[i] = arg;
}
}
}
@@ -75,12 +75,12 @@ void clang::serializeSanitizerSet(SanitizerSet Set,
#include "clang/Basic/Sanitizers.def"
}
-void clang::serializeSanitizerMaskWeights(
- const SanitizerMaskWeights Weights, SmallVectorImpl<std::string> &Values) {
+void clang::serializeSanitizerMaskCutoffs(
+ const SanitizerMaskCutoffs Cutoffs, SmallVectorImpl<std::string> &Values) {
#define SANITIZER(NAME, ID) \
- if (Weights[SanitizerKind::SO_##ID]) \
+ if (Cutoffs[SanitizerKind::SO_##ID]) \
Values.push_back(std::string(NAME "=") + \
- std::to_string(Weights[SanitizerKind::SO_##ID]));
+ std::to_string(Cutoffs[SanitizerKind::SO_##ID]));
#include "clang/Basic/Sanitizers.def"
}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index faa97f3bc5da79..f7db3e5032ce1a 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -112,7 +112,7 @@ enum BinaryMetadataFeature {
/// invalid components. Returns a SanitizerMask.
static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors,
- SanitizerMaskWeights *Weights);
+ SanitizerMaskCutoffs *Cutoffs);
/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
/// components. Returns OR of members of \c CoverageFeature enumeration.
@@ -261,7 +261,7 @@ static SanitizerMask
parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
bool DiagnoseErrors, SanitizerMask Default,
SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
- int OptOutID, SanitizerMaskWeights *Weights) {
+ int OptOutID, SanitizerMaskCutoffs *Cutoffs) {
assert(!(AlwaysIn & AlwaysOut) &&
"parseSanitizeArgs called with contradictory in/out requirements");
@@ -272,7 +272,7 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
SanitizerMask DiagnosedAlwaysOutViolations;
for (const auto *Arg : Args) {
if (Arg->getOption().matches(OptInID)) {
- SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors, Weights);
+ SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors, Cutoffs);
// Report error if user explicitly tries to opt-in to an always-out
// sanitizer.
if (SanitizerMask KindsToDiagnose =
@@ -288,7 +288,7 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
Output |= expandSanitizerGroups(Add);
Arg->claim();
} else if (Arg->getOption().matches(OptOutID)) {
- SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors, Weights);
+ SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors, Cutoffs);
// Report error if user explicitly tries to opt-out of an always-in
// sanitizer.
if (SanitizerMask KindsToDiagnose =
@@ -327,9 +327,9 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
static SanitizerMask parseNoSanitizeHotArgs(const Driver &D,
const llvm::opt::ArgList &Args,
bool DiagnoseErrors,
- SanitizerMaskWeights *Weights) {
+ SanitizerMaskCutoffs *Cutoffs) {
return parseSanitizeArgs(D, Args, DiagnoseErrors, {}, {}, {},
- options::OPT_fno_sanitize_top_hot_EQ, -1, Weights);
+ options::OPT_fno_sanitize_top_hot_EQ, -1, Cutoffs);
}
bool SanitizerArgs::needsFuzzerInterceptors() const {
@@ -724,7 +724,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Parse -fno-sanitize-top-hot flags
SanitizerMask TopHotMask =
- parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotWeights);
+ parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotCutoffs);
(void)TopHotMask;
// Setup ignorelist files.
@@ -1153,7 +1153,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Zero out TopHot for unused sanitizers
for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) {
if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i)))
- TopHotWeights[i] = 0;
+ TopHotCutoffs[i] = 0;
}
}
@@ -1169,14 +1169,14 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) {
return Res;
}
-static std::string toString(const clang::SanitizerMaskWeights &Weights) {
+static std::string toString(const clang::SanitizerMaskCutoffs &Cutoffs) {
std::string Res;
#define SANITIZER(NAME, ID) \
- if (Weights[SanitizerKind::SO_##ID]) { \
+ if (Cutoffs[SanitizerKind::SO_##ID]) { \
if (!Res.empty()) \
Res += ","; \
Res += std::string(NAME) + "=" + \
- std::to_string(Weights[SanitizerKind::SO_##ID]); \
+ std::to_string(Cutoffs[SanitizerKind::SO_##ID]); \
}
#include "clang/Basic/Sanitizers.def"
return Res;
@@ -1333,10 +1333,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-fsanitize-merge=" + toString(MergeHandlers)));
- std::string TopHotWeightsStr = toString(TopHotWeights);
- if (TopHotWeightsStr != "")
+ std::string TopHotCutoffsStr = toString(TopHotCutoffs);
+ if (TopHotCutoffsStr != "")
CmdArgs.push_back(
- Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotWeightsStr));
+ Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotCutoffsStr));
addSpecialCaseListOpt(Args, CmdArgs,
"-fsanitize-ignorelist=", UserIgnorelistFiles);
@@ -1505,7 +1505,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors,
- SanitizerMaskWeights *Weights) {
+ SanitizerMaskCutoffs *Cutoffs) {
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
@@ -1526,11 +1526,11 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
Kind = SanitizerMask();
else if (A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) {
assert(
- Weights &&
- "Null weights parameter provided for parsing fno_sanitize_top_hot!");
- Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Weights);
+ Cutoffs &&
+ "Null Cutoffs parameter provided for parsing fno_sanitize_top_hot!");
+ Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs);
} else {
- assert((!Weights) && "Non-null weights parameter erroneously provided!");
+ assert((!Cutoffs) && "Non-null Cutoffs parameter erroneously provided!");
Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 084e62c467535e..78dd5099259f18 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1438,10 +1438,10 @@ static SmallVector<StringRef, 4> serializeSanitizerKinds(SanitizerSet S) {
static void parseSanitizerWeightedKinds(
StringRef FlagName, const std::vector<std::string> &Sanitizers,
- DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights *Weights) {
+ DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskCutoffs *Cutoffs) {
for (const auto &Sanitizer : Sanitizers) {
SanitizerMask K =
- parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Weights);
+ parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs);
if (K == SanitizerMask())
Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer;
else
@@ -1810,7 +1810,7 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
GenerateArg(Consumer, OPT_fsanitize_merge_handlers_EQ, Sanitizer);
SmallVector<std::string, 4> Values;
- serializeSanitizerMaskWeights(Opts.NoSanitizeTopHotWeights, Values);
+ serializeSanitizerMaskCutoffs(Opts.NoSanitizeTopHotCutoffs, Values);
for (std::string Sanitizer : Values)
GenerateArg(Consumer, OPT_fno_sanitize_top_hot_EQ, Sanitizer);
@@ -2299,7 +2299,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
parseSanitizerWeightedKinds("-fno-sanitize-top-hot=",
Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ),
Diags, Opts.NoSanitizeTopHot,
- &Opts.NoSanitizeTopHotWeights);
+ &Opts.NoSanitizeTopHotCutoffs);
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
>From 66dbc49408f13089b1602c3b27db14b9cccf6d64 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Mon, 6 Jan 2025 23:30:51 +0000
Subject: [PATCH 9/9] Limit changes to Driver
---
clang/lib/CodeGen/CGExpr.cpp | 6 +-----
clang/test/CodeGen/allow-ubsan-check.c | 5 -----
2 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3e14b0ffa7b320..ba1cba291553b0 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3602,7 +3602,6 @@ void CodeGenFunction::EmitCheck(
llvm::Value *RecoverableCond = nullptr;
llvm::Value *TrapCond = nullptr;
bool NoMerge = false;
- bool SanitizeGuardChecks = ClSanitizeGuardChecks;
for (int i = 0, n = Checked.size(); i < n; ++i) {
llvm::Value *Check = Checked[i].first;
// -fsanitize-trap= overrides -fsanitize-recover=.
@@ -3616,12 +3615,9 @@ void CodeGenFunction::EmitCheck(
if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Checked[i].second))
NoMerge = true;
-
- if (!CGM.getCodeGenOpts().NoSanitizeTopHot.has(Checked[i].second))
- SanitizeGuardChecks = true;
}
- if (SanitizeGuardChecks) {
+ if (ClSanitizeGuardChecks) {
llvm::Value *Allow =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler));
diff --git a/clang/test/CodeGen/allow-ubsan-check.c b/clang/test/CodeGen/allow-ubsan-check.c
index adc56dee9ad02e..1c76049b57bda8 100644
--- a/clang/test/CodeGen/allow-ubsan-check.c
+++ b/clang/test/CodeGen/allow-ubsan-check.c
@@ -3,11 +3,6 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -mllvm -ubsan-guard-checks -fsanitize-trap=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=TRAP
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -mllvm -ubsan-guard-checks -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=RECOVER
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -fno-sanitize-top-hot=signed-integer-overflow=1,integer-divide-by-zero=1,null=1 | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -fno-sanitize-top-hot=signed-integer-overflow=1,integer-divide-by-zero=1,null=1 -fsanitize-trap=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=TRAP
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null -fno-sanitize-top-hot=signed-integer-overflow=1,integer-divide-by-zero=1,null=1 -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,null | FileCheck %s --check-prefixes=RECOVER
-
-
// CHECK-LABEL: define dso_local i32 @div(
// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
More information about the cfe-commits
mailing list