1010#include " clang/Driver/Driver.h"
1111#include " clang/Driver/Options.h"
1212#include " clang/Driver/ToolChain.h"
13+ #include " llvm/ADT/SmallVector.h"
1314#include " llvm/ADT/StringRef.h"
1415#include " llvm/ADT/StringSwitch.h"
1516#include " llvm/Support/Path.h"
@@ -113,6 +114,12 @@ enum BinaryMetadataFeature {
113114static SanitizerMask parseArgValues (const Driver &D, const llvm::opt::Arg *A,
114115 bool DiagnoseErrors);
115116
117+ // / Parse a -fsanitize=<sanitizer1>=<value1>... or -fno-sanitize= argument's
118+ // / values, diagnosing any invalid components.
119+ // / Cutoffs are stored in the passed parameter.
120+ static void parseArgCutoffs (const Driver &D, const llvm::opt::Arg *A,
121+ bool DiagnoseErrors, SanitizerMaskCutoffs &Cutoffs);
122+
116123// / Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
117124// / components. Returns OR of members of \c CoverageFeature enumeration.
118125static int parseCoverageFeatures (const Driver &D, const llvm::opt::Arg *A,
@@ -323,6 +330,19 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
323330 options::OPT_fno_sanitize_trap_EQ);
324331}
325332
333+ static SanitizerMaskCutoffs
334+ parseSanitizeSkipHotCutoffArgs (const Driver &D, const llvm::opt::ArgList &Args,
335+ bool DiagnoseErrors) {
336+ SanitizerMaskCutoffs Cutoffs;
337+ for (const auto *Arg : Args)
338+ if (Arg->getOption ().matches (options::OPT_fsanitize_skip_hot_cutoff_EQ)) {
339+ Arg->claim ();
340+ parseArgCutoffs (D, Arg, DiagnoseErrors, Cutoffs);
341+ }
342+
343+ return Cutoffs;
344+ }
345+
326346bool SanitizerArgs::needsFuzzerInterceptors () const {
327347 return needsFuzzer () && !needsAsanRt () && !needsTsanRt () && !needsMsanRt ();
328348}
@@ -713,6 +733,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
713733 options::OPT_fno_sanitize_merge_handlers_EQ);
714734 MergeKinds &= Kinds;
715735
736+ // Parse -fno-sanitize-top-hot flags
737+ SkipHotCutoffs = parseSanitizeSkipHotCutoffArgs (D, Args, DiagnoseErrors);
738+
716739 // Setup ignorelist files.
717740 // Add default ignorelist from resource directory for activated sanitizers,
718741 // and validate special case lists format.
@@ -1132,6 +1155,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
11321155 " Overlap between recoverable and trapping sanitizers" );
11331156
11341157 MergeHandlers.Mask |= MergeKinds;
1158+
1159+ // Zero out SkipHotCutoffs for unused sanitizers
1160+ SkipHotCutoffs.clear (~Sanitizers.Mask );
11351161}
11361162
11371163static std::string toString (const clang::SanitizerSet &Sanitizers) {
@@ -1146,6 +1172,12 @@ static std::string toString(const clang::SanitizerSet &Sanitizers) {
11461172 return Res;
11471173}
11481174
1175+ static std::string toString (const clang::SanitizerMaskCutoffs &Cutoffs) {
1176+ llvm::SmallVector<std::string, 4 > Res;
1177+ serializeSanitizerMaskCutoffs (Cutoffs, Res);
1178+ return llvm::join (Res, " ," );
1179+ }
1180+
11491181static void addSpecialCaseListOpt (const llvm::opt::ArgList &Args,
11501182 llvm::opt::ArgStringList &CmdArgs,
11511183 const char *SCLOptFlag,
@@ -1297,6 +1329,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
12971329 CmdArgs.push_back (
12981330 Args.MakeArgString (" -fsanitize-merge=" + toString (MergeHandlers)));
12991331
1332+ std::string SkipHotCutoffsStr = toString (SkipHotCutoffs);
1333+ if (!SkipHotCutoffsStr.empty ())
1334+ CmdArgs.push_back (
1335+ Args.MakeArgString (" -fsanitize-skip-hot-cutoff=" + SkipHotCutoffsStr));
1336+
13001337 addSpecialCaseListOpt (Args, CmdArgs,
13011338 " -fsanitize-ignorelist=" , UserIgnorelistFiles);
13021339 addSpecialCaseListOpt (Args, CmdArgs,
@@ -1494,6 +1531,22 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
14941531 return Kinds;
14951532}
14961533
1534+ void parseArgCutoffs (const Driver &D, const llvm::opt::Arg *A,
1535+ bool DiagnoseErrors, SanitizerMaskCutoffs &Cutoffs) {
1536+ assert (A->getOption ().matches (options::OPT_fsanitize_skip_hot_cutoff_EQ) &&
1537+ " Invalid argument in parseArgCutoffs!" );
1538+ for (int i = 0 , n = A->getNumValues (); i != n; ++i) {
1539+ const char *Value = A->getValue (i);
1540+
1541+ // We don't check the value of Cutoffs[i]: it's legal to specify
1542+ // a cutoff of 0.
1543+ if (!parseSanitizerWeightedValue (Value, /* AllowGroups=*/ true , Cutoffs) &&
1544+ DiagnoseErrors)
1545+ D.Diag (clang::diag::err_drv_unsupported_option_argument)
1546+ << A->getSpelling () << Value;
1547+ }
1548+ }
1549+
14971550static int parseOverflowPatternExclusionValues (const Driver &D,
14981551 const llvm::opt::Arg *A,
14991552 bool DiagnoseErrors) {
0 commit comments