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,
68 const llvm::opt::ArgList &Args,
83 std::string &BLPath) {
84 const char *BlacklistFile =
nullptr;
86 BlacklistFile =
"asan_blacklist.txt";
87 else if (Kinds & Memory)
88 BlacklistFile =
"msan_blacklist.txt";
89 else if (Kinds & Thread)
90 BlacklistFile =
"tsan_blacklist.txt";
91 else if (Kinds & DataFlow)
92 BlacklistFile =
"dfsan_abilist.txt";
94 BlacklistFile =
"cfi_blacklist.txt";
98 llvm::sys::path::append(Path, BlacklistFile);
108 #define SANITIZER(NAME, ID)
109 #define SANITIZER_GROUP(NAME, ID, ALIAS) \
110 if (Kinds & SanitizerKind::ID) \
111 Kinds |= SanitizerKind::ID##Group;
112 #include "clang/Basic/Sanitizers.def"
117 const llvm::opt::ArgList &Args) {
124 for (ArgList::const_reverse_iterator
I = Args.rbegin(),
E = Args.rend();
126 const auto *Arg = *
I;
127 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
131 if (
SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
133 S.
Mask = InvalidValues;
134 D.
Diag(diag::err_drv_unsupported_option_argument) <<
"-fsanitize-trap"
138 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
141 }
else if (Arg->getOption().matches(
142 options::OPT_fsanitize_undefined_trap_on_error)) {
146 }
else if (Arg->getOption().matches(
147 options::OPT_fno_sanitize_undefined_trap_on_error)) {
156 return TrappingKinds;
159 bool SanitizerArgs::needsUbsanRt()
const {
160 return (Sanitizers.Mask &
NeedsUbsanRt & ~TrapSanitizers.Mask) &&
161 !Sanitizers.has(Address) &&
162 !Sanitizers.has(Memory) &&
163 !Sanitizers.has(Thread) &&
167 bool SanitizerArgs::needsCfiRt()
const {
168 return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
171 bool SanitizerArgs::needsCfiDiagRt()
const {
172 return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
175 bool SanitizerArgs::requiresPIE()
const {
179 bool SanitizerArgs::needsUnwindTables()
const {
185 RecoverableSanitizers.clear();
186 TrapSanitizers.clear();
187 BlacklistFiles.clear();
189 CoverageFeatures = 0;
190 MsanTrackOrigins = 0;
191 MsanUseAfterDtor =
false;
193 AsanFieldPadding = 0;
194 AsanSharedRuntime =
false;
195 LinkCXXRuntimes =
false;
200 const llvm::opt::ArgList &Args) {
220 for (ArgList::const_reverse_iterator
I = Args.rbegin(),
E = Args.rend();
222 const auto *Arg = *
I;
223 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
234 Add & InvalidTrappingKinds & ~DiagnosedKinds) {
236 D.
Diag(diag::err_drv_argument_not_allowed_with)
237 << Desc <<
"-fsanitize-trap=undefined";
238 DiagnosedKinds |= KindsToDiagnose;
240 Add &= ~InvalidTrappingKinds;
241 if (
SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
243 D.
Diag(diag::err_drv_unsupported_opt_for_target)
245 DiagnosedKinds |= KindsToDiagnose;
253 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
254 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
255 if (RTTIMode == ToolChain::RM_DisabledImplicitly)
258 D.
Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
260 const llvm::opt::Arg *NoRTTIArg = TC.
getRTTIArg();
262 "RTTI disabled explicitly but we have no argument!");
263 D.
Diag(diag::err_drv_argument_not_allowed_with)
264 <<
"-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
276 Add &= ~InvalidTrappingKinds;
280 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
289 if ((Kinds & Vptr) &&
290 (RTTIMode == ToolChain::RM_DisabledImplicitly ||
291 RTTIMode == ToolChain::RM_DisabledExplicitly)) {
297 D.
Diag(diag::err_drv_argument_only_allowed_with)
305 if (~Supported & Vptr) {
310 KindsToDiagnose &= ~CFI;
311 if (KindsToDiagnose) {
313 S.
Mask = KindsToDiagnose;
314 D.
Diag(diag::err_drv_unsupported_opt_for_target)
316 Kinds &= ~KindsToDiagnose;
321 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
322 std::make_pair(Address, Thread), std::make_pair(Address, Memory),
323 std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
324 std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
325 std::make_pair(KernelAddress, Leak),
326 std::make_pair(KernelAddress, Thread),
327 std::make_pair(KernelAddress, Memory)};
328 for (
auto G : IncompatibleGroups) {
332 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
335 Kinds &= ~Incompatible;
347 for (
const auto *Arg : Args) {
348 const char *DeprecatedReplacement =
nullptr;
349 if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
350 DeprecatedReplacement =
"-fsanitize-recover=undefined,integer";
353 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
354 DeprecatedReplacement =
"-fno-sanitize-recover=undefined,integer";
357 }
else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
364 SetToDiagnose.
Mask |= KindsToDiagnose;
365 D.
Diag(diag::err_drv_unsupported_option_argument)
366 << Arg->getOption().getName() <<
toString(SetToDiagnose);
367 DiagnosedUnrecoverableKinds |= KindsToDiagnose;
371 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
375 if (DeprecatedReplacement) {
376 D.
Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
377 << DeprecatedReplacement;
380 RecoverableKinds &= Kinds;
383 TrappingKinds &= Kinds;
390 BlacklistFiles.push_back(BLPath);
393 for (
const auto *Arg : Args) {
394 if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
396 std::string BLPath = Arg->getValue();
397 if (llvm::sys::fs::exists(BLPath)) {
398 BlacklistFiles.push_back(BLPath);
399 ExtraDeps.push_back(BLPath);
401 D.
Diag(clang::diag::err_drv_no_such_file) << BLPath;
403 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
405 BlacklistFiles.clear();
412 std::unique_ptr<llvm::SpecialCaseList> SCL(
415 D.
Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
419 if (AllAddedKinds & Memory) {
421 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
422 options::OPT_fsanitize_memory_track_origins,
423 options::OPT_fno_sanitize_memory_track_origins)) {
424 if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
425 MsanTrackOrigins = 2;
426 }
else if (A->getOption().matches(
427 options::OPT_fno_sanitize_memory_track_origins)) {
428 MsanTrackOrigins = 0;
430 StringRef
S = A->getValue();
431 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
432 MsanTrackOrigins > 2) {
433 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) <<
S;
438 Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor);
439 NeedPIE |= !(TC.
getTriple().isOSLinux() &&
440 TC.
getTriple().getArch() == llvm::Triple::x86_64);
443 if (AllAddedKinds & CFI) {
444 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
445 options::OPT_fno_sanitize_cfi_cross_dso,
false);
448 NeedPIE |= CfiCrossDso;
454 for (
const auto *Arg : Args) {
455 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
457 int LegacySanitizeCoverage;
458 if (Arg->getNumValues() == 1 &&
459 !StringRef(Arg->getValue(0))
460 .getAsInteger(0, LegacySanitizeCoverage) &&
461 LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
463 switch (LegacySanitizeCoverage) {
465 CoverageFeatures = 0;
483 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
491 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
492 <<
"-fsanitize-coverage=func"
493 <<
"-fsanitize-coverage=bb";
494 if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures &
CoverageEdge))
495 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
496 <<
"-fsanitize-coverage=func"
497 <<
"-fsanitize-coverage=edge";
498 if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
499 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
500 <<
"-fsanitize-coverage=bb"
501 <<
"-fsanitize-coverage=edge";
504 int CoverageTypes = CoverageFunc | CoverageBB |
CoverageEdge;
506 !(CoverageFeatures & CoverageTypes))
507 D.
Diag(clang::diag::err_drv_argument_only_allowed_with)
508 <<
"-fsanitize-coverage=trace-bb"
509 <<
"-fsanitize-coverage=(func|bb|edge)";
511 !(CoverageFeatures & CoverageTypes))
512 D.
Diag(clang::diag::err_drv_argument_only_allowed_with)
513 <<
"-fsanitize-coverage=8bit-counters"
514 <<
"-fsanitize-coverage=(func|bb|edge)";
516 if (AllAddedKinds & Address) {
518 Args.hasArg(options::OPT_shared_libasan) || TC.
getTriple().isAndroid();
521 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
522 StringRef
S = A->getValue();
524 if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
525 AsanFieldPadding > 2) {
526 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) <<
S;
530 if (Arg *WindowsDebugRTArg =
531 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
532 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
533 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
534 switch (WindowsDebugRTArg->getOption().getID()) {
535 case options::OPT__SLASH_MTd:
536 case options::OPT__SLASH_MDd:
537 case options::OPT__SLASH_LDd:
538 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
539 << WindowsDebugRTArg->getAsString(Args)
541 D.
Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
548 Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.
CCCIsCXX();
551 Sanitizers.Mask |= Kinds;
552 RecoverableSanitizers.Mask |= RecoverableKinds;
553 TrapSanitizers.Mask |= TrappingKinds;
558 #define SANITIZER(NAME, ID) \
559 if (Sanitizers.has(ID)) { \
564 #include "clang/Basic/Sanitizers.def"
568 void SanitizerArgs::addArgs(
const ToolChain &TC,
const llvm::opt::ArgList &Args,
569 llvm::opt::ArgStringList &CmdArgs,
571 if (Sanitizers.empty())
573 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize=" +
toString(Sanitizers)));
575 if (!RecoverableSanitizers.empty())
576 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-recover=" +
579 if (!TrapSanitizers.empty())
581 Args.MakeArgString(
"-fsanitize-trap=" +
toString(TrapSanitizers)));
583 for (
const auto &BLPath : BlacklistFiles) {
585 BlacklistOpt += BLPath;
586 CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
588 for (
const auto &Dep : ExtraDeps) {
591 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
594 if (MsanTrackOrigins)
595 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-memory-track-origins=" +
596 llvm::utostr(MsanTrackOrigins)));
598 if (MsanUseAfterDtor)
599 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-memory-use-after-dtor"));
602 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-cfi-cross-dso"));
604 if (AsanFieldPadding)
605 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-address-field-padding=" +
606 llvm::utostr(AsanFieldPadding)));
608 std::pair<int, const char *> CoverageFlags[] = {
609 std::make_pair(
CoverageFunc,
"-fsanitize-coverage-type=1"),
610 std::make_pair(
CoverageBB,
"-fsanitize-coverage-type=2"),
611 std::make_pair(
CoverageEdge,
"-fsanitize-coverage-type=3"),
616 for (
auto F : CoverageFlags) {
617 if (CoverageFeatures & F.first)
618 CmdArgs.push_back(Args.MakeArgString(F.second));
627 if (Sanitizers.has(Memory) || Sanitizers.has(Address))
628 CmdArgs.push_back(Args.MakeArgString(
"-fno-assume-sane-operator-new"));
630 if (TC.
getTriple().isOSWindows() && needsUbsanRt()) {
633 CmdArgs.push_back(Args.MakeArgString(
634 "--dependent-lib=" + TC.
getCompilerRT(Args,
"ubsan_standalone")));
636 CmdArgs.push_back(Args.MakeArgString(
637 "--dependent-lib=" + TC.
getCompilerRT(Args,
"ubsan_standalone_cxx")));
642 bool DiagnoseErrors) {
643 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
644 A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
645 A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
646 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
647 A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
648 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
649 "Invalid argument in parseArgValues!");
651 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
652 const char *
Value = A->getValue(i);
655 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
656 0 == strcmp(
"all", Value))
663 else if (DiagnoseErrors)
664 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
665 << A->getOption().getName() <<
Value;
671 assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
672 A->getOption().matches(options::OPT_fno_sanitize_coverage));
674 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
675 const char *
Value = A->getValue(i);
676 int F = llvm::StringSwitch<int>(
Value)
686 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
687 << A->getOption().getName() <<
Value;
695 for (llvm::opt::ArgList::const_reverse_iterator
I = Args.rbegin(),
698 const auto *Arg = *
I;
699 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
704 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
707 Mask &= ~RemoveKinds;
710 llvm_unreachable(
"arg list didn't provide expected value");
714 assert(A->getOption().matches(options::OPT_fsanitize_EQ)
715 &&
"Invalid argument in describeSanitizerArg!");
717 std::string Sanitizers;
718 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
722 if (!Sanitizers.empty())
724 Sanitizers += A->getValue(i);
728 assert(!Sanitizers.empty() &&
"arg didn't provide expected value");
729 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.
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.