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