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;
43 CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
76 const llvm::opt::ArgList &Args,
91 std::string &BLPath) {
92 const char *BlacklistFile =
nullptr;
94 BlacklistFile =
"asan_blacklist.txt";
95 else if (Kinds & Memory)
96 BlacklistFile =
"msan_blacklist.txt";
97 else if (Kinds & Thread)
98 BlacklistFile =
"tsan_blacklist.txt";
99 else if (Kinds & DataFlow)
100 BlacklistFile =
"dfsan_abilist.txt";
101 else if (Kinds & CFI)
102 BlacklistFile =
"cfi_blacklist.txt";
106 llvm::sys::path::append(Path, BlacklistFile);
116 #define SANITIZER(NAME, ID)
117 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
118 if (Kinds & SanitizerKind::ID) \
119 Kinds |= SanitizerKind::ID##Group;
120 #include "clang/Basic/Sanitizers.def"
125 const llvm::opt::ArgList &Args) {
132 for (ArgList::const_reverse_iterator
I = Args.rbegin(),
E = Args.rend();
134 const auto *Arg = *
I;
135 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
139 if (
SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
141 S.
Mask = InvalidValues;
142 D.
Diag(diag::err_drv_unsupported_option_argument) <<
"-fsanitize-trap"
146 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
149 }
else if (Arg->getOption().matches(
150 options::OPT_fsanitize_undefined_trap_on_error)) {
154 }
else if (Arg->getOption().matches(
155 options::OPT_fno_sanitize_undefined_trap_on_error)) {
164 return TrappingKinds;
167 bool SanitizerArgs::needsUbsanRt()
const {
168 return ((Sanitizers.Mask &
NeedsUbsanRt & ~TrapSanitizers.Mask) ||
170 !Sanitizers.has(Address) && !Sanitizers.has(Memory) &&
171 !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) &&
172 !Sanitizers.has(Leak) && !CfiCrossDso;
175 bool SanitizerArgs::needsCfiRt()
const {
176 return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
179 bool SanitizerArgs::needsCfiDiagRt()
const {
180 return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
183 bool SanitizerArgs::requiresPIE()
const {
187 bool SanitizerArgs::needsUnwindTables()
const {
192 const llvm::opt::ArgList &Args) {
212 Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
213 bool RemoveObjectSizeAtO0 =
214 !OptLevel || OptLevel->getOption().matches(options::OPT_O0);
216 for (ArgList::const_reverse_iterator
I = Args.rbegin(),
E = Args.rend();
218 const auto *Arg = *
I;
219 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
223 if (RemoveObjectSizeAtO0) {
224 AllRemove |= SanitizerKind::ObjectSize;
228 if (Add & SanitizerKind::ObjectSize)
229 D.
Diag(diag::warn_drv_object_size_disabled_O0)
230 << Arg->getAsString(Args);
241 Add & InvalidTrappingKinds & ~DiagnosedKinds) {
243 D.
Diag(diag::err_drv_argument_not_allowed_with)
244 << Desc <<
"-fsanitize-trap=undefined";
245 DiagnosedKinds |= KindsToDiagnose;
247 Add &= ~InvalidTrappingKinds;
248 if (
SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
250 D.
Diag(diag::err_drv_unsupported_opt_for_target)
252 DiagnosedKinds |= KindsToDiagnose;
260 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
261 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
262 if (RTTIMode == ToolChain::RM_DisabledImplicitly)
265 D.
Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
267 const llvm::opt::Arg *NoRTTIArg = TC.
getRTTIArg();
269 "RTTI disabled explicitly but we have no argument!");
270 D.
Diag(diag::err_drv_argument_not_allowed_with)
271 <<
"-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
283 Add &= ~InvalidTrappingKinds;
291 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
303 if ((Kinds & Vptr) &&
304 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
305 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
311 D.
Diag(diag::err_drv_argument_only_allowed_with)
319 if (~Supported & Vptr) {
324 KindsToDiagnose &= ~CFI;
325 if (KindsToDiagnose) {
327 S.
Mask = KindsToDiagnose;
328 D.
Diag(diag::err_drv_unsupported_opt_for_target)
330 Kinds &= ~KindsToDiagnose;
335 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
336 std::make_pair(Address, Thread), std::make_pair(Address, Memory),
337 std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
338 std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
339 std::make_pair(KernelAddress, Leak),
340 std::make_pair(KernelAddress, Thread),
341 std::make_pair(KernelAddress, Memory),
342 std::make_pair(Efficiency, Address),
343 std::make_pair(Efficiency, Leak),
344 std::make_pair(Efficiency, Thread),
345 std::make_pair(Efficiency, Memory),
346 std::make_pair(Efficiency, KernelAddress)};
347 for (
auto G : IncompatibleGroups) {
351 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
354 Kinds &= ~Incompatible;
366 for (
const auto *Arg : Args) {
367 const char *DeprecatedReplacement =
nullptr;
368 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
369 DeprecatedReplacement =
370 "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all";
373 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
374 DeprecatedReplacement =
"-fno-sanitize-recover=undefined,integer' or "
375 "'-fno-sanitize-recover=all";
378 }
else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
385 SetToDiagnose.
Mask |= KindsToDiagnose;
386 D.
Diag(diag::err_drv_unsupported_option_argument)
387 << Arg->getOption().getName() <<
toString(SetToDiagnose);
388 DiagnosedUnrecoverableKinds |= KindsToDiagnose;
392 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
396 if (DeprecatedReplacement) {
397 D.
Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
398 << DeprecatedReplacement;
401 RecoverableKinds &= Kinds;
404 TrappingKinds &= Kinds;
411 BlacklistFiles.push_back(BLPath);
414 for (
const auto *Arg : Args) {
415 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
417 std::string BLPath = Arg->getValue();
418 if (llvm::sys::fs::exists(BLPath)) {
419 BlacklistFiles.push_back(BLPath);
420 ExtraDeps.push_back(BLPath);
422 D.
Diag(clang::diag::err_drv_no_such_file) << BLPath;
424 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
426 BlacklistFiles.clear();
433 std::unique_ptr<llvm::SpecialCaseList> SCL(
436 D.
Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
440 if (AllAddedKinds & Memory) {
442 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
443 options::OPT_fsanitize_memory_track_origins,
444 options::OPT_fno_sanitize_memory_track_origins)) {
445 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
446 MsanTrackOrigins = 2;
447 }
else if (A->getOption().matches(
448 options::OPT_fno_sanitize_memory_track_origins)) {
449 MsanTrackOrigins = 0;
451 StringRef
S = A->getValue();
452 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
453 MsanTrackOrigins > 2) {
454 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) <<
S;
459 Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor);
460 NeedPIE |= !(TC.
getTriple().isOSLinux() &&
461 TC.
getTriple().getArch() == llvm::Triple::x86_64);
464 if (AllAddedKinds & Thread) {
465 TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access,
466 options::OPT_fno_sanitize_thread_memory_access,
468 TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit,
469 options::OPT_fno_sanitize_thread_func_entry_exit,
471 TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics,
472 options::OPT_fno_sanitize_thread_atomics,
476 if (AllAddedKinds & CFI) {
477 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
478 options::OPT_fno_sanitize_cfi_cross_dso,
false);
481 NeedPIE |= CfiCrossDso;
484 Stats = Args.hasFlag(options::OPT_fsanitize_stats,
485 options::OPT_fno_sanitize_stats,
false);
489 for (
const auto *Arg : Args) {
490 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
491 int LegacySanitizeCoverage;
492 if (Arg->getNumValues() == 1 &&
493 !StringRef(Arg->getValue(0))
494 .getAsInteger(0, LegacySanitizeCoverage)) {
495 CoverageFeatures = 0;
497 if (LegacySanitizeCoverage != 0) {
498 D.
Diag(diag::warn_drv_deprecated_arg)
499 << Arg->getAsString(Args) <<
"-fsanitize-coverage=trace-pc-guard";
510 CoverageFeatures = 0;
512 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
519 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
520 <<
"-fsanitize-coverage=func"
521 <<
"-fsanitize-coverage=bb";
522 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures &
CoverageEdge))
523 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
524 <<
"-fsanitize-coverage=func"
525 <<
"-fsanitize-coverage=edge";
526 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
527 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
528 <<
"-fsanitize-coverage=bb"
529 <<
"-fsanitize-coverage=edge";
533 D.
Diag(clang::diag::warn_drv_deprecated_arg)
534 <<
"-fsanitize-coverage=trace-bb"
535 <<
"-fsanitize-coverage=trace-pc-guard";
537 D.
Diag(clang::diag::warn_drv_deprecated_arg)
538 <<
"-fsanitize-coverage=8bit-counters"
539 <<
"-fsanitize-coverage=trace-pc-guard";
541 int InsertionPointTypes = CoverageFunc | CoverageBB |
CoverageEdge;
542 if ((CoverageFeatures & InsertionPointTypes) &&
544 D.
Diag(clang::diag::warn_drv_deprecated_arg)
545 <<
"-fsanitize-coverage=[func|bb|edge]"
546 <<
"-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
550 if ((CoverageFeatures &
552 !(CoverageFeatures & InsertionPointTypes))
555 if (AllAddedKinds & Address) {
557 Args.hasArg(options::OPT_shared_libasan) || TC.
getTriple().isAndroid();
560 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
561 StringRef
S = A->getValue();
563 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
564 AsanFieldPadding > 2) {
565 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) <<
S;
569 if (Arg *WindowsDebugRTArg =
570 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
571 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
572 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
573 switch (WindowsDebugRTArg->getOption().getID()) {
574 case options::OPT__SLASH_MTd:
575 case options::OPT__SLASH_MDd:
576 case options::OPT__SLASH_LDd:
577 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
578 << WindowsDebugRTArg->getAsString(Args)
580 D.
Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
584 AsanUseAfterScope = Args.hasFlag(
585 options::OPT_fsanitize_address_use_after_scope,
586 options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
591 AsanGlobalsDeadStripping =
593 Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
595 AsanUseAfterScope =
false;
600 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.
CCCIsCXX();
603 Sanitizers.Mask |= Kinds;
604 RecoverableSanitizers.Mask |= RecoverableKinds;
605 TrapSanitizers.Mask |= TrappingKinds;
610 #define SANITIZER(NAME, ID) \
611 if (Sanitizers.has(ID)) { \
616 #include "clang/Basic/Sanitizers.def"
621 const llvm::opt::ArgList &Args,
622 llvm::opt::ArgStringList &CmdArgs,
623 StringRef SymbolName) {
625 LinkerOptionFlag =
"--linker-option=/include:";
626 if (TC.
getTriple().getArch() == llvm::Triple::x86) {
628 LinkerOptionFlag +=
'_';
630 LinkerOptionFlag += SymbolName;
631 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
634 void SanitizerArgs::addArgs(
const ToolChain &TC,
const llvm::opt::ArgList &Args,
635 llvm::opt::ArgStringList &CmdArgs,
646 std::pair<int, const char *> CoverageFlags[] = {
647 std::make_pair(
CoverageFunc,
"-fsanitize-coverage-type=1"),
648 std::make_pair(
CoverageBB,
"-fsanitize-coverage-type=2"),
649 std::make_pair(
CoverageEdge,
"-fsanitize-coverage-type=3"),
660 for (
auto F : CoverageFlags) {
661 if (CoverageFeatures & F.first)
662 CmdArgs.push_back(F.second);
665 if (TC.
getTriple().isOSWindows() && needsUbsanRt()) {
668 CmdArgs.push_back(Args.MakeArgString(
669 "--dependent-lib=" + TC.
getCompilerRT(Args,
"ubsan_standalone")));
671 CmdArgs.push_back(Args.MakeArgString(
672 "--dependent-lib=" + TC.
getCompilerRT(Args,
"ubsan_standalone_cxx")));
674 if (TC.
getTriple().isOSWindows() && needsStatsRt()) {
675 CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" +
682 CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" +
687 if (Sanitizers.empty())
689 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize=" +
toString(Sanitizers)));
691 if (!RecoverableSanitizers.empty())
692 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-recover=" +
695 if (!TrapSanitizers.empty())
697 Args.MakeArgString(
"-fsanitize-trap=" +
toString(TrapSanitizers)));
699 for (
const auto &BLPath : BlacklistFiles) {
701 BlacklistOpt += BLPath;
702 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
704 for (
const auto &Dep : ExtraDeps) {
707 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
710 if (MsanTrackOrigins)
711 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-memory-track-origins=" +
712 llvm::utostr(MsanTrackOrigins)));
714 if (MsanUseAfterDtor)
715 CmdArgs.push_back(
"-fsanitize-memory-use-after-dtor");
718 if (!TsanMemoryAccess) {
719 CmdArgs.push_back(
"-mllvm");
720 CmdArgs.push_back(
"-tsan-instrument-memory-accesses=0");
721 CmdArgs.push_back(
"-mllvm");
722 CmdArgs.push_back(
"-tsan-instrument-memintrinsics=0");
724 if (!TsanFuncEntryExit) {
725 CmdArgs.push_back(
"-mllvm");
726 CmdArgs.push_back(
"-tsan-instrument-func-entry-exit=0");
729 CmdArgs.push_back(
"-mllvm");
730 CmdArgs.push_back(
"-tsan-instrument-atomics=0");
734 CmdArgs.push_back(
"-fsanitize-cfi-cross-dso");
737 CmdArgs.push_back(
"-fsanitize-stats");
739 if (AsanFieldPadding)
740 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-address-field-padding=" +
741 llvm::utostr(AsanFieldPadding)));
743 if (AsanUseAfterScope)
744 CmdArgs.push_back(
"-fsanitize-address-use-after-scope");
746 if (AsanGlobalsDeadStripping)
747 CmdArgs.push_back(
"-fsanitize-address-globals-dead-stripping");
754 if (Sanitizers.has(Memory) || Sanitizers.has(Address))
755 CmdArgs.push_back(
"-fno-assume-sane-operator-new");
760 !Args.hasArg(options::OPT_fvisibility_EQ)) {
761 TC.
getDriver().
Diag(clang::diag::err_drv_argument_only_allowed_with)
769 bool DiagnoseErrors) {
770 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
771 A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
772 A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
773 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
774 A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
775 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
776 "Invalid argument in parseArgValues!");
778 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
779 const char *
Value = A->getValue(i);
782 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
783 0 == strcmp(
"all", Value))
786 else if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
787 0 == strcmp(
"efficiency-all", Value))
794 else if (DiagnoseErrors)
795 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
796 << A->getOption().getName() <<
Value;
802 assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
803 A->getOption().matches(options::OPT_fno_sanitize_coverage));
805 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
806 const char *
Value = A->getValue(i);
807 int F = llvm::StringSwitch<int>(
Value)
823 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
824 << A->getOption().getName() <<
Value;
832 for (llvm::opt::ArgList::const_reverse_iterator
I = Args.rbegin(),
835 const auto *Arg = *
I;
836 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
841 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
844 Mask &= ~RemoveKinds;
847 llvm_unreachable(
"arg list didn't provide expected value");
851 assert(A->getOption().matches(options::OPT_fsanitize_EQ)
852 &&
"Invalid argument in describeSanitizerArg!");
854 std::string Sanitizers;
855 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
859 if (!Sanitizers.empty())
861 Sanitizers += A->getValue(i);
865 assert(!Sanitizers.empty() &&
"arg didn't provide expected value");
866 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.