16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/Support/SpecialCaseList.h"
23 using namespace clang;
24 using namespace clang::SanitizerKind;
25 using namespace clang::driver;
26 using namespace llvm::opt;
40 (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
42 CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
70 const llvm::opt::ArgList &Args,
85 std::string &BLPath) {
86 const char *BlacklistFile =
nullptr;
88 BlacklistFile =
"asan_blacklist.txt";
89 else if (Kinds & Memory)
90 BlacklistFile =
"msan_blacklist.txt";
91 else if (Kinds & Thread)
92 BlacklistFile =
"tsan_blacklist.txt";
93 else if (Kinds & DataFlow)
94 BlacklistFile =
"dfsan_abilist.txt";
96 BlacklistFile =
"cfi_blacklist.txt";
100 llvm::sys::path::append(Path, BlacklistFile);
110 #define SANITIZER(NAME, ID)
111 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
112 if (Kinds & SanitizerKind::ID) \
113 Kinds |= SanitizerKind::ID##Group;
114 #include "clang/Basic/Sanitizers.def"
119 const llvm::opt::ArgList &Args) {
126 for (ArgList::const_reverse_iterator
I = Args.rbegin(),
E = Args.rend();
128 const auto *Arg = *
I;
129 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
133 if (
SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
135 S.
Mask = InvalidValues;
136 D.
Diag(diag::err_drv_unsupported_option_argument) <<
"-fsanitize-trap"
140 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
143 }
else if (Arg->getOption().matches(
144 options::OPT_fsanitize_undefined_trap_on_error)) {
148 }
else if (Arg->getOption().matches(
149 options::OPT_fno_sanitize_undefined_trap_on_error)) {
158 return TrappingKinds;
161 bool SanitizerArgs::needsUbsanRt()
const {
162 return ((Sanitizers.Mask &
NeedsUbsanRt & ~TrapSanitizers.Mask) ||
164 !Sanitizers.has(Address) && !Sanitizers.has(Memory) &&
165 !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) && !CfiCrossDso;
168 bool SanitizerArgs::needsCfiRt()
const {
169 return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
172 bool SanitizerArgs::needsCfiDiagRt()
const {
173 return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
176 bool SanitizerArgs::requiresPIE()
const {
180 bool SanitizerArgs::needsUnwindTables()
const {
185 const llvm::opt::ArgList &Args) {
204 for (ArgList::const_reverse_iterator
I = Args.rbegin(),
E = Args.rend();
206 const auto *Arg = *
I;
207 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
218 Add & InvalidTrappingKinds & ~DiagnosedKinds) {
220 D.
Diag(diag::err_drv_argument_not_allowed_with)
221 << Desc <<
"-fsanitize-trap=undefined";
222 DiagnosedKinds |= KindsToDiagnose;
224 Add &= ~InvalidTrappingKinds;
225 if (
SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
227 D.
Diag(diag::err_drv_unsupported_opt_for_target)
229 DiagnosedKinds |= KindsToDiagnose;
237 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
238 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
239 if (RTTIMode == ToolChain::RM_DisabledImplicitly)
242 D.
Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
244 const llvm::opt::Arg *NoRTTIArg = TC.
getRTTIArg();
246 "RTTI disabled explicitly but we have no argument!");
247 D.
Diag(diag::err_drv_argument_not_allowed_with)
248 <<
"-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
260 Add &= ~InvalidTrappingKinds;
264 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
276 if ((Kinds & Vptr) &&
277 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
278 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
284 D.
Diag(diag::err_drv_argument_only_allowed_with)
292 if (~Supported & Vptr) {
297 KindsToDiagnose &= ~CFI;
298 if (KindsToDiagnose) {
300 S.
Mask = KindsToDiagnose;
301 D.
Diag(diag::err_drv_unsupported_opt_for_target)
303 Kinds &= ~KindsToDiagnose;
308 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
309 std::make_pair(Address, Thread), std::make_pair(Address, Memory),
310 std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
311 std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
312 std::make_pair(KernelAddress, Leak),
313 std::make_pair(KernelAddress, Thread),
314 std::make_pair(KernelAddress, Memory),
315 std::make_pair(Efficiency, Address),
316 std::make_pair(Efficiency, Leak),
317 std::make_pair(Efficiency, Thread),
318 std::make_pair(Efficiency, Memory),
319 std::make_pair(Efficiency, KernelAddress)};
320 for (
auto G : IncompatibleGroups) {
324 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
327 Kinds &= ~Incompatible;
339 for (
const auto *Arg : Args) {
340 const char *DeprecatedReplacement =
nullptr;
341 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
342 DeprecatedReplacement =
343 "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all";
346 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
347 DeprecatedReplacement =
"-fno-sanitize-recover=undefined,integer' or "
348 "'-fno-sanitize-recover=all";
351 }
else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
358 SetToDiagnose.
Mask |= KindsToDiagnose;
359 D.
Diag(diag::err_drv_unsupported_option_argument)
360 << Arg->getOption().getName() <<
toString(SetToDiagnose);
361 DiagnosedUnrecoverableKinds |= KindsToDiagnose;
365 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
369 if (DeprecatedReplacement) {
370 D.
Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
371 << DeprecatedReplacement;
374 RecoverableKinds &= Kinds;
377 TrappingKinds &= Kinds;
384 BlacklistFiles.push_back(BLPath);
387 for (
const auto *Arg : Args) {
388 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
390 std::string BLPath = Arg->getValue();
391 if (llvm::sys::fs::exists(BLPath)) {
392 BlacklistFiles.push_back(BLPath);
393 ExtraDeps.push_back(BLPath);
395 D.
Diag(clang::diag::err_drv_no_such_file) << BLPath;
397 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
399 BlacklistFiles.clear();
406 std::unique_ptr<llvm::SpecialCaseList> SCL(
409 D.
Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
413 if (AllAddedKinds & Memory) {
415 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
416 options::OPT_fsanitize_memory_track_origins,
417 options::OPT_fno_sanitize_memory_track_origins)) {
418 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
419 MsanTrackOrigins = 2;
420 }
else if (A->getOption().matches(
421 options::OPT_fno_sanitize_memory_track_origins)) {
422 MsanTrackOrigins = 0;
424 StringRef
S = A->getValue();
425 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
426 MsanTrackOrigins > 2) {
427 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) <<
S;
432 Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor);
433 NeedPIE |= !(TC.
getTriple().isOSLinux() &&
434 TC.
getTriple().getArch() == llvm::Triple::x86_64);
437 if (AllAddedKinds & CFI) {
438 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
439 options::OPT_fno_sanitize_cfi_cross_dso,
false);
442 NeedPIE |= CfiCrossDso;
445 Stats = Args.hasFlag(options::OPT_fsanitize_stats,
446 options::OPT_fno_sanitize_stats,
false);
450 for (
const auto *Arg : Args) {
451 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
452 int LegacySanitizeCoverage;
453 if (Arg->getNumValues() == 1 &&
454 !StringRef(Arg->getValue(0))
455 .getAsInteger(0, LegacySanitizeCoverage) &&
456 LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
457 switch (LegacySanitizeCoverage) {
459 CoverageFeatures = 0;
463 D.
Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
464 <<
"-fsanitize-coverage=func";
468 D.
Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
469 <<
"-fsanitize-coverage=bb";
473 D.
Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
474 <<
"-fsanitize-coverage=edge";
478 D.
Diag(diag::warn_drv_deprecated_arg)
479 << Arg->getAsString(Args)
480 <<
"-fsanitize-coverage=edge,indirect-calls";
493 CoverageFeatures = 0;
495 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
502 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
503 <<
"-fsanitize-coverage=func"
504 <<
"-fsanitize-coverage=bb";
505 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures &
CoverageEdge))
506 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
507 <<
"-fsanitize-coverage=func"
508 <<
"-fsanitize-coverage=edge";
509 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
510 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
511 <<
"-fsanitize-coverage=bb"
512 <<
"-fsanitize-coverage=edge";
515 int CoverageTypes = CoverageFunc | CoverageBB |
CoverageEdge;
517 !(CoverageFeatures & CoverageTypes))
518 D.
Diag(clang::diag::err_drv_argument_only_allowed_with)
519 <<
"-fsanitize-coverage=trace-bb"
520 <<
"-fsanitize-coverage=(func|bb|edge)";
522 !(CoverageFeatures & CoverageTypes))
523 D.
Diag(clang::diag::err_drv_argument_only_allowed_with)
524 <<
"-fsanitize-coverage=8bit-counters"
525 <<
"-fsanitize-coverage=(func|bb|edge)";
528 !(CoverageFeatures & CoverageTypes))
531 if (AllAddedKinds & Address) {
533 Args.hasArg(options::OPT_shared_libasan) || TC.
getTriple().isAndroid();
536 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
537 StringRef
S = A->getValue();
539 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
540 AsanFieldPadding > 2) {
541 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) <<
S;
545 if (Arg *WindowsDebugRTArg =
546 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
547 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
548 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
549 switch (WindowsDebugRTArg->getOption().getID()) {
550 case options::OPT__SLASH_MTd:
551 case options::OPT__SLASH_MDd:
552 case options::OPT__SLASH_LDd:
553 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
554 << WindowsDebugRTArg->getAsString(Args)
556 D.
Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
562 Args.hasArg(options::OPT_fsanitize_address_use_after_scope);
563 if (AsanUseAfterScope && !(AllAddedKinds & Address)) {
564 D.
Diag(clang::diag::err_drv_argument_only_allowed_with)
565 <<
"-fsanitize-address-use-after-scope"
566 <<
"-fsanitize=address";
571 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.
CCCIsCXX();
574 Sanitizers.Mask |= Kinds;
575 RecoverableSanitizers.Mask |= RecoverableKinds;
576 TrapSanitizers.Mask |= TrappingKinds;
581 #define SANITIZER(NAME, ID) \
582 if (Sanitizers.has(ID)) { \
587 #include "clang/Basic/Sanitizers.def"
592 const llvm::opt::ArgList &Args,
593 llvm::opt::ArgStringList &CmdArgs,
594 StringRef SymbolName) {
596 LinkerOptionFlag =
"--linker-option=/include:";
597 if (TC.
getTriple().getArch() == llvm::Triple::x86) {
599 LinkerOptionFlag +=
'_';
601 LinkerOptionFlag += SymbolName;
602 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
605 void SanitizerArgs::addArgs(
const ToolChain &TC,
const llvm::opt::ArgList &Args,
606 llvm::opt::ArgStringList &CmdArgs,
611 std::pair<int, const char *> CoverageFlags[] = {
612 std::make_pair(
CoverageFunc,
"-fsanitize-coverage-type=1"),
613 std::make_pair(
CoverageBB,
"-fsanitize-coverage-type=2"),
614 std::make_pair(
CoverageEdge,
"-fsanitize-coverage-type=3"),
620 for (
auto F : CoverageFlags) {
621 if (CoverageFeatures & F.first)
622 CmdArgs.push_back(Args.MakeArgString(F.second));
625 if (TC.
getTriple().isOSWindows() && needsUbsanRt()) {
628 CmdArgs.push_back(Args.MakeArgString(
629 "--dependent-lib=" + TC.
getCompilerRT(Args,
"ubsan_standalone")));
631 CmdArgs.push_back(Args.MakeArgString(
632 "--dependent-lib=" + TC.
getCompilerRT(Args,
"ubsan_standalone_cxx")));
634 if (TC.
getTriple().isOSWindows() && needsStatsRt()) {
635 CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" +
642 CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" +
647 if (Sanitizers.empty())
649 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize=" +
toString(Sanitizers)));
651 if (!RecoverableSanitizers.empty())
652 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-recover=" +
655 if (!TrapSanitizers.empty())
657 Args.MakeArgString(
"-fsanitize-trap=" +
toString(TrapSanitizers)));
659 for (
const auto &BLPath : BlacklistFiles) {
661 BlacklistOpt += BLPath;
662 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
664 for (
const auto &Dep : ExtraDeps) {
667 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
670 if (MsanTrackOrigins)
671 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-memory-track-origins=" +
672 llvm::utostr(MsanTrackOrigins)));
674 if (MsanUseAfterDtor)
675 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-memory-use-after-dtor"));
678 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-cfi-cross-dso"));
681 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-stats"));
683 if (AsanFieldPadding)
684 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-address-field-padding=" +
685 llvm::utostr(AsanFieldPadding)));
687 if (AsanUseAfterScope)
688 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-address-use-after-scope"));
695 if (Sanitizers.has(Memory) || Sanitizers.has(Address))
696 CmdArgs.push_back(Args.MakeArgString(
"-fno-assume-sane-operator-new"));
701 !Args.hasArg(options::OPT_fvisibility_EQ)) {
702 TC.
getDriver().
Diag(clang::diag::err_drv_argument_only_allowed_with)
710 bool DiagnoseErrors) {
711 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
712 A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
713 A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
714 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
715 A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
716 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
717 "Invalid argument in parseArgValues!");
719 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
720 const char *
Value = A->getValue(i);
723 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
724 0 == strcmp(
"all", Value))
727 else if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
728 0 == strcmp(
"efficiency-all", Value))
735 else if (DiagnoseErrors)
736 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
737 << A->getOption().getName() <<
Value;
743 assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
744 A->getOption().matches(options::OPT_fno_sanitize_coverage));
746 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
747 const char *
Value = A->getValue(i);
748 int F = llvm::StringSwitch<int>(
Value)
759 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
760 << A->getOption().getName() <<
Value;
768 for (llvm::opt::ArgList::const_reverse_iterator
I = Args.rbegin(),
771 const auto *Arg = *
I;
772 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
777 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
780 Mask &= ~RemoveKinds;
783 llvm_unreachable(
"arg list didn't provide expected value");
787 assert(A->getOption().matches(options::OPT_fsanitize_EQ)
788 &&
"Invalid argument in describeSanitizerArg!");
790 std::string Sanitizers;
791 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
795 if (!Sanitizers.empty())
797 Sanitizers += A->getValue(i);
801 assert(!Sanitizers.empty() &&
"arg didn't provide expected value");
802 return "-fsanitize=" + Sanitizers;
DiagnosticBuilder Diag(unsigned DiagID) const
bool CCCIsCXX() const
Whether the driver should follow g++ like behavior.
Defines the clang::SanitizerKind enum.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
SanitizerMask Mask
Bitmask of enabled sanitizers.
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
detail::InMemoryDirectory::const_iterator I
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.
static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A)
Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid components.
static void addIncludeLinkerOption(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, StringRef SymbolName)
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
detail::InMemoryDirectory::const_iterator E
SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups)
Parse a single value from a -fsanitize= or -fno-sanitize= value list.
static SanitizerMask setGroupBits(SanitizerMask Kinds)
Sets group bits for every group that has at least one representative already enabled in Kinds...
bool isCXX(ID Id)
isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, std::string &BLPath)
bool isUsingLTO() const
Returns true if we are performing any kind of LTO.
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds)
For each sanitizer group bit set in Kinds, set the bits for sanitizers this group enables...
static SanitizerMask parseSanitizeTrapArgs(const Driver &D, const llvm::opt::ArgList &Args)
static std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask)
Produce an argument string from argument A, which shows how it provides a value in Mask...
static std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, SanitizerMask Mask)
Produce an argument string from ArgList Args, which shows how it provides some sanitizer kind from Ma...
std::string ResourceDir
The path to the compiler resource directory.