From ca1fabc5ea75af0acdd1969c0ad505e04103e1c9 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Sat, 4 Jan 2025 02:53:00 +0000 Subject: [PATCH 01/52] [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 8097c9ef772bc..f69f52e49a2fe 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 CmdArgs; diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index c890242269b33..fa6b557819a1a 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 &Values); +/// Serialize a SanitizerMaskWeights into values for -fsanitize= or -fno-sanitize=. +void serializeSanitizerMaskWeights(const SanitizerMaskWeights Weights, + SmallVectorImpl &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 d922709db1778..631a6099781e6 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, "0", "int">; +def fno_sanitize_top_hot_EQ + : CommaJoined<["-"], "fno-sanitize-top-hot=">, + 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 3b275092bbbe8..854893269e854 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 UserIgnorelistFiles; std::vector SystemIgnorelistFiles; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 62ccdf8e9bbf2..adfab2d3afab0 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(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 &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 &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 98116e2c8336b..0f500ca14c527 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 348c56cc37da3..c1c11f5a2325c 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 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 Date: Sat, 4 Jan 2025 03:22:24 +0000 Subject: [PATCH 02/52] 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 f69f52e49a2fe..39eabe0b1effa 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 fa6b557819a1a..f179fe5027ed0 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 &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 &Values); diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index adfab2d3afab0..c0e08ccfcdf74 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(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 &Values) { + SmallVectorImpl &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 0f500ca14c527..bac24dc824671 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 Date: Mon, 6 Jan 2025 18:41:15 +0000 Subject: [PATCH 03/52] 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 39eabe0b1effa..2cf0197d17c8f 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 631a6099781e6..ecdd4d1655cb7 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, - 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 c0e08ccfcdf74..924d86b036051 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 aeae15aada70c..9c08ad8c40bc6 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 Date: Mon, 6 Jan 2025 21:44:53 +0000 Subject: [PATCH 04/52] 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 2cf0197d17c8f..e648bc4ea90cd 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 CmdArgs; diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index f179fe5027ed0..d80e04ca1290c 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 &Values); + SmallVectorImpl &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 854893269e854..28c067444f2e4 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 UserIgnorelistFiles; std::vector SystemIgnorelistFiles; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 924d86b036051..92d9fb7255961 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 &Values) { + SmallVectorImpl &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 ba1cba291553b..3e14b0ffa7b32 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 bac24dc824671..cb1c0801a8c45 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 c1c11f5a2325c..e2705b111fb8d 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1436,6 +1436,18 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { return Values; } +static void parseSanitizerWeightedKinds(StringRef FlagName, + const std::vector &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 Values; - serializeSanitizerMaskWeights(Opts.NoSanitizeTopHot, Values); - for (StringRef Sanitizer : Values) + SmallVector 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 5232d24085466..adc56dee9ad02 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 9c08ad8c40bc6..211104fd66727 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 Date: Mon, 6 Jan 2025 21:50:26 +0000 Subject: [PATCH 05/52] 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 92d9fb7255961..13f42bd143e08 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 &Values) { +void clang::serializeSanitizerMaskWeights( + const SanitizerMaskWeights Weights, SmallVectorImpl &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 cb1c0801a8c45..773ebf53b005a 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 e2705b111fb8d..df7fac32fec58 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1436,11 +1436,12 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { return Values; } -static void parseSanitizerWeightedKinds(StringRef FlagName, - const std::vector &Sanitizers, - DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskWeights &Weights) { +static void parseSanitizerWeightedKinds( + StringRef FlagName, const std::vector &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 Date: Mon, 6 Jan 2025 22:43:30 +0000 Subject: [PATCH 06/52] using SanitizerMaskWeights = std::array --- 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 d80e04ca1290c..c1242a1a69ef3 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; 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 13f42bd143e08..179f2ad03714b 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(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 773ebf53b005a..44c1b353cf2d9 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 df7fac32fec58..084e62c467535 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1438,7 +1438,7 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { static void parseSanitizerWeightedKinds( StringRef FlagName, const std::vector &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 Date: Mon, 6 Jan 2025 22:43:40 +0000 Subject: [PATCH 07/52] 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 179f2ad03714b..b2fc7f8bcf49f 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(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 44c1b353cf2d9..faa97f3bc5da7 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 Date: Mon, 6 Jan 2025 23:28:45 +0000 Subject: [PATCH 08/52] 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 e648bc4ea90cd..227bddf831002 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 CmdArgs; diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index c1242a1a69ef3..12c2c93a7f89f 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; +using SanitizerMaskCutoffs = std::array; 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 &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 &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 ecdd4d1655cb7..027093157d4c7 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, - 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: =,=,...">; } // end -f[no-]sanitize* flags diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 28c067444f2e4..2462228f53374 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 UserIgnorelistFiles; std::vector SystemIgnorelistFiles; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index b2fc7f8bcf49f..6711b05c4539d 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(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 &Values) { +void clang::serializeSanitizerMaskCutoffs( + const SanitizerMaskCutoffs Cutoffs, SmallVectorImpl &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 faa97f3bc5da7..f7db3e5032ce1 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 084e62c467535..78dd5099259f1 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1438,10 +1438,10 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { static void parseSanitizerWeightedKinds( StringRef FlagName, const std::vector &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 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 Date: Mon, 6 Jan 2025 23:30:51 +0000 Subject: [PATCH 09/52] 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 3e14b0ffa7b32..ba1cba291553b 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 adc56dee9ad02..1c76049b57bda 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: From 6f5e7145d0c8eb2f8f62638d9fa15b3be777fb68 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 00:17:57 +0000 Subject: [PATCH 10/52] Reorder to make comment more logical --- clang/include/clang/Basic/CodeGenOptions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 227bddf831002..32dc39ed2a812 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -387,10 +387,10 @@ class CodeGenOptions : public CodeGenOptionsBase { /// 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; + SanitizerMaskCutoffs NoSanitizeTopHotCutoffs = {0}; /// N.B. The cutoffs contain strictly more information than the SanitizerSet, /// but the SanitizerSet is more efficient for some calculations. - SanitizerMaskCutoffs NoSanitizeTopHotCutoffs = {0}; + SanitizerSet NoSanitizeTopHot; /// List of backend command-line options for -fembed-bitcode. std::vector CmdArgs; From fc623f2f0e4cdda0533a26106a428d621dcacb5a Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 01:16:31 +0000 Subject: [PATCH 11/52] Refactor into parseArgCutoffs; update comment --- clang/include/clang/Basic/Sanitizers.h | 2 +- clang/include/clang/Driver/Options.td | 2 +- clang/lib/Basic/Sanitizers.cpp | 2 +- clang/lib/Driver/SanitizerArgs.cpp | 74 +++++++++++++++++++------- 4 files changed, 59 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 12c2c93a7f89f..9ddd6cd546f9a 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -203,7 +203,7 @@ void serializeSanitizerSet(SanitizerSet Set, /// Serialize a SanitizerMaskCutoffs into values for -fsanitize= or /// -fno-sanitize=. -void serializeSanitizerMaskCutoffs(const SanitizerMaskCutoffs Cutoffs, +void serializeSanitizerMaskCutoffs(const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl &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 027093157d4c7..b34faa544c609 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2655,7 +2655,7 @@ def fno_sanitize_top_hot_EQ 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: =,=,...">; + "Argument format: =,=,...">; } // end -f[no-]sanitize* flags diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 6711b05c4539d..74150f32c0ae7 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -76,7 +76,7 @@ void clang::serializeSanitizerSet(SanitizerSet Set, } void clang::serializeSanitizerMaskCutoffs( - const SanitizerMaskCutoffs Cutoffs, SmallVectorImpl &Values) { + const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl &Values) { #define SANITIZER(NAME, ID) \ if (Cutoffs[SanitizerKind::SO_##ID]) \ Values.push_back(std::string(NAME "=") + \ diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index f7db3e5032ce1..66d19545f4028 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -111,6 +111,22 @@ 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); + +/// Parse a -fsanitize==... or -fno-sanitize= argument's +/// values, diagnosing any invalid components. Returns a SanitizerMask. +/// Cutoffs are stored in the passed parameter. +static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors, + SanitizerMaskCutoffs *Cutoffs); + +/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any +/// invalid components. Returns a SanitizerMask. +/// +/// If Cutoffs is null, it assumes -fsanitize=... +/// Othrewise, it assumes -fsanitize==..., and cutoffs are +/// stored in the passed parameter. +static SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, SanitizerMaskCutoffs *Cutoffs); @@ -272,7 +288,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, Cutoffs); + SanitizerMask Add = parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); // Report error if user explicitly tries to opt-in to an always-out // sanitizer. if (SanitizerMask KindsToDiagnose = @@ -288,7 +304,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, Cutoffs); + SanitizerMask Remove = parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); // Report error if user explicitly tries to opt-out of an always-in // sanitizer. if (SanitizerMask KindsToDiagnose = @@ -412,7 +428,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, nullptr); + SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors); if (RemoveObjectSizeAtO0) { AllRemove |= SanitizerKind::ObjectSize; @@ -582,7 +598,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, nullptr); + SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors); AllRemove |= expandSanitizerGroups(Remove); } } @@ -1504,8 +1520,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, } SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs) { + bool DiagnoseErrors) { assert((A->getOption().matches(options::OPT_fsanitize_EQ) || A->getOption().matches(options::OPT_fno_sanitize_EQ) || A->getOption().matches(options::OPT_fsanitize_recover_EQ) || @@ -1513,8 +1528,7 @@ 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_top_hot_EQ)) && + A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ)) && "Invalid argument in parseArgValues!"); SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { @@ -1524,15 +1538,8 @@ 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 if (A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) { - assert( - Cutoffs && - "Null Cutoffs parameter provided for parsing fno_sanitize_top_hot!"); - Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); - } else { - assert((!Cutoffs) && "Non-null Cutoffs parameter erroneously provided!"); + else Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); - } if (Kind) Kinds |= Kind; @@ -1543,6 +1550,37 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, return Kinds; } +SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors, + SanitizerMaskCutoffs *Cutoffs) { + assert(A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ) && + "Invalid argument in parseArgCutoffs!"); + assert(Cutoffs && + "Null Cutoffs parameter provided for parsing fno_sanitize_top_hot!"); + + SanitizerMask Kinds; + for (int i = 0, n = A->getNumValues(); i != n; ++i) { + const char *Value = A->getValue(i); + SanitizerMask Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); + + if (Kind) + Kinds |= Kind; + else if (DiagnoseErrors) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + } + return Kinds; +} + +SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors, + SanitizerMaskCutoffs *Cutoffs) { + if (Cutoffs) + return parseArgCutoffs(D, A, DiagnoseErrors, Cutoffs); + else + return parseArgValues(D, A, DiagnoseErrors); +} + static int parseOverflowPatternExclusionValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors) { @@ -1635,12 +1673,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, nullptr)); + expandSanitizerGroups(parseArgValues(D, Arg, false)); if (AddKinds & Mask) return describeSanitizeArg(Arg, Mask); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { SanitizerMask RemoveKinds = - expandSanitizerGroups(parseArgValues(D, Arg, false, nullptr)); + expandSanitizerGroups(parseArgValues(D, Arg, false)); Mask &= ~RemoveKinds; } } From 00d135ee99302bf30c727e785ec900e97030197d Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 01:22:52 +0000 Subject: [PATCH 12/52] Remove unnecessary suppression --- clang/lib/Driver/SanitizerArgs.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 66d19545f4028..1033493ecb6c3 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -741,7 +741,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Parse -fno-sanitize-top-hot flags SanitizerMask TopHotMask = parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotCutoffs); - (void)TopHotMask; // Setup ignorelist files. // Add default ignorelist from resource directory for activated sanitizers, From 4d97bed1b403f5736ad8eb83140fca2f5c3ab1e7 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 01:23:50 +0000 Subject: [PATCH 13/52] clang-format --- clang/include/clang/Driver/Options.td | 9 ++++--- clang/lib/Driver/SanitizerArgs.cpp | 37 +++++++++++++++------------ 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b34faa544c609..4db17baa9c92f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2652,10 +2652,11 @@ def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-unde def fno_sanitize_top_hot_EQ : CommaJoined<["-"], "fno-sanitize-top-hot=">, Group, - 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: =,=,...">; + 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: =,=,...">; } // end -f[no-]sanitize* flags diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 1033493ecb6c3..18c7090088d5c 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -126,9 +126,10 @@ static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, /// If Cutoffs is null, it assumes -fsanitize=... /// Othrewise, it assumes -fsanitize==..., and cutoffs are /// stored in the passed parameter. -static SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs); +static SanitizerMask parseArgValuesOrCutoffs(const Driver &D, + const llvm::opt::Arg *A, + bool DiagnoseErrors, + SanitizerMaskCutoffs *Cutoffs); /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid /// components. Returns OR of members of \c CoverageFeature enumeration. @@ -288,7 +289,8 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args, SanitizerMask DiagnosedAlwaysOutViolations; for (const auto *Arg : Args) { if (Arg->getOption().matches(OptInID)) { - SanitizerMask Add = parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); + SanitizerMask Add = + parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); // Report error if user explicitly tries to opt-in to an always-out // sanitizer. if (SanitizerMask KindsToDiagnose = @@ -304,7 +306,8 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args, Output |= expandSanitizerGroups(Add); Arg->claim(); } else if (Arg->getOption().matches(OptOutID)) { - SanitizerMask Remove = parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); + SanitizerMask Remove = + parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); // Report error if user explicitly tries to opt-out of an always-in // sanitizer. if (SanitizerMask KindsToDiagnose = @@ -1520,15 +1523,16 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors) { - 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)) && - "Invalid argument in parseArgValues!"); + 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)) && + "Invalid argument in parseArgValues!"); SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); @@ -1555,12 +1559,13 @@ SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, assert(A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ) && "Invalid argument in parseArgCutoffs!"); assert(Cutoffs && - "Null Cutoffs parameter provided for parsing fno_sanitize_top_hot!"); + "Null Cutoffs parameter provided for parsing fno_sanitize_top_hot!"); SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); - SanitizerMask Kind = parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); + SanitizerMask Kind = + parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); if (Kind) Kinds |= Kind; From 1f528c5c98b5dce1cd73aa3169d50b8e896daeb4 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 02:25:02 +0000 Subject: [PATCH 14/52] Change Cutoffs* to Cutoffs& --- clang/include/clang/Basic/Sanitizers.h | 2 +- clang/lib/Basic/Sanitizers.cpp | 6 +++--- clang/lib/Driver/SanitizerArgs.cpp | 9 +++------ clang/lib/Frontend/CompilerInvocation.cpp | 4 ++-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 9ddd6cd546f9a..16f2b6c6da106 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -195,7 +195,7 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); /// Individual Cutoffs are never reset to zero unless explicitly set /// (e.g., 'null=0.0'). SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, - SanitizerMaskCutoffs *Cutoffs); + SanitizerMaskCutoffs &Cutoffs); /// 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 74150f32c0ae7..eecaf33ff9799 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, - SanitizerMaskCutoffs *Cutoffs) { + SanitizerMaskCutoffs &Cutoffs) { SanitizerMask ParsedKind = llvm::StringSwitch(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 && Cutoffs) { + if (ParsedKind) { 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)) - (*Cutoffs)[i] = arg; + Cutoffs[i] = arg; } } } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 18c7090088d5c..dd061264b3082 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -118,7 +118,7 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, /// Cutoffs are stored in the passed parameter. static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs); + SanitizerMaskCutoffs &Cutoffs); /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any /// invalid components. Returns a SanitizerMask. @@ -1555,12 +1555,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs) { + SanitizerMaskCutoffs &Cutoffs) { assert(A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ) && "Invalid argument in parseArgCutoffs!"); - assert(Cutoffs && - "Null Cutoffs parameter provided for parsing fno_sanitize_top_hot!"); - SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); @@ -1580,7 +1577,7 @@ SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, SanitizerMaskCutoffs *Cutoffs) { if (Cutoffs) - return parseArgCutoffs(D, A, DiagnoseErrors, Cutoffs); + return parseArgCutoffs(D, A, DiagnoseErrors, *Cutoffs); else return parseArgValues(D, A, DiagnoseErrors); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 78dd5099259f1..f71c41e6ae8f7 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1438,7 +1438,7 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { static void parseSanitizerWeightedKinds( StringRef FlagName, const std::vector &Sanitizers, - DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskCutoffs *Cutoffs) { + DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskCutoffs &Cutoffs) { for (const auto &Sanitizer : Sanitizers) { SanitizerMask K = parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs); @@ -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.NoSanitizeTopHotCutoffs); + Opts.NoSanitizeTopHotCutoffs); Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); From 071e10e79598409e8393848b5fd067b19bc725a2 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 03:45:42 +0000 Subject: [PATCH 15/52] Remove SanitizerMask TopHot --- clang/include/clang/Basic/CodeGenOptions.h | 3 --- clang/include/clang/Basic/Sanitizers.h | 6 +++--- clang/include/clang/Driver/SanitizerArgs.h | 1 - clang/lib/Basic/Sanitizers.cpp | 6 ++++-- clang/lib/Driver/SanitizerArgs.cpp | 17 +++++++++-------- clang/lib/Frontend/CompilerInvocation.cpp | 11 +++-------- 6 files changed, 19 insertions(+), 25 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 32dc39ed2a812..856dc10be9211 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -388,9 +388,6 @@ class CodeGenOptions : public CodeGenOptionsBase { /// fraction of PGO counters will be excluded from sanitization /// (0.0 [default] = skip none, 1.0 = skip all). SanitizerMaskCutoffs NoSanitizeTopHotCutoffs = {0}; - /// N.B. The cutoffs contain strictly more information than the SanitizerSet, - /// but the SanitizerSet is more efficient for some calculations. - SanitizerSet NoSanitizeTopHot; /// List of backend command-line options for -fembed-bitcode. std::vector CmdArgs; diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 16f2b6c6da106..d92c555161675 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -190,12 +190,12 @@ 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 Cutoffs are never reset to zero unless explicitly set /// (e.g., 'null=0.0'). -SanitizerMask parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, - SanitizerMaskCutoffs &Cutoffs); +/// Returns \c False if \p Value is not known. +bool parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, + SanitizerMaskCutoffs &Cutoffs); /// Serialize a SanitizerSet into values for -fsanitize= or -fno-sanitize=. void serializeSanitizerSet(SanitizerSet Set, diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 2462228f53374..098e5a1682dbc 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -26,7 +26,6 @@ class SanitizerArgs { SanitizerSet RecoverableSanitizers; SanitizerSet TrapSanitizers; SanitizerSet MergeHandlers; - SanitizerSet TopHot; SanitizerMaskCutoffs TopHotCutoffs = {0}; std::vector UserIgnorelistFiles; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index eecaf33ff9799..59a0f6f0af1da 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -36,7 +36,7 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { return ParsedKind; } -SanitizerMask +bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskCutoffs &Cutoffs) { SanitizerMask ParsedKind = llvm::StringSwitch(Value) @@ -62,9 +62,11 @@ clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, Cutoffs[i] = arg; } } + + return true; } - return ParsedKind; + return false; } void clang::serializeSanitizerSet(SanitizerSet Set, diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index dd061264b3082..32715965b64b7 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -742,8 +742,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeKinds &= Kinds; // Parse -fno-sanitize-top-hot flags - SanitizerMask TopHotMask = - parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotCutoffs); + parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotCutoffs); // Setup ignorelist files. // Add default ignorelist from resource directory for activated sanitizers, @@ -1165,10 +1164,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeHandlers.Mask |= MergeKinds; - TopHotMask &= Sanitizers.Mask; - TopHot.Mask = TopHotMask; - - // Zero out TopHot for unused sanitizers + // Zero out TopHotCutoffs for unused sanitizers for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i))) TopHotCutoffs[i] = 0; @@ -1561,8 +1557,13 @@ SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); - SanitizerMask Kind = - parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); + parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); + + SanitizerMask Kind; + for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { + if (Cutoffs[i]) + Kind |= SanitizerMask::bitPosToMask(i); + } if (Kind) Kinds |= Kind; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index f71c41e6ae8f7..a62b7ac0d3b04 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1438,14 +1438,10 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { static void parseSanitizerWeightedKinds( StringRef FlagName, const std::vector &Sanitizers, - DiagnosticsEngine &Diags, SanitizerSet &S, SanitizerMaskCutoffs &Cutoffs) { + DiagnosticsEngine &Diags, SanitizerMaskCutoffs &Cutoffs) { for (const auto &Sanitizer : Sanitizers) { - SanitizerMask K = - parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs); - if (K == SanitizerMask()) + if (!parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs)) Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer; - else - S.set(K, true); } } @@ -2298,8 +2294,7 @@ 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.NoSanitizeTopHotCutoffs); + Diags, Opts.NoSanitizeTopHotCutoffs); Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); From c970179e7b902ea009f21135623d9f0f715bdd12 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 03:54:00 +0000 Subject: [PATCH 16/52] Rely on RVO --- clang/lib/Frontend/CompilerInvocation.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a62b7ac0d3b04..b9df7237b9302 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1436,13 +1436,15 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { return Values; } -static void parseSanitizerWeightedKinds( +static SanitizerMaskCutoffs parseSanitizerWeightedKinds( StringRef FlagName, const std::vector &Sanitizers, - DiagnosticsEngine &Diags, SanitizerMaskCutoffs &Cutoffs) { + DiagnosticsEngine &Diags) { + SanitizerMaskCutoffs Cutoffs; for (const auto &Sanitizer : Sanitizers) { if (!parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs)) Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer; } + return Cutoffs; } static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle, @@ -2292,9 +2294,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Diags, Opts.SanitizeMergeHandlers); // Parse -fno-sanitize-top-hot= arguments. - parseSanitizerWeightedKinds("-fno-sanitize-top-hot=", + Opts.NoSanitizeTopHotCutoffs = parseSanitizerWeightedKinds("-fno-sanitize-top-hot=", Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ), - Diags, Opts.NoSanitizeTopHotCutoffs); + Diags); Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); From b2bb1d6d34afce14de2587c39517c20f1f732aec Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 04:30:25 +0000 Subject: [PATCH 17/52] Fix uninitialized memory --- clang/lib/Driver/SanitizerArgs.cpp | 3 +++ clang/lib/Frontend/CompilerInvocation.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 32715965b64b7..7c68f5c8b7f98 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1561,6 +1561,9 @@ SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, SanitizerMask Kind; for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { + // Invoking bitPosToMask repeatedly is inefficient: we could simply + // repeatedly set the LSB then left-shift; however, we assume the + // compiler will optimize this (in any case, the runtime is negligible). if (Cutoffs[i]) Kind |= SanitizerMask::bitPosToMask(i); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b9df7237b9302..27885869929f3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1439,7 +1439,7 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { static SanitizerMaskCutoffs parseSanitizerWeightedKinds( StringRef FlagName, const std::vector &Sanitizers, DiagnosticsEngine &Diags) { - SanitizerMaskCutoffs Cutoffs; + SanitizerMaskCutoffs Cutoffs = {0}; for (const auto &Sanitizer : Sanitizers) { if (!parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs)) Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer; From 369e6c81fea87a69db90f3276984b51dfd342df4 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 04:30:56 +0000 Subject: [PATCH 18/52] clang-format --- clang/lib/Basic/Sanitizers.cpp | 5 ++--- clang/lib/Frontend/CompilerInvocation.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 59a0f6f0af1da..9b84b04a284ef 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -36,9 +36,8 @@ SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { return ParsedKind; } -bool -clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, - SanitizerMaskCutoffs &Cutoffs) { +bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, + SanitizerMaskCutoffs &Cutoffs) { SanitizerMask ParsedKind = llvm::StringSwitch(Value) #define SANITIZER(NAME, ID) .StartsWith(NAME "=", SanitizerKind::ID) #define SANITIZER_GROUP(NAME, ID, ALIAS) \ diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 27885869929f3..100b408b3092f 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1436,9 +1436,10 @@ static SmallVector serializeSanitizerKinds(SanitizerSet S) { return Values; } -static SanitizerMaskCutoffs parseSanitizerWeightedKinds( - StringRef FlagName, const std::vector &Sanitizers, - DiagnosticsEngine &Diags) { +static SanitizerMaskCutoffs +parseSanitizerWeightedKinds(StringRef FlagName, + const std::vector &Sanitizers, + DiagnosticsEngine &Diags) { SanitizerMaskCutoffs Cutoffs = {0}; for (const auto &Sanitizer : Sanitizers) { if (!parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs)) @@ -2294,9 +2295,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Diags, Opts.SanitizeMergeHandlers); // Parse -fno-sanitize-top-hot= arguments. - Opts.NoSanitizeTopHotCutoffs = parseSanitizerWeightedKinds("-fno-sanitize-top-hot=", - Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ), - Diags); + Opts.NoSanitizeTopHotCutoffs = parseSanitizerWeightedKinds( + "-fno-sanitize-top-hot=", + Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ), Diags); Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); From c6d4e7344c427e482cc744bb6b8b89e3b6371eb7 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 06:22:27 +0000 Subject: [PATCH 19/52] Allow passing -fno-sanitize-top-hot=undefined=0.0. Add more tests. --- clang/lib/Driver/SanitizerArgs.cpp | 27 ++++++++------- clang/test/Driver/fsanitize.c | 53 ++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 7c68f5c8b7f98..fd0564ede4131 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1554,26 +1554,25 @@ SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, SanitizerMaskCutoffs &Cutoffs) { assert(A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ) && "Invalid argument in parseArgCutoffs!"); - SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); - parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs); - - SanitizerMask Kind; - for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { - // Invoking bitPosToMask repeatedly is inefficient: we could simply - // repeatedly set the LSB then left-shift; however, we assume the - // compiler will optimize this (in any case, the runtime is negligible). - if (Cutoffs[i]) - Kind |= SanitizerMask::bitPosToMask(i); - } - if (Kind) - Kinds |= Kind; - else if (DiagnoseErrors) + // We don't check the value of Cutoffs[i]: it's legal to specify + // -fsanitize-blah=value=0.0. + if (!parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs)) D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getSpelling() << Value; } + + SanitizerMask Kinds; + for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { + // Invoking bitPosToMask repeatedly is inefficient: we could simply + // set the LSB then left-shift in a loop; however, we assume the compiler + // will optimize this (in any case, the runtime is negligible). + if (Cutoffs[i]) + Kinds |= SanitizerMask::bitPosToMask(i); + } + return Kinds; } diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 211104fd66727..3eef0ce5f7128 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1156,20 +1156,39 @@ // 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}"}} - -// 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}"}} +// * Test -fno-sanitize-top-hot * + +// -fno-sanitize-top-hot=undefined=0.5 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT1 +// CHECK-TOP-HOT1: "-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 specified, -fno-sanitize-top-hot=... is a no-op and does not enable any sanitizers. +// RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT2 +// CHECK-TOP-HOT2-NOT: "-fsanitize" +// CHECK-TOP-HOT2-NOT: "-fno-sanitize-top-hot" + +// Enable undefined, then cancel out integer using a cutoff of 0.0 +// 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-TOP-HOT3 +// CHECK-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}"}} + +// Enable undefined, then cancel out integer using a cutoff of 0.0, then re-enable signed-integer-overflow +// 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-TOP-HOT4 +// CHECK-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}"}} + +// Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize= checks. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 +// CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.4(0*),?){4}"}} + +// It's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 +// CHECK-TOP-HOT6: "-fsanitize={{((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),?){19}"}} +// CHECK-TOP-HOT6-NOT: unsupported argument +// CHECK-TOP-HOT6-NOT: "-fno-sanitize-top-hot" + +// Invalid sanitizer 'pot' +// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=pot=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT7 +// CHECK-TOP-HOT7: unsupported argument 'pot=0.0' to option '-fno-sanitize-top-hot=' + +// -fno-sanitize-top without parameters is not valid +// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT8 +// CHECK-TOP-HOT8: unknown argument: '-fno-sanitize-top-hot' From 85b898c33ff540a2c9f35a0d28a3745abd395255 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 17:08:04 +0000 Subject: [PATCH 20/52] Check cutoffs in parsing. Update tests. --- clang/lib/Basic/Sanitizers.cpp | 4 ++-- clang/test/Driver/fsanitize.c | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 9b84b04a284ef..e3c54d4561063 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -59,10 +59,10 @@ bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) if (ExpandedKind & SanitizerMask::bitPosToMask(i)) Cutoffs[i] = arg; + + return true; } } - - return true; } return false; diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 3eef0ce5f7128..f2da42e834a4d 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1185,10 +1185,26 @@ // CHECK-TOP-HOT6-NOT: unsupported argument // CHECK-TOP-HOT6-NOT: "-fno-sanitize-top-hot" -// Invalid sanitizer 'pot' +// Invalid: bad sanitizer // RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=pot=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT7 // CHECK-TOP-HOT7: unsupported argument 'pot=0.0' to option '-fno-sanitize-top-hot=' -// -fno-sanitize-top without parameters is not valid -// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT8 -// CHECK-TOP-HOT8: unknown argument: '-fno-sanitize-top-hot' +// Invalid: bad cutoff +// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=xyzzy %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT8 +// CHECK-TOP-HOT8: unsupported argument 'undefined=xyzzy' to option '-fno-sanitize-top-hot=' + +// Invalid: -fno-sanitize-top without parameters +// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT9 +// CHECK-TOP-HOT9: unknown argument: '-fno-sanitize-top-hot' + +// Invalid: -fno-sanitize-top=undefined without cutoff +// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT10 +// CHECK-TOP-HOT10: unsupported argument 'undefined' to option '-fno-sanitize-top-hot=' + +// Invalid: -fno-sanitize-top=undefined= without cutoff +// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT11 +// CHECK-TOP-HOT11: unsupported argument 'undefined=' to option '-fno-sanitize-top-hot=' + +// -fno-sanitize-top= without parameters is unusual but valid (no-op) +// RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT12 +// CHECK-TOP-HOT12-NOT: "-fno-sanitize-top-hot" From 6cd43bb3ceea000d763d17bfc5fc2ad085579bcd Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 17:14:41 +0000 Subject: [PATCH 21/52] Change cutoffs parser to return an empty SanitizerMask (Cutoffs becomes the sole source of truth) --- clang/lib/Driver/SanitizerArgs.cpp | 22 ++++++++-------------- clang/test/Driver/fsanitize.c | 9 +++++---- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index fd0564ede4131..3d28cb60a0c4d 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -114,7 +114,7 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors); /// Parse a -fsanitize==... or -fno-sanitize= argument's -/// values, diagnosing any invalid components. Returns a SanitizerMask. +/// values, diagnosing any invalid components. Returns an EMPTY SanitizerMask. /// Cutoffs are stored in the passed parameter. static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, @@ -123,9 +123,12 @@ static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any /// invalid components. Returns a SanitizerMask. /// -/// If Cutoffs is null, it assumes -fsanitize=... -/// Othrewise, it assumes -fsanitize==..., and cutoffs are -/// stored in the passed parameter. +/// If Cutoffs is null, it assumes -fsanitize=,,... +/// and returns the result in the SanitizerMask. +/// +/// Otherwise, it assumes -fsanitize==,=,... +/// and returns an EMPTY SanitizerMask; results are stored in the passed +/// Cutoffs. static SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, @@ -1564,16 +1567,7 @@ SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, << A->getSpelling() << Value; } - SanitizerMask Kinds; - for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { - // Invoking bitPosToMask repeatedly is inefficient: we could simply - // set the LSB then left-shift in a loop; however, we assume the compiler - // will optimize this (in any case, the runtime is negligible). - if (Cutoffs[i]) - Kinds |= SanitizerMask::bitPosToMask(i); - } - - return Kinds; + return {}; } SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index f2da42e834a4d..8fab84dad1270 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1162,7 +1162,7 @@ // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT1 // CHECK-TOP-HOT1: "-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 specified, -fno-sanitize-top-hot=... is a no-op and does not enable any sanitizers. +// No-op: no sanitizers are specified // RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT2 // CHECK-TOP-HOT2-NOT: "-fsanitize" // CHECK-TOP-HOT2-NOT: "-fno-sanitize-top-hot" @@ -1175,11 +1175,11 @@ // 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-TOP-HOT4 // CHECK-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}"}} -// Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize= checks. +// Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize=integer checks. // RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 // CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.4(0*),?){4}"}} -// It's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. +// No-op: it's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 // CHECK-TOP-HOT6: "-fsanitize={{((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),?){19}"}} // CHECK-TOP-HOT6-NOT: unsupported argument @@ -1205,6 +1205,7 @@ // RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT11 // CHECK-TOP-HOT11: unsupported argument 'undefined=' to option '-fno-sanitize-top-hot=' -// -fno-sanitize-top= without parameters is unusual but valid (no-op) +// No-op: -fno-sanitize-top= without parameters is unusual but valid // RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT12 +// CHECK-TOP-HOT12-NOT: unsupported argument // CHECK-TOP-HOT12-NOT: "-fno-sanitize-top-hot" From c4b6a68fd5eb3e8a802225c604f833ea2ffa31e9 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 17:55:14 +0000 Subject: [PATCH 22/52] Simplify parseNoSanitizeHotArgs by not relying on parseSanitizeArgs --- clang/lib/Driver/SanitizerArgs.cpp | 41 ++++++++++-------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 3d28cb60a0c4d..f0d6cb029c391 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -120,20 +120,6 @@ static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, SanitizerMaskCutoffs &Cutoffs); -/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any -/// invalid components. Returns a SanitizerMask. -/// -/// If Cutoffs is null, it assumes -fsanitize=,,... -/// and returns the result in the SanitizerMask. -/// -/// Otherwise, it assumes -fsanitize==,=,... -/// and returns an EMPTY SanitizerMask; results are stored in the passed -/// Cutoffs. -static SanitizerMask parseArgValuesOrCutoffs(const Driver &D, - const llvm::opt::Arg *A, - bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs); - /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid /// components. Returns OR of members of \c CoverageFeature enumeration. static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, @@ -281,7 +267,7 @@ static SanitizerMask parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args, bool DiagnoseErrors, SanitizerMask Default, SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID, - int OptOutID, SanitizerMaskCutoffs *Cutoffs) { + int OptOutID) { assert(!(AlwaysIn & AlwaysOut) && "parseSanitizeArgs called with contradictory in/out requirements"); @@ -292,8 +278,7 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args, SanitizerMask DiagnosedAlwaysOutViolations; for (const auto *Arg : Args) { if (Arg->getOption().matches(OptInID)) { - SanitizerMask Add = - parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); + SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors); // Report error if user explicitly tries to opt-in to an always-out // sanitizer. if (SanitizerMask KindsToDiagnose = @@ -309,8 +294,7 @@ parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args, Output |= expandSanitizerGroups(Add); Arg->claim(); } else if (Arg->getOption().matches(OptOutID)) { - SanitizerMask Remove = - parseArgValuesOrCutoffs(D, Arg, DiagnoseErrors, Cutoffs); + SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors); // Report error if user explicitly tries to opt-out of an always-in // sanitizer. if (SanitizerMask KindsToDiagnose = @@ -343,15 +327,16 @@ 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, nullptr); + options::OPT_fno_sanitize_trap_EQ); } -static SanitizerMask parseNoSanitizeHotArgs(const Driver &D, - const llvm::opt::ArgList &Args, - bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs) { - return parseSanitizeArgs(D, Args, DiagnoseErrors, {}, {}, {}, - options::OPT_fno_sanitize_top_hot_EQ, -1, Cutoffs); +static void parseNoSanitizeHotArgs(const Driver &D, + const llvm::opt::ArgList &Args, + bool DiagnoseErrors, + SanitizerMaskCutoffs *Cutoffs) { + for (const auto *Arg : Args) + if (Arg->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) + parseArgCutoffs(D, Arg, DiagnoseErrors, *Cutoffs); } bool SanitizerArgs::needsFuzzerInterceptors() const { @@ -729,7 +714,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, nullptr); + options::OPT_fno_sanitize_recover_EQ); RecoverableKinds |= AlwaysRecoverable; RecoverableKinds &= ~Unrecoverable; RecoverableKinds &= Kinds; @@ -741,7 +726,7 @@ 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, nullptr); + options::OPT_fno_sanitize_merge_handlers_EQ); MergeKinds &= Kinds; // Parse -fno-sanitize-top-hot flags From 57d6c5946c507b461ae4307c20aa81f0d9463fac Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 17:59:21 +0000 Subject: [PATCH 23/52] Change parseArgCutoffs to void return --- clang/include/clang/Basic/Sanitizers.h | 4 ++-- clang/lib/Driver/SanitizerArgs.cpp | 28 ++++++++------------------ 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index d92c555161675..718d19b76f4df 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -190,10 +190,10 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); /// Parse a single weighted value (e.g., 'undefined=0.05') from a -fsanitize= or /// -fno-sanitize= value list. -/// The relevant weight(s) are updated in the passed array. +/// The relevant weight(s) are updated in the passed Cutoffs parameter. /// Individual Cutoffs are never reset to zero unless explicitly set /// (e.g., 'null=0.0'). -/// Returns \c False if \p Value is not known. +/// Returns \c False if \p Value is not known or the weight is not valid. bool parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskCutoffs &Cutoffs); diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index f0d6cb029c391..9e47ce2bbaca3 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -114,11 +114,10 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors); /// Parse a -fsanitize==... or -fno-sanitize= argument's -/// values, diagnosing any invalid components. Returns an EMPTY SanitizerMask. +/// values, diagnosing any invalid components. /// Cutoffs are stored in the passed parameter. -static SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors, - SanitizerMaskCutoffs &Cutoffs); +static void parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors, SanitizerMaskCutoffs &Cutoffs); /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid /// components. Returns OR of members of \c CoverageFeature enumeration. @@ -1537,31 +1536,20 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, return Kinds; } -SanitizerMask parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors, - SanitizerMaskCutoffs &Cutoffs) { +void parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors, SanitizerMaskCutoffs &Cutoffs) { assert(A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ) && "Invalid argument in parseArgCutoffs!"); for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); // We don't check the value of Cutoffs[i]: it's legal to specify - // -fsanitize-blah=value=0.0. - if (!parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs)) + // a cutoff of 0. + if (!parseSanitizerWeightedValue(Value, /*AllowGroups=*/true, Cutoffs) && + DiagnoseErrors) D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getSpelling() << Value; } - - return {}; -} - -SanitizerMask parseArgValuesOrCutoffs(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs) { - if (Cutoffs) - return parseArgCutoffs(D, A, DiagnoseErrors, *Cutoffs); - else - return parseArgValues(D, A, DiagnoseErrors); } static int parseOverflowPatternExclusionValues(const Driver &D, From 56ba349e7f085fca3bfd531ea219b1d9e8ef177c Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 22:28:24 +0000 Subject: [PATCH 24/52] Convert SanitizerMaskCutoffs to struct --- clang/include/clang/Basic/Sanitizers.h | 8 +++++++- clang/include/clang/Driver/SanitizerArgs.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 718d19b76f4df..67c18e4c539a8 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -154,7 +154,13 @@ struct SanitizerKind { #include "clang/Basic/Sanitizers.def" }; // SanitizerKind -using SanitizerMaskCutoffs = std::array; +struct SanitizerMaskCutoffs { + std::array data = {0}; + + float &operator[](int index) { return data[index]; } + + const float &operator[](int index) const { return data[index]; } +}; // SanitizerMaskCutoffs; struct SanitizerSet { /// Check if a certain (single) sanitizer is enabled. diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 098e5a1682dbc..6e46922800a5f 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -26,7 +26,7 @@ class SanitizerArgs { SanitizerSet RecoverableSanitizers; SanitizerSet TrapSanitizers; SanitizerSet MergeHandlers; - SanitizerMaskCutoffs TopHotCutoffs = {0}; + SanitizerMaskCutoffs TopHotCutoffs; std::vector UserIgnorelistFiles; std::vector SystemIgnorelistFiles; From 2298f93af8ea35021b02091c7a2365dda31ee38c Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 22:31:23 +0000 Subject: [PATCH 25/52] Omit redundant initialization --- clang/include/clang/Basic/CodeGenOptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 856dc10be9211..581182a4d0080 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -387,7 +387,7 @@ class CodeGenOptions : public CodeGenOptionsBase { /// 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). - SanitizerMaskCutoffs NoSanitizeTopHotCutoffs = {0}; + SanitizerMaskCutoffs NoSanitizeTopHotCutoffs; /// List of backend command-line options for -fembed-bitcode. std::vector CmdArgs; From a5ff1447f6b4695b7a5fa6112e97480ee28a40c6 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 22:37:17 +0000 Subject: [PATCH 26/52] Remove unnecessary braces --- clang/lib/Driver/SanitizerArgs.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 9e47ce2bbaca3..0e470e03deb09 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1152,10 +1152,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeHandlers.Mask |= MergeKinds; // Zero out TopHotCutoffs for unused sanitizers - for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) { + for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i))) TopHotCutoffs[i] = 0; - } } static std::string toString(const clang::SanitizerSet &Sanitizers) { From 46e90e5309cb76177a66ebd2d60eb2b31b6b8ad5 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 22:44:19 +0000 Subject: [PATCH 27/52] Rename 'data' to 'cutoffs' --- clang/include/clang/Basic/Sanitizers.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 67c18e4c539a8..003ee99630d42 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -155,11 +155,11 @@ struct SanitizerKind { }; // SanitizerKind struct SanitizerMaskCutoffs { - std::array data = {0}; + std::array cutoffs = {0}; - float &operator[](int index) { return data[index]; } + float &operator[](int index) { return cutoffs[index]; } - const float &operator[](int index) const { return data[index]; } + const float &operator[](int index) const { return cutoffs[index]; } }; // SanitizerMaskCutoffs; struct SanitizerSet { From 58550e945564259ca9255d33ed5800a43c6f2554 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 14:57:33 -0800 Subject: [PATCH 28/52] Improve comment --- clang/include/clang/Basic/CodeGenOptions.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 581182a4d0080..889ebb8242574 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 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). + /// Set of thresholds in a range [0.0, 1.0]: the top hottest code responsible + /// for the given fraction of PGO counters will be excluded from sanitization + /// (0.0 [default] to skip none, 1.0 to skip all). SanitizerMaskCutoffs NoSanitizeTopHotCutoffs; /// List of backend command-line options for -fembed-bitcode. From b2f0e5d78ba4e8572d37588b8c6b52e95f03efca Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 14:59:20 -0800 Subject: [PATCH 29/52] Make SanitizerMaskCutoffs class --- clang/include/clang/Basic/Sanitizers.h | 4 ++-- clang/lib/Frontend/CompilerInvocation.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 003ee99630d42..a96ebe743e3ea 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -154,11 +154,11 @@ struct SanitizerKind { #include "clang/Basic/Sanitizers.def" }; // SanitizerKind -struct SanitizerMaskCutoffs { +class SanitizerMaskCutoffs { std::array cutoffs = {0}; + public: float &operator[](int index) { return cutoffs[index]; } - const float &operator[](int index) const { return cutoffs[index]; } }; // SanitizerMaskCutoffs; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 100b408b3092f..2b1754e565651 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1440,7 +1440,7 @@ static SanitizerMaskCutoffs parseSanitizerWeightedKinds(StringRef FlagName, const std::vector &Sanitizers, DiagnosticsEngine &Diags) { - SanitizerMaskCutoffs Cutoffs = {0}; + SanitizerMaskCutoffs Cutoffs; for (const auto &Sanitizer : Sanitizers) { if (!parseSanitizerWeightedValue(Sanitizer, /*AllowGroups=*/false, Cutoffs)) Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer; From be0f4e8bbf656780a71dfed6cc796889eb888f09 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 15:05:52 -0800 Subject: [PATCH 30/52] Remove unrelated change --- clang/test/CodeGen/allow-ubsan-check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/test/CodeGen/allow-ubsan-check.c b/clang/test/CodeGen/allow-ubsan-check.c index 1c76049b57bda..5232d24085466 100644 --- a/clang/test/CodeGen/allow-ubsan-check.c +++ b/clang/test/CodeGen/allow-ubsan-check.c @@ -3,6 +3,7 @@ // 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 + // CHECK-LABEL: define dso_local i32 @div( // CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: entry: From a21c77b247cb557cdcf0459c50fdd47aaa67caad Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 15:09:00 -0800 Subject: [PATCH 31/52] Simplify parseSanitizerWeightedValue and add clamp --- clang/lib/Basic/Sanitizers.cpp | 35 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index e3c54d4561063..afc0ad52c1fb8 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/MathExtras.h" +#include using namespace clang; @@ -46,26 +47,20 @@ bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, #include "clang/Basic/Sanitizers.def" .Default(SanitizerMask()); - if (ParsedKind) { - 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)) - Cutoffs[i] = arg; - - return true; - } - } - } - - return false; + if (!ParsedKind) + return false; + auto [N, W] = Value.split('='); + double A; + if (W.getAsDouble(A)) + return false; + float C = std::clamp()(A, 0.0, 1.0); + // 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)) + Cutoffs[i] = C; + return true; } void clang::serializeSanitizerSet(SanitizerSet Set, From 27fe651425853ca635cb2a3d357b2f5c82734394 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 15:18:37 -0800 Subject: [PATCH 32/52] Fix clamp call --- clang/lib/Basic/Sanitizers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index afc0ad52c1fb8..d6384f621f197 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -53,7 +53,7 @@ bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, double A; if (W.getAsDouble(A)) return false; - float C = std::clamp()(A, 0.0, 1.0); + float C = std::clamp(A, 0.0, 1.0); // AllowGroups is already taken into account for ParsedKind, // hence we unconditionally expandSanitizerGroups. SanitizerMask ExpandedKind = expandSanitizerGroups(ParsedKind); From 45a9fa5b9b4567f70e44efd97dc4e0fef47dd3f8 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 7 Jan 2025 23:55:08 +0000 Subject: [PATCH 33/52] Whitespace --- clang/include/clang/Basic/Sanitizers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index a96ebe743e3ea..60c210630ea08 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -157,7 +157,7 @@ struct SanitizerKind { class SanitizerMaskCutoffs { std::array cutoffs = {0}; - public: +public: float &operator[](int index) { return cutoffs[index]; } const float &operator[](int index) const { return cutoffs[index]; } }; // SanitizerMaskCutoffs; From 5ab2a2becc74dd0f25a3372157f8da6dc6782602 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 15:22:58 -0800 Subject: [PATCH 34/52] Fix case in comment --- clang/include/clang/Basic/Sanitizers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 60c210630ea08..a7a766714ba1a 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -199,7 +199,7 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups); /// The relevant weight(s) are updated in the passed Cutoffs parameter. /// Individual Cutoffs are never reset to zero unless explicitly set /// (e.g., 'null=0.0'). -/// Returns \c False if \p Value is not known or the weight is not valid. +/// Returns \c false if \p Value is not known or the weight is not valid. bool parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, SanitizerMaskCutoffs &Cutoffs); From a9c8d582f5a3304fa1a12aabcf93df4f5a9a05eb Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 16:20:58 -0800 Subject: [PATCH 35/52] Hide clear logic into SanitizerMaskCutoffs --- clang/include/clang/Basic/Sanitizers.h | 4 +++- clang/lib/Basic/Sanitizers.cpp | 6 ++++++ clang/lib/Driver/SanitizerArgs.cpp | 4 +--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index a7a766714ba1a..7dc32cee289fa 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -160,7 +160,9 @@ class SanitizerMaskCutoffs { public: float &operator[](int index) { return cutoffs[index]; } const float &operator[](int index) const { return cutoffs[index]; } -}; // SanitizerMaskCutoffs; + + void clear(SanitizerMask K = SanitizerKind::All); +}; struct SanitizerSet { /// Check if a certain (single) sanitizer is enabled. diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index d6384f621f197..8fab5e28c17ae 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -19,6 +19,12 @@ using namespace clang; +void SanitizerMaskCutoffs::clear(SanitizerMask K) { + for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) + if (!(K & SanitizerMask::bitPosToMask(i))) + cutoffs[i] = 0; +} + // Once LLVM switches to C++17, the constexpr variables can be inline and we // won't need this. #define SANITIZER(NAME, ID) constexpr SanitizerMask SanitizerKind::ID; diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 0e470e03deb09..7f630234a4dae 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1152,9 +1152,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeHandlers.Mask |= MergeKinds; // Zero out TopHotCutoffs for unused sanitizers - for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) - if (!(Sanitizers.Mask & SanitizerMask::bitPosToMask(i))) - TopHotCutoffs[i] = 0; + TopHotCutoffs.clear(Sanitizers.Mask); } static std::string toString(const clang::SanitizerSet &Sanitizers) { From b668bcb8749061ff30f5d70c3500a07ba4157c6b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 16:24:06 -0800 Subject: [PATCH 36/52] use string::empty --- clang/lib/Driver/SanitizerArgs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 7f630234a4dae..3539e74b38cb3 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1332,7 +1332,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, Args.MakeArgString("-fsanitize-merge=" + toString(MergeHandlers))); std::string TopHotCutoffsStr = toString(TopHotCutoffs); - if (TopHotCutoffsStr != "") + if (!TopHotCutoffsStr.empty()) CmdArgs.push_back( Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotCutoffsStr)); From 9321def30ce442be3ff451c72b6048f81910cfa2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 16:24:44 -0800 Subject: [PATCH 37/52] Return SanitizerMaskCutoffs from parseNoSanitizeHotArgs by value --- clang/lib/Driver/SanitizerArgs.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 3539e74b38cb3..82e32362ba976 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -329,13 +329,14 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, options::OPT_fno_sanitize_trap_EQ); } -static void parseNoSanitizeHotArgs(const Driver &D, - const llvm::opt::ArgList &Args, - bool DiagnoseErrors, - SanitizerMaskCutoffs *Cutoffs) { +static SanitizerMaskCutoffs +parseNoSanitizeHotArgs(const Driver &D, const llvm::opt::ArgList &Args, + bool DiagnoseErrors) { + SanitizerMaskCutoffs Cutoffs; for (const auto *Arg : Args) if (Arg->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) - parseArgCutoffs(D, Arg, DiagnoseErrors, *Cutoffs); + parseArgCutoffs(D, Arg, DiagnoseErrors, Cutoffs); + return Cutoffs; } bool SanitizerArgs::needsFuzzerInterceptors() const { @@ -729,7 +730,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeKinds &= Kinds; // Parse -fno-sanitize-top-hot flags - parseNoSanitizeHotArgs(D, Args, DiagnoseErrors, &TopHotCutoffs); + TopHotCutoffs = parseNoSanitizeHotArgs(D, Args, DiagnoseErrors); // Setup ignorelist files. // Add default ignorelist from resource directory for activated sanitizers, From d39638d6eecb6af3cbc01bb6e1f1c783b1c4fed9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 16:48:18 -0800 Subject: [PATCH 38/52] Extract ::set and fix clear --- clang/include/clang/Basic/Sanitizers.h | 2 +- clang/lib/Basic/Sanitizers.cpp | 13 ++++++------- clang/lib/Driver/SanitizerArgs.cpp | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 7dc32cee289fa..705b942718cab 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -158,9 +158,9 @@ class SanitizerMaskCutoffs { std::array cutoffs = {0}; public: - float &operator[](int index) { return cutoffs[index]; } const float &operator[](int index) const { return cutoffs[index]; } + void set(SanitizerMask K, float V); void clear(SanitizerMask K = SanitizerKind::All); }; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 8fab5e28c17ae..54917677c18b5 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -19,12 +19,14 @@ using namespace clang; -void SanitizerMaskCutoffs::clear(SanitizerMask K) { +void SanitizerMaskCutoffs::set(SanitizerMask K, float V) { for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) - if (!(K & SanitizerMask::bitPosToMask(i))) - cutoffs[i] = 0; + if (K & SanitizerMask::bitPosToMask(i)) + cutoffs[i] = V; } +void SanitizerMaskCutoffs::clear(SanitizerMask K) { set(K, 0); } + // Once LLVM switches to C++17, the constexpr variables can be inline and we // won't need this. #define SANITIZER(NAME, ID) constexpr SanitizerMask SanitizerKind::ID; @@ -62,10 +64,7 @@ bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, float C = std::clamp(A, 0.0, 1.0); // 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)) - Cutoffs[i] = C; + Cutoffs.set(expandSanitizerGroups(ParsedKind), C); return true; } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 82e32362ba976..ec20e1102c549 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1153,7 +1153,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeHandlers.Mask |= MergeKinds; // Zero out TopHotCutoffs for unused sanitizers - TopHotCutoffs.clear(Sanitizers.Mask); + TopHotCutoffs.clear(~Sanitizers.Mask); } static std::string toString(const clang::SanitizerSet &Sanitizers) { From 99cfdb265a0a14dc1813f7fda61874f1edd22ce7 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 16:55:21 -0800 Subject: [PATCH 39/52] return float by value --- clang/include/clang/Basic/Sanitizers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 705b942718cab..75e2281bfc47c 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -158,7 +158,7 @@ class SanitizerMaskCutoffs { std::array cutoffs = {0}; public: - const float &operator[](int index) const { return cutoffs[index]; } + float operator[](int index) const { return cutoffs[index]; } void set(SanitizerMask K, float V); void clear(SanitizerMask K = SanitizerKind::All); From 58c752b05589c11443e740e9830b0c20b4aa97de Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 18:10:01 -0800 Subject: [PATCH 40/52] Updates Lazy vector Epsilon and std::optional --- clang/include/clang/Basic/Sanitizers.h | 4 ++-- clang/lib/Basic/Sanitizers.cpp | 24 +++++++++++++++++++----- clang/lib/Driver/SanitizerArgs.cpp | 13 +++---------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index 75e2281bfc47c..ee4e567aeb286 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -155,10 +155,10 @@ struct SanitizerKind { }; // SanitizerKind class SanitizerMaskCutoffs { - std::array cutoffs = {0}; + std::vector Cutoffs; public: - float operator[](int index) const { return cutoffs[index]; } + std::optional operator[](unsigned Kind) const; void set(SanitizerMask K, float V); void clear(SanitizerMask K = SanitizerKind::All); diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 54917677c18b5..e1c74d00d3358 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -16,13 +16,27 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/MathExtras.h" #include +#include using namespace clang; +static const double SanitizerMaskCutoffsEps = 0.000000001f; + void SanitizerMaskCutoffs::set(SanitizerMask K, float V) { + if (V < SanitizerMaskCutoffsEps && Cutoffs.empty()) + return; for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) - if (K & SanitizerMask::bitPosToMask(i)) - cutoffs[i] = V; + if (K & SanitizerMask::bitPosToMask(i)) { + Cutoffs.resize(SanitizerKind::SO_Count); + Cutoffs[i] = V; + } +} + +std::optional SanitizerMaskCutoffs::operator[](unsigned Kind) const { + if (Cutoffs.empty() || Cutoffs[Kind] < SanitizerMaskCutoffsEps) + return std::nullopt; + + return Cutoffs[Kind]; } void SanitizerMaskCutoffs::clear(SanitizerMask K) { set(K, 0); } @@ -79,9 +93,9 @@ void clang::serializeSanitizerSet(SanitizerSet Set, void clang::serializeSanitizerMaskCutoffs( const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl &Values) { #define SANITIZER(NAME, ID) \ - if (Cutoffs[SanitizerKind::SO_##ID]) \ - Values.push_back(std::string(NAME "=") + \ - std::to_string(Cutoffs[SanitizerKind::SO_##ID])); + if (auto C = Cutoffs[SanitizerKind::SO_##ID]) { \ + Values.push_back(std::string(NAME "=") + std::to_string(*C)); \ + } #include "clang/Basic/Sanitizers.def" } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index ec20e1102c549..e5b8b42ab3b96 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1169,16 +1169,9 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) { } static std::string toString(const clang::SanitizerMaskCutoffs &Cutoffs) { - std::string Res; -#define SANITIZER(NAME, ID) \ - if (Cutoffs[SanitizerKind::SO_##ID]) { \ - if (!Res.empty()) \ - Res += ","; \ - Res += std::string(NAME) + "=" + \ - std::to_string(Cutoffs[SanitizerKind::SO_##ID]); \ - } -#include "clang/Basic/Sanitizers.def" - return Res; + llvm::SmallVector Res; + serializeSanitizerMaskCutoffs(Cutoffs, Res); + return llvm::join(Res, ","); } static void addSpecialCaseListOpt(const llvm::opt::ArgList &Args, From f27eb850b558be664a9d9b6c52d08215effcecb6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 18:10:49 -0800 Subject: [PATCH 41/52] Include --- clang/lib/Driver/SanitizerArgs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index e5b8b42ab3b96..34416d2f52888 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -10,6 +10,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Path.h" From 1aed6085ffcd467460f6079602444655a19bf63d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 18:12:34 -0800 Subject: [PATCH 42/52] Fix clamp for double --- clang/lib/Basic/Sanitizers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index e1c74d00d3358..244859e75310e 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -75,10 +75,10 @@ bool clang::parseSanitizerWeightedValue(StringRef Value, bool AllowGroups, double A; if (W.getAsDouble(A)) return false; - float C = std::clamp(A, 0.0, 1.0); + A = std::clamp(A, 0.0, 1.0); // AllowGroups is already taken into account for ParsedKind, // hence we unconditionally expandSanitizerGroups. - Cutoffs.set(expandSanitizerGroups(ParsedKind), C); + Cutoffs.set(expandSanitizerGroups(ParsedKind), A); return true; } From b82e48d83663afead2b5b0ed4c5f2fb2b32683ad Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 7 Jan 2025 18:50:47 -0800 Subject: [PATCH 43/52] Format --- clang/lib/Basic/Sanitizers.cpp | 8 +++++++- clang/test/Driver/fsanitize.c | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 244859e75310e..e5537942d9355 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -11,10 +11,12 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Sanitizers.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -94,7 +96,11 @@ void clang::serializeSanitizerMaskCutoffs( const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl &Values) { #define SANITIZER(NAME, ID) \ if (auto C = Cutoffs[SanitizerKind::SO_##ID]) { \ - Values.push_back(std::string(NAME "=") + std::to_string(*C)); \ + llvm::APFloat F(*C); \ + std::string Str; \ + llvm::raw_string_ostream OS(Str); \ + OS << NAME "=" << F; \ + Values.emplace_back(std::move(Str)); \ } #include "clang/Basic/Sanitizers.def" } diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 8fab84dad1270..c4f965ddaac1a 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1173,11 +1173,11 @@ // Enable undefined, then cancel out integer using a cutoff of 0.0, then re-enable signed-integer-overflow // 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-TOP-HOT4 -// CHECK-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}"}} +// CHECK-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.49|0.7|0.69)([0-9]*),?){16}"}} // Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize=integer checks. // RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 -// CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.4(0*),?){4}"}} +// CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=(0.4|0.39)([0-9]*),?){4}"}} // No-op: it's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 From a8e79cefa3b27550673ad0abaeed4cbd7094e760 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Wed, 8 Jan 2025 07:19:23 +0000 Subject: [PATCH 44/52] Claim matched arguments --- clang/lib/Driver/SanitizerArgs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 34416d2f52888..6f37ca1136d5f 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -335,8 +335,11 @@ parseNoSanitizeHotArgs(const Driver &D, const llvm::opt::ArgList &Args, bool DiagnoseErrors) { SanitizerMaskCutoffs Cutoffs; for (const auto *Arg : Args) - if (Arg->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) + if (Arg->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) { + Arg->claim(); parseArgCutoffs(D, Arg, DiagnoseErrors, Cutoffs); + } + return Cutoffs; } From d3fa04dbe6622878e7747f21ad036799e0af5e5a Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Wed, 8 Jan 2025 07:19:43 +0000 Subject: [PATCH 45/52] Change test to use -Werror and not check for error messages, per Fangrui's feedback --- clang/test/Driver/fsanitize.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index c4f965ddaac1a..49cd432aa18d8 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1159,30 +1159,29 @@ // * Test -fno-sanitize-top-hot * // -fno-sanitize-top-hot=undefined=0.5 -// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT1 +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT1 // CHECK-TOP-HOT1: "-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}"}} // No-op: no sanitizers are specified -// RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT2 +// RUN: %clang -Werror --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT2 // CHECK-TOP-HOT2-NOT: "-fsanitize" // CHECK-TOP-HOT2-NOT: "-fno-sanitize-top-hot" // Enable undefined, then cancel out integer using a cutoff of 0.0 -// 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-TOP-HOT3 +// RUN: %clang -Werror --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-TOP-HOT3 // CHECK-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}"}} // Enable undefined, then cancel out integer using a cutoff of 0.0, then re-enable signed-integer-overflow -// 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-TOP-HOT4 +// RUN: %clang -Werror --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-TOP-HOT4 // CHECK-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.49|0.7|0.69)([0-9]*),?){16}"}} // Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize=integer checks. -// RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 // CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=(0.4|0.39)([0-9]*),?){4}"}} // No-op: it's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. -// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 // CHECK-TOP-HOT6: "-fsanitize={{((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),?){19}"}} -// CHECK-TOP-HOT6-NOT: unsupported argument // CHECK-TOP-HOT6-NOT: "-fno-sanitize-top-hot" // Invalid: bad sanitizer @@ -1206,6 +1205,5 @@ // CHECK-TOP-HOT11: unsupported argument 'undefined=' to option '-fno-sanitize-top-hot=' // No-op: -fno-sanitize-top= without parameters is unusual but valid -// RUN: %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT12 -// CHECK-TOP-HOT12-NOT: unsupported argument +// RUN: %clang -Werror --target=x86_64-linux-gnu -fno-sanitize-top-hot= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT12 // CHECK-TOP-HOT12-NOT: "-fno-sanitize-top-hot" From 55f42e7c08ec00b93e4cc4d69af41b217fd37068 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Jan 2025 10:36:09 -0800 Subject: [PATCH 46/52] Format --- clang/lib/Basic/Sanitizers.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index e5537942d9355..834472e01786c 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Sanitizers.h" -#include "llvm/ADT/APFloat.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include @@ -96,10 +96,9 @@ void clang::serializeSanitizerMaskCutoffs( const SanitizerMaskCutoffs &Cutoffs, SmallVectorImpl &Values) { #define SANITIZER(NAME, ID) \ if (auto C = Cutoffs[SanitizerKind::SO_##ID]) { \ - llvm::APFloat F(*C); \ std::string Str; \ llvm::raw_string_ostream OS(Str); \ - OS << NAME "=" << F; \ + OS << NAME "=" << llvm::format("%.8f", *C); \ Values.emplace_back(std::move(Str)); \ } #include "clang/Basic/Sanitizers.def" From d8a3696acb940d432fb61236fd9d6da00a4314b2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Jan 2025 12:55:45 -0800 Subject: [PATCH 47/52] This reverts part of commit b82e48d83663afead2b5b0ed4c5f2fb2b32683ad. And fix V type in ::set. --- clang/include/clang/Basic/Sanitizers.h | 2 +- clang/lib/Basic/Sanitizers.cpp | 4 ++-- clang/test/Driver/fsanitize.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index ee4e567aeb286..2ff1acb772094 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -160,7 +160,7 @@ class SanitizerMaskCutoffs { public: std::optional operator[](unsigned Kind) const; - void set(SanitizerMask K, float V); + void set(SanitizerMask K, double V); void clear(SanitizerMask K = SanitizerKind::All); }; diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 834472e01786c..ebe9fc780f7db 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -24,7 +24,7 @@ using namespace clang; static const double SanitizerMaskCutoffsEps = 0.000000001f; -void SanitizerMaskCutoffs::set(SanitizerMask K, float V) { +void SanitizerMaskCutoffs::set(SanitizerMask K, double V) { if (V < SanitizerMaskCutoffsEps && Cutoffs.empty()) return; for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) @@ -38,7 +38,7 @@ std::optional SanitizerMaskCutoffs::operator[](unsigned Kind) const { if (Cutoffs.empty() || Cutoffs[Kind] < SanitizerMaskCutoffsEps) return std::nullopt; - return Cutoffs[Kind]; +return Cutoffs[Kind]; } void SanitizerMaskCutoffs::clear(SanitizerMask K) { set(K, 0); } diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 49cd432aa18d8..2c7db003ad7fb 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1173,11 +1173,11 @@ // Enable undefined, then cancel out integer using a cutoff of 0.0, then re-enable signed-integer-overflow // RUN: %clang -Werror --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-TOP-HOT4 -// CHECK-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.49|0.7|0.69)([0-9]*),?){16}"}} +// CHECK-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.[57]0*,?){16}"}} // Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize=integer checks. // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 -// CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=(0.4|0.39)([0-9]*),?){4}"}} +// CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.40*,?){4}"}} // No-op: it's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 From 17ecca4fe4f92d18bd0b53e70dea373da8dd875f Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Jan 2025 14:10:29 -0800 Subject: [PATCH 48/52] rtrim('0') --- clang/lib/Basic/Sanitizers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index ebe9fc780f7db..4a29d519f110a 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -99,7 +99,7 @@ void clang::serializeSanitizerMaskCutoffs( std::string Str; \ llvm::raw_string_ostream OS(Str); \ OS << NAME "=" << llvm::format("%.8f", *C); \ - Values.emplace_back(std::move(Str)); \ + Values.emplace_back(StringRef(Str).rtrim('0')); \ } #include "clang/Basic/Sanitizers.def" } From b43d513eb48988ac0252dbc14264e23b5a80a321 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Jan 2025 14:30:41 -0800 Subject: [PATCH 49/52] clang-format --- clang/lib/Basic/Sanitizers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 4a29d519f110a..0f8a86c31915d 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -38,7 +38,7 @@ std::optional SanitizerMaskCutoffs::operator[](unsigned Kind) const { if (Cutoffs.empty() || Cutoffs[Kind] < SanitizerMaskCutoffsEps) return std::nullopt; -return Cutoffs[Kind]; + return Cutoffs[Kind]; } void SanitizerMaskCutoffs::clear(SanitizerMask K) { set(K, 0); } From caa4964cf6399a9a8e23016ecb0c45617dad460a Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Jan 2025 20:50:10 +0000 Subject: [PATCH 50/52] Rename -fno-sanitize-top-hot to -fsanitize-skip-hot-cutoff Rename a few internal variables as well --- clang/include/clang/Basic/CodeGenOptions.h | 2 +- clang/include/clang/Driver/Options.td | 4 +- clang/include/clang/Driver/SanitizerArgs.h | 2 +- clang/lib/Driver/SanitizerArgs.cpp | 18 +++---- clang/lib/Frontend/CompilerInvocation.cpp | 12 ++--- clang/test/Driver/fsanitize.c | 58 +++++++++++----------- 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 889ebb8242574..a62980c374e64 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -387,7 +387,7 @@ class CodeGenOptions : public CodeGenOptionsBase { /// Set of thresholds in a range [0.0, 1.0]: the top hottest code responsible /// for the given fraction of PGO counters will be excluded from sanitization /// (0.0 [default] to skip none, 1.0 to skip all). - SanitizerMaskCutoffs NoSanitizeTopHotCutoffs; + SanitizerMaskCutoffs SanitizeSkipHotCutoffs; /// List of backend command-line options for -fembed-bitcode. std::vector CmdArgs; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4db17baa9c92f..4f4b7caa83033 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2649,8 +2649,8 @@ 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, "0", "int">; -def fno_sanitize_top_hot_EQ - : CommaJoined<["-"], "fno-sanitize-top-hot=">, +def fsanitize_skip_hot_cutoff_EQ + : CommaJoined<["-"], "fsanitize-skip-hot-cutoff=">, Group, HelpText< "Exclude sanitization for the top hottest code responsible for " diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 6e46922800a5f..a54995e2b153b 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -26,7 +26,7 @@ class SanitizerArgs { SanitizerSet RecoverableSanitizers; SanitizerSet TrapSanitizers; SanitizerSet MergeHandlers; - SanitizerMaskCutoffs TopHotCutoffs; + SanitizerMaskCutoffs SkipHotCutoffs; std::vector UserIgnorelistFiles; std::vector SystemIgnorelistFiles; diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 6f37ca1136d5f..582ccd06e4d79 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -331,11 +331,11 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, } static SanitizerMaskCutoffs -parseNoSanitizeHotArgs(const Driver &D, const llvm::opt::ArgList &Args, +parseSanitizeSkipHotCutoffArgs(const Driver &D, const llvm::opt::ArgList &Args, bool DiagnoseErrors) { SanitizerMaskCutoffs Cutoffs; for (const auto *Arg : Args) - if (Arg->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ)) { + if (Arg->getOption().matches(options::OPT_fsanitize_skip_hot_cutoff_EQ)) { Arg->claim(); parseArgCutoffs(D, Arg, DiagnoseErrors, Cutoffs); } @@ -734,7 +734,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeKinds &= Kinds; // Parse -fno-sanitize-top-hot flags - TopHotCutoffs = parseNoSanitizeHotArgs(D, Args, DiagnoseErrors); + SkipHotCutoffs = parseSanitizeSkipHotCutoffArgs(D, Args, DiagnoseErrors); // Setup ignorelist files. // Add default ignorelist from resource directory for activated sanitizers, @@ -1156,8 +1156,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MergeHandlers.Mask |= MergeKinds; - // Zero out TopHotCutoffs for unused sanitizers - TopHotCutoffs.clear(~Sanitizers.Mask); + // Zero out SkipHotCutoffs for unused sanitizers + SkipHotCutoffs.clear(~Sanitizers.Mask); } static std::string toString(const clang::SanitizerSet &Sanitizers) { @@ -1329,10 +1329,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back( Args.MakeArgString("-fsanitize-merge=" + toString(MergeHandlers))); - std::string TopHotCutoffsStr = toString(TopHotCutoffs); - if (!TopHotCutoffsStr.empty()) + std::string SkipHotCutoffsStr = toString(SkipHotCutoffs); + if (!SkipHotCutoffsStr.empty()) CmdArgs.push_back( - Args.MakeArgString("-fno-sanitize-top-hot=" + TopHotCutoffsStr)); + Args.MakeArgString("-fsanitize-skip-hot-cutoff=" + SkipHotCutoffsStr)); addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-ignorelist=", UserIgnorelistFiles); @@ -1533,7 +1533,7 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, void parseArgCutoffs(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors, SanitizerMaskCutoffs &Cutoffs) { - assert(A->getOption().matches(options::OPT_fno_sanitize_top_hot_EQ) && + assert(A->getOption().matches(options::OPT_fsanitize_skip_hot_cutoff_EQ) && "Invalid argument in parseArgCutoffs!"); for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2b1754e565651..1cc4a86ea534c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1809,9 +1809,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, GenerateArg(Consumer, OPT_fsanitize_merge_handlers_EQ, Sanitizer); SmallVector Values; - serializeSanitizerMaskCutoffs(Opts.NoSanitizeTopHotCutoffs, Values); + serializeSanitizerMaskCutoffs(Opts.SanitizeSkipHotCutoffs, Values); for (std::string Sanitizer : Values) - GenerateArg(Consumer, OPT_fno_sanitize_top_hot_EQ, Sanitizer); + GenerateArg(Consumer, OPT_fsanitize_skip_hot_cutoff_EQ, Sanitizer); if (!Opts.EmitVersionIdentMetadata) GenerateArg(Consumer, OPT_Qn); @@ -2294,10 +2294,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Args.getAllArgValues(OPT_fsanitize_merge_handlers_EQ), Diags, Opts.SanitizeMergeHandlers); - // Parse -fno-sanitize-top-hot= arguments. - Opts.NoSanitizeTopHotCutoffs = parseSanitizerWeightedKinds( - "-fno-sanitize-top-hot=", - Args.getAllArgValues(OPT_fno_sanitize_top_hot_EQ), Diags); + // Parse -fsanitize-skip-hot-cutoff= arguments. + Opts.SanitizeSkipHotCutoffs = parseSanitizerWeightedKinds( + "-fsanitize-skip-hot-cutoff=", + Args.getAllArgValues(OPT_fsanitize_skip_hot_cutoff_EQ), Diags); Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 2c7db003ad7fb..1d3caec748d77 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -1156,54 +1156,54 @@ // CHECK-REALTIME-UBSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=undefined' -// * Test -fno-sanitize-top-hot * +// * Test -fsanitize-skip-hot-cutoff * -// -fno-sanitize-top-hot=undefined=0.5 -// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT1 -// CHECK-TOP-HOT1: "-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}"}} +// -fsanitize-skip-hot-cutoff=undefined=0.5 +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-skip-hot-cutoff=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF1 +// CHECK-SKIP-HOT-CUTOFF1: "-fsanitize-skip-hot-cutoff={{((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}"}} // No-op: no sanitizers are specified -// RUN: %clang -Werror --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT2 -// CHECK-TOP-HOT2-NOT: "-fsanitize" -// CHECK-TOP-HOT2-NOT: "-fno-sanitize-top-hot" +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff=undefined=0.5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF2 +// CHECK-SKIP-HOT-CUTOFF2-NOT: "-fsanitize" +// CHECK-SKIP-HOT-CUTOFF2-NOT: "-fsanitize-skip-hot-cutoff" // Enable undefined, then cancel out integer using a cutoff of 0.0 -// RUN: %clang -Werror --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-TOP-HOT3 -// CHECK-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 -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-skip-hot-cutoff=undefined=0.5,integer=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF3 +// CHECK-SKIP-HOT-CUTOFF3: "-fsanitize-skip-hot-cutoff={{((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}"}} // Enable undefined, then cancel out integer using a cutoff of 0.0, then re-enable signed-integer-overflow -// RUN: %clang -Werror --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-TOP-HOT4 -// CHECK-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.[57]0*,?){16}"}} +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-skip-hot-cutoff=undefined=0.5,integer=0.0,signed-integer-overflow=0.7 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF4 +// CHECK-SKIP-HOT-CUTOFF4: "-fsanitize-skip-hot-cutoff={{((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.[57]0*,?){16}"}} -// Check that -fno-sanitize-top-hot=undefined=0.4 does not widen the set of -fsanitize=integer checks. -// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=integer -fno-sanitize-top-hot=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT5 -// CHECK-TOP-HOT5: "-fno-sanitize-top-hot={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.40*,?){4}"}} +// Check that -fsanitize-skip-hot-cutoff=undefined=0.4 does not widen the set of -fsanitize=integer checks. +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=integer -fsanitize-skip-hot-cutoff=undefined=0.4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF5 +// CHECK-SKIP-HOT-CUTOFF5: "-fsanitize-skip-hot-cutoff={{((integer-divide-by-zero|shift-base|shift-exponent|signed-integer-overflow)=0.40*,?){4}"}} // No-op: it's allowed for the user to specify a cutoff of 0.0, though the argument is not passed along by the driver. -// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fno-sanitize-top-hot=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT6 -// CHECK-TOP-HOT6: "-fsanitize={{((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),?){19}"}} -// CHECK-TOP-HOT6-NOT: "-fno-sanitize-top-hot" +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-skip-hot-cutoff=undefined=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF6 +// CHECK-SKIP-HOT-CUTOFF6: "-fsanitize={{((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),?){19}"}} +// CHECK-SKIP-HOT-CUTOFF6-NOT: "-fsanitize-skip-hot-cutoff" // Invalid: bad sanitizer -// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=pot=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT7 -// CHECK-TOP-HOT7: unsupported argument 'pot=0.0' to option '-fno-sanitize-top-hot=' +// RUN: not %clang --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff=pot=0.0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF7 +// CHECK-SKIP-HOT-CUTOFF7: unsupported argument 'pot=0.0' to option '-fsanitize-skip-hot-cutoff=' // Invalid: bad cutoff -// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined=xyzzy %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT8 -// CHECK-TOP-HOT8: unsupported argument 'undefined=xyzzy' to option '-fno-sanitize-top-hot=' +// RUN: not %clang --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff=undefined=xyzzy %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF8 +// CHECK-SKIP-HOT-CUTOFF8: unsupported argument 'undefined=xyzzy' to option '-fsanitize-skip-hot-cutoff=' // Invalid: -fno-sanitize-top without parameters -// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT9 -// CHECK-TOP-HOT9: unknown argument: '-fno-sanitize-top-hot' +// RUN: not %clang --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF9 +// CHECK-SKIP-HOT-CUTOFF9: unknown argument: '-fsanitize-skip-hot-cutoff' // Invalid: -fno-sanitize-top=undefined without cutoff -// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT10 -// CHECK-TOP-HOT10: unsupported argument 'undefined' to option '-fno-sanitize-top-hot=' +// RUN: not %clang --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF10 +// CHECK-SKIP-HOT-CUTOFF10: unsupported argument 'undefined' to option '-fsanitize-skip-hot-cutoff=' // Invalid: -fno-sanitize-top=undefined= without cutoff -// RUN: not %clang --target=x86_64-linux-gnu -fno-sanitize-top-hot=undefined= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT11 -// CHECK-TOP-HOT11: unsupported argument 'undefined=' to option '-fno-sanitize-top-hot=' +// RUN: not %clang --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff=undefined= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF11 +// CHECK-SKIP-HOT-CUTOFF11: unsupported argument 'undefined=' to option '-fsanitize-skip-hot-cutoff=' // No-op: -fno-sanitize-top= without parameters is unusual but valid -// RUN: %clang -Werror --target=x86_64-linux-gnu -fno-sanitize-top-hot= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TOP-HOT12 -// CHECK-TOP-HOT12-NOT: "-fno-sanitize-top-hot" +// RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize-skip-hot-cutoff= %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF12 +// CHECK-SKIP-HOT-CUTOFF12-NOT: "-fsanitize-skip-hot-cutoff" From 98379123984dfeb10eb4a7faf321b87b6a8ab4cc Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 9 Jan 2025 21:36:39 +0000 Subject: [PATCH 51/52] clang-format --- clang/lib/Driver/SanitizerArgs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 582ccd06e4d79..a0d6919c6dc8d 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -332,7 +332,7 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, static SanitizerMaskCutoffs parseSanitizeSkipHotCutoffArgs(const Driver &D, const llvm::opt::ArgList &Args, - bool DiagnoseErrors) { + bool DiagnoseErrors) { SanitizerMaskCutoffs Cutoffs; for (const auto *Arg : Args) if (Arg->getOption().matches(options::OPT_fsanitize_skip_hot_cutoff_EQ)) { From 10e0a5512ed09ce5972668f457fe202d885f2e77 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Fri, 10 Jan 2025 05:50:59 +0000 Subject: [PATCH 52/52] ++clang --- clang/lib/Basic/Sanitizers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp index 0f8a86c31915d..5b9b88d032702 100644 --- a/clang/lib/Basic/Sanitizers.cpp +++ b/clang/lib/Basic/Sanitizers.cpp @@ -27,7 +27,7 @@ static const double SanitizerMaskCutoffsEps = 0.000000001f; void SanitizerMaskCutoffs::set(SanitizerMask K, double V) { if (V < SanitizerMaskCutoffsEps && Cutoffs.empty()) return; - for (unsigned int i = 0; i < SanitizerKind::SO_Count; i++) + for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) if (K & SanitizerMask::bitPosToMask(i)) { Cutoffs.resize(SanitizerKind::SO_Count); Cutoffs[i] = V;