15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/StringSwitch.h"
18#include "llvm/Support/Path.h"
19#include "llvm/Support/SpecialCaseList.h"
20#include "llvm/Support/VirtualFileSystem.h"
21#include "llvm/TargetParser/AArch64TargetParser.h"
22#include "llvm/TargetParser/RISCVTargetParser.h"
23#include "llvm/TargetParser/TargetParser.h"
24#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
32 SanitizerKind::Undefined | SanitizerKind::Integer |
33 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
34 SanitizerKind::CFI | SanitizerKind::FloatDivideByZero |
35 SanitizerKind::ObjCCast;
37 SanitizerKind::Vptr | SanitizerKind::CFI;
41 SanitizerKind::Function | SanitizerKind::KCFI;
43 SanitizerKind::DataFlow | SanitizerKind::Scudo;
45 SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
46 SanitizerKind::Memory | SanitizerKind::DataFlow;
48 SanitizerKind::Address | SanitizerKind::HWAddress |
49 SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
50 SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
51 SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
52 SanitizerKind::KernelMemory | SanitizerKind::Leak |
53 SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
54 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
55 SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
56 SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
57 SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
58 SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
60 SanitizerKind::Undefined | SanitizerKind::Integer |
61 SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
62 SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
64 SanitizerKind::Unreachable | SanitizerKind::Return;
66 SanitizerKind::KernelHWAddress |
70 (SanitizerKind::Undefined &
~SanitizerKind::Vptr) | SanitizerKind::Integer |
71 SanitizerKind::Nullability | SanitizerKind::LocalBounds |
72 SanitizerKind::CFI | SanitizerKind::FloatDivideByZero |
73 SanitizerKind::ObjCCast;
76 SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
77 SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast |
78 SanitizerKind::CFIUnrelatedCast;
81 SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
82 SanitizerKind::MemtagGlobals | SanitizerKind::KCFI;
115 bool DiagnoseErrors);
120 bool DiagnoseErrors);
125 bool DiagnoseErrors);
132 const llvm::opt::ArgList &Args,
149 const llvm::opt::ArgList &Args) {
152 return Args.hasFlagNoClaim(options::OPT_mexecute_only,
153 options::OPT_mno_execute_only,
false);
157 std::vector<std::string> &SCLFiles,
158 unsigned MalformedSCLErrorDiagID,
159 bool DiagnoseErrors) {
160 if (SCLFiles.empty())
164 std::unique_ptr<llvm::SpecialCaseList> SCL(
165 llvm::SpecialCaseList::create(SCLFiles, D.
getVFS(), BLError));
166 if (!SCL.get() && DiagnoseErrors)
167 D.
Diag(MalformedSCLErrorDiagID) << BLError;
171 std::vector<std::string> &IgnorelistFiles,
172 bool DiagnoseErrors) {
176 } Ignorelists[] = {{
"asan_ignorelist.txt", SanitizerKind::Address},
177 {
"hwasan_ignorelist.txt", SanitizerKind::HWAddress},
178 {
"memtag_ignorelist.txt", SanitizerKind::MemTag},
179 {
"msan_ignorelist.txt", SanitizerKind::Memory},
180 {
"tsan_ignorelist.txt", SanitizerKind::Thread},
181 {
"dfsan_abilist.txt", SanitizerKind::DataFlow},
182 {
"cfi_ignorelist.txt", SanitizerKind::CFI},
183 {
"ubsan_ignorelist.txt",
184 SanitizerKind::Undefined | SanitizerKind::Integer |
185 SanitizerKind::Nullability |
186 SanitizerKind::FloatDivideByZero}};
188 for (
auto BL : Ignorelists) {
189 if (!(Kinds & BL.Mask))
193 llvm::sys::path::append(Path,
"share", BL.File);
194 if (D.
getVFS().exists(Path))
195 IgnorelistFiles.push_back(std::string(Path.str()));
196 else if (BL.Mask == SanitizerKind::CFI && DiagnoseErrors)
199 D.
Diag(clang::diag::err_drv_missing_sanitizer_ignorelist) << Path;
202 D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist,
209 const llvm::opt::ArgList &Args,
210 std::vector<std::string> &SCLFiles,
211 llvm::opt::OptSpecifier SCLOptionID,
212 llvm::opt::OptSpecifier NoSCLOptionID,
213 unsigned MalformedSCLErrorDiagID,
214 bool DiagnoseErrors) {
215 for (
const auto *Arg : Args) {
217 if (Arg->getOption().matches(SCLOptionID)) {
219 std::string SCLPath = Arg->getValue();
220 if (D.
getVFS().exists(SCLPath)) {
221 SCLFiles.push_back(SCLPath);
222 }
else if (DiagnoseErrors) {
223 D.
Diag(clang::diag::err_drv_no_such_file) << SCLPath;
226 }
else if (Arg->getOption().matches(NoSCLOptionID)) {
238#define SANITIZER(NAME, ID)
239#define SANITIZER_GROUP(NAME, ID, ALIAS) \
240 if (Kinds & SanitizerKind::ID) \
241 Kinds |= SanitizerKind::ID##Group;
242#include "clang/Basic/Sanitizers.def"
247 const llvm::opt::ArgList &Args,
248 bool DiagnoseErrors) {
255 for (
const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
256 if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
260 SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups;
261 if (InvalidValues && DiagnoseErrors) {
263 S.Mask = InvalidValues;
264 D.
Diag(diag::err_drv_unsupported_option_argument)
265 << Arg->getSpelling() <<
toString(S);
268 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
278 return TrappingKinds;
297 return !(Sanitizers.
Mask & SanitizerKind::CFI & ~TrapSanitizers.Mask) &&
298 CfiCrossDso && !ImplicitCfiRuntime;
302 return (Sanitizers.
Mask & SanitizerKind::CFI & ~TrapSanitizers.
Mask) &&
303 CfiCrossDso && !ImplicitCfiRuntime;
319 const llvm::opt::ArgList &Args,
320 bool DiagnoseErrors) {
334 CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
335 options::OPT_fno_sanitize_cfi_cross_dso,
false);
344 Args.hasFlag(options::OPT_fsanitize_minimal_runtime,
345 options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime);
348 Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
349 bool RemoveObjectSizeAtO0 =
350 !OptLevel || OptLevel->getOption().matches(options::OPT_O0);
352 for (
const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
353 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
357 if (RemoveObjectSizeAtO0) {
358 AllRemove |= SanitizerKind::ObjectSize;
362 if ((Add & SanitizerKind::ObjectSize) && DiagnoseErrors)
363 D.
Diag(diag::warn_drv_object_size_disabled_O0)
364 << Arg->getAsString(Args);
375 Add & InvalidTrappingKinds & ~DiagnosedKinds) {
376 if (DiagnoseErrors) {
378 D.
Diag(diag::err_drv_argument_not_allowed_with)
379 << Desc <<
"-fsanitize-trap=undefined";
381 DiagnosedKinds |= KindsToDiagnose;
383 Add &= ~InvalidTrappingKinds;
385 if (MinimalRuntime) {
388 if (DiagnoseErrors) {
390 D.
Diag(diag::err_drv_argument_not_allowed_with)
391 << Desc <<
"-fsanitize-minimal-runtime";
393 DiagnosedKinds |= KindsToDiagnose;
395 Add &= ~NotAllowedWithMinimalRuntime;
398 if (llvm::opt::Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
399 StringRef CM = A->getValue();
401 (Add & SanitizerKind::Function & ~DiagnosedKinds)) {
403 D.
Diag(diag::err_drv_argument_only_allowed_with)
404 <<
"-fsanitize=function"
407 DiagnosedKinds |= SanitizerKind::Function;
413 const llvm::Triple &Triple = TC.
getTriple();
417 if (DiagnoseErrors) {
419 D.
Diag(diag::err_drv_argument_not_allowed_with)
420 << Desc << Triple.str();
422 DiagnosedKinds |= KindsToDiagnose;
424 Add &= ~NotAllowedWithExecuteOnly;
437 if (CfiCrossDso && (Add & SanitizerKind::CFIMFCall & ~DiagnosedKinds)) {
439 D.
Diag(diag::err_drv_argument_not_allowed_with)
440 <<
"-fsanitize=cfi-mfcall"
441 <<
"-fsanitize-cfi-cross-dso";
443 DiagnosedKinds |= SanitizerKind::CFIMFCall;
446 if (
SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
447 if (DiagnoseErrors) {
449 D.
Diag(diag::err_drv_unsupported_opt_for_target)
452 DiagnosedKinds |= KindsToDiagnose;
460 if (
const llvm::opt::Arg *NoRTTIArg = TC.
getRTTIArg()) {
461 assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) &&
462 "RTTI disabled without -fno-rtti option?");
466 D.
Diag(diag::err_drv_argument_not_allowed_with)
467 <<
"-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
472 D.
Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
476 AllRemove |= SanitizerKind::Vptr;
484 Add &= ~InvalidTrappingKinds;
485 if (MinimalRuntime) {
486 Add &= ~NotAllowedWithMinimalRuntime;
491 Add &= ~NotAllowedWithExecuteOnly;
496 if (Add & SanitizerKind::Fuzzer)
497 Add |= SanitizerKind::FuzzerNoLink;
500 if (Add & SanitizerKind::FuzzerNoLink) {
509 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
516 std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
517 std::make_pair(SanitizerKind::Address,
518 SanitizerKind::Thread | SanitizerKind::Memory),
519 std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
520 std::make_pair(SanitizerKind::Leak,
521 SanitizerKind::Thread | SanitizerKind::Memory),
522 std::make_pair(SanitizerKind::KernelAddress,
523 SanitizerKind::Address | SanitizerKind::Leak |
524 SanitizerKind::Thread | SanitizerKind::Memory),
525 std::make_pair(SanitizerKind::HWAddress,
526 SanitizerKind::Address | SanitizerKind::Thread |
527 SanitizerKind::Memory | SanitizerKind::KernelAddress),
528 std::make_pair(SanitizerKind::Scudo,
529 SanitizerKind::Address | SanitizerKind::HWAddress |
530 SanitizerKind::Leak | SanitizerKind::Thread |
531 SanitizerKind::Memory | SanitizerKind::KernelAddress),
532 std::make_pair(SanitizerKind::SafeStack,
534 : SanitizerKind::Leak) |
535 SanitizerKind::Address | SanitizerKind::HWAddress |
536 SanitizerKind::Thread | SanitizerKind::Memory |
537 SanitizerKind::KernelAddress),
538 std::make_pair(SanitizerKind::KernelHWAddress,
539 SanitizerKind::Address | SanitizerKind::HWAddress |
540 SanitizerKind::Leak | SanitizerKind::Thread |
541 SanitizerKind::Memory | SanitizerKind::KernelAddress |
542 SanitizerKind::SafeStack),
543 std::make_pair(SanitizerKind::KernelMemory,
544 SanitizerKind::Address | SanitizerKind::HWAddress |
545 SanitizerKind::Leak | SanitizerKind::Thread |
546 SanitizerKind::Memory | SanitizerKind::KernelAddress |
547 SanitizerKind::Scudo | SanitizerKind::SafeStack),
548 std::make_pair(SanitizerKind::MemTag,
549 SanitizerKind::Address | SanitizerKind::KernelAddress |
550 SanitizerKind::HWAddress |
551 SanitizerKind::KernelHWAddress),
552 std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)};
558 for (
auto G : IncompatibleGroups) {
560 if ((
Default & Group) && (Kinds & G.second))
574 D.
Diag(diag::err_drv_argument_only_allowed_with)
578 if ((Kinds & SanitizerKind::ShadowCallStack) && TC.
getTriple().isAArch64() &&
579 !llvm::AArch64::isX18ReservedByDefault(TC.
getTriple()) &&
580 !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) {
581 D.
Diag(diag::err_drv_argument_only_allowed_with)
590 if (~Supported & SanitizerKind::Vptr) {
596 if (KindsToDiagnose) {
598 S.Mask = KindsToDiagnose;
600 D.
Diag(diag::err_drv_unsupported_opt_for_target)
602 Kinds &= ~KindsToDiagnose;
607 for (
auto G : IncompatibleGroups) {
612 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
615 Kinds &= ~Incompatible;
628 for (
const auto *Arg : Args) {
629 if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
636 SetToDiagnose.
Mask |= KindsToDiagnose;
638 D.
Diag(diag::err_drv_unsupported_option_argument)
639 << Arg->getSpelling() <<
toString(SetToDiagnose);
640 DiagnosedUnrecoverableKinds |= KindsToDiagnose;
644 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
651 SetToDiagnose.
Mask |= KindsToDiagnose;
653 D.
Diag(diag::err_drv_unsupported_option_argument)
654 << Arg->getSpelling() <<
toString(SetToDiagnose);
655 DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
657 RecoverableKinds &= ~expandSanitizerGroups(Remove);
661 RecoverableKinds &= Kinds;
662 RecoverableKinds &= ~Unrecoverable;
664 TrappingKinds &= Kinds;
665 RecoverableKinds &= ~TrappingKinds;
670 if (!Args.hasArgNoClaim(options::OPT_fno_sanitize_ignorelist))
676 D, Args, UserIgnorelistFiles, options::OPT_fsanitize_ignorelist_EQ,
677 options::OPT_fno_sanitize_ignorelist,
678 clang::diag::err_drv_malformed_sanitizer_ignorelist, DiagnoseErrors);
681 if (AllAddedKinds & SanitizerKind::Memory) {
683 Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
684 options::OPT_fno_sanitize_memory_track_origins)) {
685 if (!A->getOption().matches(
686 options::OPT_fno_sanitize_memory_track_origins)) {
687 StringRef S = A->getValue();
688 if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
689 MsanTrackOrigins > 2) {
691 D.
Diag(clang::diag::err_drv_invalid_value)
692 << A->getAsString(Args) << S;
696 MsanUseAfterDtor = Args.hasFlag(
697 options::OPT_fsanitize_memory_use_after_dtor,
698 options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor);
699 MsanParamRetval = Args.hasFlag(
700 options::OPT_fsanitize_memory_param_retval,
701 options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
702 NeedPIE |= !(TC.
getTriple().isOSLinux() &&
703 TC.
getTriple().getArch() == llvm::Triple::x86_64);
704 }
else if (AllAddedKinds & SanitizerKind::KernelMemory) {
705 MsanUseAfterDtor =
false;
706 MsanParamRetval = Args.hasFlag(
707 options::OPT_fsanitize_memory_param_retval,
708 options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
710 MsanUseAfterDtor =
false;
711 MsanParamRetval =
false;
714 if (AllAddedKinds & SanitizerKind::MemTag) {
716 Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ,
"sync");
717 if (S ==
"async" || S ==
"sync") {
718 MemtagMode = S.str();
720 D.
Diag(clang::diag::err_drv_invalid_value_with_suggestion)
721 <<
"-fsanitize-memtag-mode=" << S <<
"{async, sync}";
726 if (AllAddedKinds & SanitizerKind::Thread) {
727 TsanMemoryAccess = Args.hasFlag(
728 options::OPT_fsanitize_thread_memory_access,
729 options::OPT_fno_sanitize_thread_memory_access, TsanMemoryAccess);
730 TsanFuncEntryExit = Args.hasFlag(
731 options::OPT_fsanitize_thread_func_entry_exit,
732 options::OPT_fno_sanitize_thread_func_entry_exit, TsanFuncEntryExit);
734 Args.hasFlag(options::OPT_fsanitize_thread_atomics,
735 options::OPT_fno_sanitize_thread_atomics, TsanAtomics);
738 if (AllAddedKinds & SanitizerKind::CFI) {
741 NeedPIE |= CfiCrossDso;
742 CfiICallGeneralizePointers =
743 Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
745 CfiICallNormalizeIntegers =
746 Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
748 if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
749 D.
Diag(diag::err_drv_argument_not_allowed_with)
750 <<
"-fsanitize-cfi-cross-dso"
751 <<
"-fsanitize-cfi-icall-generalize-pointers";
753 CfiCanonicalJumpTables =
754 Args.hasFlag(options::OPT_fsanitize_cfi_canonical_jump_tables,
755 options::OPT_fno_sanitize_cfi_canonical_jump_tables,
true);
758 if (AllAddedKinds & SanitizerKind::KCFI) {
759 CfiICallNormalizeIntegers =
760 Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
762 if (AllAddedKinds & SanitizerKind::CFI && DiagnoseErrors)
763 D.
Diag(diag::err_drv_argument_not_allowed_with)
768 Stats = Args.hasFlag(options::OPT_fsanitize_stats,
769 options::OPT_fno_sanitize_stats,
false);
771 if (MinimalRuntime) {
774 if (IncompatibleMask && DiagnoseErrors)
775 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
776 <<
"-fsanitize-minimal-runtime"
779 SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds;
780 if (NonTrappingCfi && DiagnoseErrors)
781 D.
Diag(clang::diag::err_drv_argument_only_allowed_with)
782 <<
"fsanitize-minimal-runtime"
783 <<
"fsanitize-trap=cfi";
788 for (
const auto *Arg : Args) {
789 if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
790 int LegacySanitizeCoverage;
791 if (Arg->getNumValues() == 1 &&
792 !StringRef(Arg->getValue(0))
793 .getAsInteger(0, LegacySanitizeCoverage)) {
794 CoverageFeatures = 0;
796 if (LegacySanitizeCoverage != 0 && DiagnoseErrors) {
797 D.
Diag(diag::warn_drv_deprecated_arg)
798 << Arg->getAsString(Args) <<
"-fsanitize-coverage=trace-pc-guard";
809 CoverageFeatures = 0;
811 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
813 CoverageFeatures &= ~parseCoverageFeatures(D, Arg, DiagnoseErrors);
817 if (DiagnoseErrors) {
819 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
820 <<
"-fsanitize-coverage=func"
821 <<
"-fsanitize-coverage=bb";
823 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
824 <<
"-fsanitize-coverage=func"
825 <<
"-fsanitize-coverage=edge";
827 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
828 <<
"-fsanitize-coverage=bb"
829 <<
"-fsanitize-coverage=edge";
833 D.
Diag(clang::diag::warn_drv_deprecated_arg)
834 <<
"-fsanitize-coverage=trace-bb"
835 <<
"-fsanitize-coverage=trace-pc-guard";
837 D.
Diag(clang::diag::warn_drv_deprecated_arg)
838 <<
"-fsanitize-coverage=8bit-counters"
839 <<
"-fsanitize-coverage=trace-pc-guard";
847 if ((CoverageFeatures & InsertionPointTypes) &&
848 !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) {
849 D.
Diag(clang::diag::warn_drv_deprecated_arg)
850 <<
"-fsanitize-coverage=[func|bb|edge]"
851 <<
"-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],["
856 if (!(CoverageFeatures & InsertionPointTypes)) {
857 if (CoverageFeatures &
870 if (CoverageFeatures) {
872 D, Args, CoverageAllowlistFiles,
873 options::OPT_fsanitize_coverage_allowlist, OptSpecifier(),
874 clang::diag::err_drv_malformed_sanitizer_coverage_allowlist,
877 D, Args, CoverageIgnorelistFiles,
878 options::OPT_fsanitize_coverage_ignorelist, OptSpecifier(),
879 clang::diag::err_drv_malformed_sanitizer_coverage_ignorelist,
884 for (
const auto *Arg :
885 Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ,
886 options::OPT_fno_experimental_sanitize_metadata_EQ)) {
887 if (Arg->getOption().matches(
888 options::OPT_fexperimental_sanitize_metadata_EQ)) {
890 BinaryMetadataFeatures |=
894 BinaryMetadataFeatures &=
895 ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
900 if (BinaryMetadataFeatures) {
902 D, Args, BinaryMetadataIgnorelistFiles,
903 options::OPT_fexperimental_sanitize_metadata_ignorelist_EQ,
905 clang::diag::err_drv_malformed_sanitizer_metadata_ignorelist,
910 Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
914 ImplicitCfiRuntime = TC.
getTriple().isAndroid();
916 if (AllAddedKinds & SanitizerKind::Address) {
919 Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
920 StringRef S = A->getValue();
922 if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
923 AsanFieldPadding > 2) &&
925 D.
Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
929 if (Arg *WindowsDebugRTArg =
930 Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
931 options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
932 options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
933 switch (WindowsDebugRTArg->getOption().getID()) {
934 case options::OPT__SLASH_MTd:
935 case options::OPT__SLASH_MDd:
936 case options::OPT__SLASH_LDd:
937 if (DiagnoseErrors) {
938 D.
Diag(clang::diag::err_drv_argument_not_allowed_with)
939 << WindowsDebugRTArg->getAsString(Args)
941 D.
Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
946 StableABI = Args.hasFlag(options::OPT_fsanitize_stable_abi,
947 options::OPT_fno_sanitize_stable_abi,
false);
949 AsanUseAfterScope = Args.hasFlag(
950 options::OPT_fsanitize_address_use_after_scope,
951 options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
953 AsanPoisonCustomArrayCookie = Args.hasFlag(
954 options::OPT_fsanitize_address_poison_custom_array_cookie,
955 options::OPT_fno_sanitize_address_poison_custom_array_cookie,
956 AsanPoisonCustomArrayCookie);
958 AsanOutlineInstrumentation =
959 Args.hasFlag(options::OPT_fsanitize_address_outline_instrumentation,
960 options::OPT_fno_sanitize_address_outline_instrumentation,
961 AsanOutlineInstrumentation);
963 AsanGlobalsDeadStripping = Args.hasFlag(
964 options::OPT_fsanitize_address_globals_dead_stripping,
965 options::OPT_fno_sanitize_address_globals_dead_stripping,
true);
971 AsanUseOdrIndicator =
972 Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator,
973 options::OPT_fno_sanitize_address_use_odr_indicator,
976 if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) {
977 AsanInvalidPointerCmp =
true;
980 if (AllAddedKinds & SanitizerKind::PointerSubtract & ~AllRemove) {
981 AsanInvalidPointerSub =
true;
985 (Args.hasArg(options::OPT_mkernel) ||
986 Args.hasArg(options::OPT_fapple_kext))) {
987 AsanDtorKind = llvm::AsanDtorKind::None;
990 if (
const auto *Arg =
991 Args.getLastArg(options::OPT_sanitize_address_destructor_EQ)) {
993 if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) {
994 TC.
getDriver().
Diag(clang::diag::err_drv_unsupported_option_argument)
995 << Arg->getSpelling() << Arg->getValue();
997 AsanDtorKind = parsedAsanDtorKind;
1000 if (
const auto *Arg = Args.getLastArg(
1001 options::OPT_sanitize_address_use_after_return_EQ)) {
1002 auto parsedAsanUseAfterReturn =
1004 if (parsedAsanUseAfterReturn ==
1005 llvm::AsanDetectStackUseAfterReturnMode::Invalid &&
1007 TC.
getDriver().
Diag(clang::diag::err_drv_unsupported_option_argument)
1008 << Arg->getSpelling() << Arg->getValue();
1010 AsanUseAfterReturn = parsedAsanUseAfterReturn;
1014 AsanUseAfterScope =
false;
1017 SanitizerKind::PointerCompare | SanitizerKind::PointerSubtract;
1018 if ((AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) &&
1020 TC.
getDriver().
Diag(clang::diag::err_drv_argument_only_allowed_with)
1022 SanitizerKind::PointerCompare |
1023 SanitizerKind::PointerSubtract)
1024 <<
"-fsanitize=address";
1028 if (AllAddedKinds & SanitizerKind::HWAddress) {
1029 if (Arg *HwasanAbiArg =
1030 Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) {
1031 HwasanAbi = HwasanAbiArg->getValue();
1032 if (HwasanAbi !=
"platform" && HwasanAbi !=
"interceptor" &&
1034 D.
Diag(clang::diag::err_drv_invalid_value)
1035 << HwasanAbiArg->getAsString(Args) << HwasanAbi;
1037 HwasanAbi =
"interceptor";
1039 if (TC.
getTriple().getArch() == llvm::Triple::x86_64)
1040 HwasanUseAliases = Args.hasFlag(
1041 options::OPT_fsanitize_hwaddress_experimental_aliasing,
1042 options::OPT_fno_sanitize_hwaddress_experimental_aliasing,
1046 if (AllAddedKinds & SanitizerKind::SafeStack) {
1053 Args.hasFlag(options::OPT_fsanitize_link_runtime,
1054 options::OPT_fno_sanitize_link_runtime, LinkRuntimes);
1057 LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime,
1058 options::OPT_fno_sanitize_link_cxx_runtime,
1062 NeedsMemProfRt = Args.hasFlag(options::OPT_fmemory_profile,
1063 options::OPT_fmemory_profile_EQ,
1064 options::OPT_fno_memory_profile,
false);
1067 Sanitizers.
Mask |= Kinds;
1068 RecoverableSanitizers.
Mask |= RecoverableKinds;
1069 TrapSanitizers.
Mask |= TrappingKinds;
1070 assert(!(RecoverableKinds & TrappingKinds) &&
1071 "Overlap between recoverable and trapping sanitizers");
1076#define SANITIZER(NAME, ID) \
1077 if (Sanitizers.has(SanitizerKind::ID)) { \
1082#include "clang/Basic/Sanitizers.def"
1087 llvm::opt::ArgStringList &CmdArgs,
1088 const char *SCLOptFlag,
1089 const std::vector<std::string> &SCLFiles) {
1090 for (
const auto &SCLPath : SCLFiles) {
1093 CmdArgs.push_back(Args.MakeArgString(SCLOpt));
1098 const llvm::opt::ArgList &Args,
1099 llvm::opt::ArgStringList &CmdArgs,
1100 StringRef SymbolName) {
1102 LinkerOptionFlag =
"--linker-option=/include:";
1103 if (TC.
getTriple().getArch() == llvm::Triple::x86) {
1105 LinkerOptionFlag +=
'_';
1107 LinkerOptionFlag += SymbolName;
1108 CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
1112 for (
auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End;
1114 auto It = std::find(Start, End, StringRef(
"+mte"));
1117 if (It > Start && *std::prev(It) == StringRef(
"-target-feature"))
1125 llvm::opt::ArgStringList &CmdArgs,
1133 bool GPUSanitize =
false;
1135 if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
1144 std::pair<int, const char *> CoverageFlags[] = {
1145 std::make_pair(
CoverageFunc,
"-fsanitize-coverage-type=1"),
1146 std::make_pair(
CoverageBB,
"-fsanitize-coverage-type=2"),
1147 std::make_pair(
CoverageEdge,
"-fsanitize-coverage-type=3"),
1156 "-fsanitize-coverage-trace-pc-guard"),
1158 "-fsanitize-coverage-inline-8bit-counters"),
1160 "-fsanitize-coverage-inline-bool-flag"),
1167 for (
auto F : CoverageFlags) {
1168 if (CoverageFeatures & F.first)
1169 CmdArgs.push_back(F.second);
1172 Args, CmdArgs,
"-fsanitize-coverage-allowlist=", CoverageAllowlistFiles);
1174 CoverageIgnorelistFiles);
1179 const std::pair<int, std::string> BinaryMetadataFlags[] = {
1183 for (
const auto &F : BinaryMetadataFlags) {
1184 if (BinaryMetadataFeatures & F.first)
1186 Args.MakeArgString(
"-fexperimental-sanitize-metadata=" + F.second));
1189 "-fexperimental-sanitize-metadata-ignorelist=",
1190 BinaryMetadataIgnorelistFiles);
1197 Args.MakeArgString(
"--dependent-lib=" +
1200 CmdArgs.push_back(Args.MakeArgString(
1201 "--dependent-lib=" +
1205 CmdArgs.push_back(Args.MakeArgString(
1212 CmdArgs.push_back(Args.MakeArgString(
1217 if (Sanitizers.
empty())
1219 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize=" +
toString(Sanitizers)));
1221 if (!RecoverableSanitizers.
empty())
1222 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-recover=" +
1225 if (!TrapSanitizers.
empty())
1227 Args.MakeArgString(
"-fsanitize-trap=" +
toString(TrapSanitizers)));
1230 "-fsanitize-ignorelist=", UserIgnorelistFiles);
1232 "-fsanitize-system-ignorelist=", SystemIgnorelistFiles);
1234 if (MsanTrackOrigins)
1235 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-memory-track-origins=" +
1236 Twine(MsanTrackOrigins)));
1238 if (MsanUseAfterDtor)
1239 CmdArgs.push_back(
"-fsanitize-memory-use-after-dtor");
1241 if (!MsanParamRetval)
1242 CmdArgs.push_back(
"-fno-sanitize-memory-param-retval");
1245 if (!TsanMemoryAccess) {
1246 CmdArgs.push_back(
"-mllvm");
1247 CmdArgs.push_back(
"-tsan-instrument-memory-accesses=0");
1248 CmdArgs.push_back(
"-mllvm");
1249 CmdArgs.push_back(
"-tsan-instrument-memintrinsics=0");
1251 if (!TsanFuncEntryExit) {
1252 CmdArgs.push_back(
"-mllvm");
1253 CmdArgs.push_back(
"-tsan-instrument-func-entry-exit=0");
1256 CmdArgs.push_back(
"-mllvm");
1257 CmdArgs.push_back(
"-tsan-instrument-atomics=0");
1260 if (HwasanUseAliases) {
1261 CmdArgs.push_back(
"-mllvm");
1262 CmdArgs.push_back(
"-hwasan-experimental-use-page-aliases=1");
1266 CmdArgs.push_back(
"-fsanitize-cfi-cross-dso");
1268 if (CfiICallGeneralizePointers)
1269 CmdArgs.push_back(
"-fsanitize-cfi-icall-generalize-pointers");
1271 if (CfiICallNormalizeIntegers)
1272 CmdArgs.push_back(
"-fsanitize-cfi-icall-experimental-normalize-integers");
1274 if (CfiCanonicalJumpTables)
1275 CmdArgs.push_back(
"-fsanitize-cfi-canonical-jump-tables");
1278 CmdArgs.push_back(
"-fsanitize-stats");
1281 CmdArgs.push_back(
"-fsanitize-minimal-runtime");
1283 if (AsanFieldPadding)
1284 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-address-field-padding=" +
1285 Twine(AsanFieldPadding)));
1287 if (AsanUseAfterScope)
1288 CmdArgs.push_back(
"-fsanitize-address-use-after-scope");
1290 if (AsanPoisonCustomArrayCookie)
1291 CmdArgs.push_back(
"-fsanitize-address-poison-custom-array-cookie");
1293 if (AsanGlobalsDeadStripping)
1294 CmdArgs.push_back(
"-fsanitize-address-globals-dead-stripping");
1296 if (!AsanUseOdrIndicator)
1297 CmdArgs.push_back(
"-fno-sanitize-address-use-odr-indicator");
1299 if (AsanInvalidPointerCmp) {
1300 CmdArgs.push_back(
"-mllvm");
1301 CmdArgs.push_back(
"-asan-detect-invalid-pointer-cmp");
1304 if (AsanInvalidPointerSub) {
1305 CmdArgs.push_back(
"-mllvm");
1306 CmdArgs.push_back(
"-asan-detect-invalid-pointer-sub");
1309 if (AsanOutlineInstrumentation) {
1310 CmdArgs.push_back(
"-mllvm");
1311 CmdArgs.push_back(
"-asan-instrumentation-with-call-threshold=0");
1318 CmdArgs.push_back(
"-mllvm");
1319 CmdArgs.push_back(
"-asan-instrumentation-with-call-threshold=0");
1320 CmdArgs.push_back(
"-mllvm");
1321 CmdArgs.push_back(
"-asan-max-inline-poisoning-size=0");
1322 CmdArgs.push_back(
"-mllvm");
1323 CmdArgs.push_back(
"-asan-guard-against-version-mismatch=0");
1328 if (AsanDtorKind != llvm::AsanDtorKind::Invalid) {
1329 CmdArgs.push_back(Args.MakeArgString(
"-fsanitize-address-destructor=" +
1333 if (AsanUseAfterReturn != llvm::AsanDetectStackUseAfterReturnMode::Invalid) {
1334 CmdArgs.push_back(Args.MakeArgString(
1335 "-fsanitize-address-use-after-return=" +
1339 if (!HwasanAbi.empty()) {
1340 CmdArgs.push_back(
"-default-function-attr");
1341 CmdArgs.push_back(Args.MakeArgString(
"hwasan-abi=" + HwasanAbi));
1344 if (Sanitizers.
has(SanitizerKind::HWAddress) && !HwasanUseAliases) {
1345 CmdArgs.push_back(
"-target-feature");
1346 CmdArgs.push_back(
"+tagged-globals");
1354 if (Sanitizers.
has(SanitizerKind::Memory) ||
1355 Sanitizers.
has(SanitizerKind::Address))
1356 CmdArgs.push_back(
"-fno-assume-sane-operator-new");
1363 if (Sanitizers.
has(SanitizerKind::FuzzerNoLink)) {
1364 CmdArgs.push_back(
"-fno-builtin-bcmp");
1365 CmdArgs.push_back(
"-fno-builtin-memcmp");
1366 CmdArgs.push_back(
"-fno-builtin-strncmp");
1367 CmdArgs.push_back(
"-fno-builtin-strcmp");
1368 CmdArgs.push_back(
"-fno-builtin-strncasecmp");
1369 CmdArgs.push_back(
"-fno-builtin-strcasecmp");
1370 CmdArgs.push_back(
"-fno-builtin-strstr");
1371 CmdArgs.push_back(
"-fno-builtin-strcasestr");
1372 CmdArgs.push_back(
"-fno-builtin-memmem");
1378 !Args.hasArg(options::OPT_fvisibility_EQ)) {
1379 TC.
getDriver().
Diag(clang::diag::err_drv_argument_only_allowed_with)
1385 if (Sanitizers.
has(SanitizerKind::MemtagStack) &&
1387 TC.
getDriver().
Diag(diag::err_stack_tagging_requires_hardware_feature);
1391 bool DiagnoseErrors) {
1392 assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
1393 A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
1394 A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
1395 A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
1396 A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
1397 A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
1398 "Invalid argument in parseArgValues!");
1400 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
1401 const char *
Value = A->getValue(i);
1404 if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
1405 0 == strcmp(
"all",
Value))
1412 else if (DiagnoseErrors)
1413 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
1414 << A->getSpelling() <<
Value;
1420 bool DiagnoseErrors) {
1421 assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
1422 A->getOption().matches(options::OPT_fno_sanitize_coverage));
1424 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
1425 const char *
Value = A->getValue(i);
1426 int F = llvm::StringSwitch<int>(
Value)
1447 if (F == 0 && DiagnoseErrors)
1448 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
1449 << A->getSpelling() <<
Value;
1456 bool DiagnoseErrors) {
1458 A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) ||
1459 A->getOption().matches(
1460 options::OPT_fno_experimental_sanitize_metadata_EQ));
1462 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
1463 const char *
Value = A->getValue(i);
1464 int F = llvm::StringSwitch<int>(
Value)
1470 if (F == 0 && DiagnoseErrors)
1471 D.
Diag(clang::diag::err_drv_unsupported_option_argument)
1472 << A->getSpelling() <<
Value;
1480 for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
1483 const auto *Arg = *I;
1484 if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
1487 if (AddKinds & Mask)
1489 }
else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
1492 Mask &= ~RemoveKinds;
1495 llvm_unreachable(
"arg list didn't provide expected value");
1499 assert(A->getOption().matches(options::OPT_fsanitize_EQ) &&
1500 "Invalid argument in describeSanitizerArg!");
1502 std::string Sanitizers;
1503 for (
int i = 0, n = A->getNumValues(); i != n; ++i) {
1507 if (!Sanitizers.empty())
1509 Sanitizers += A->getValue(i);
1513 assert(!Sanitizers.empty() &&
"arg didn't provide expected value");
1514 return "-fsanitize=" + Sanitizers;
static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, std::vector< std::string > &IgnorelistFiles, bool DiagnoseErrors)
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 SanitizerMask parseSanitizeTrapArgs(const Driver &D, const llvm::opt::ArgList &Args, bool DiagnoseErrors)
static void addIncludeLinkerOption(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, StringRef SymbolName)
static bool isExecuteOnlyTarget(const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Return true if an execute-only target disallows data access to code sections.
static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs)
static const SanitizerMask SupportsCoverage
static const SanitizerMask CFIClasses
static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors)
Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid components.
static const SanitizerMask TrappingSupported
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 const SanitizerMask NeedsUnwindTables
static const SanitizerMask RequiresPIE
static void addSpecialCaseListOpt(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const char *SCLOptFlag, const std::vector< std::string > &SCLFiles)
static const SanitizerMask NotAllowedWithMinimalRuntime
static const SanitizerMask AlwaysRecoverable
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...
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
static const SanitizerMask NeedsUbsanCxxRt
static const SanitizerMask TrappingDefault
static const SanitizerMask CompatibleWithMinimalRuntime
static const SanitizerMask Unrecoverable
static const SanitizerMask RecoverableByDefault
static const SanitizerMask NeedsLTO
static SanitizerMask setGroupBits(SanitizerMask Kinds)
Sets group bits for every group that has at least one representative already enabled in Kinds.
static const SanitizerMask NeedsUbsanRt
static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors)
Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid components.
static void validateSpecialCaseListFormat(const Driver &D, std::vector< std::string > &SCLFiles, unsigned MalformedSCLErrorDiagID, bool DiagnoseErrors)
static const SanitizerMask NotAllowedWithTrap
static void parseSpecialCaseListArg(const Driver &D, const llvm::opt::ArgList &Args, std::vector< std::string > &SCLFiles, llvm::opt::OptSpecifier SCLOptionID, llvm::opt::OptSpecifier NoSCLOptionID, unsigned MalformedSCLErrorDiagID, bool DiagnoseErrors)
Parse -f(no-)?sanitize-(coverage-)?(allow|ignore)list argument's values, diagnosing any invalid file ...
static const SanitizerMask NotAllowedWithExecuteOnly
@ CoverageInline8bitCounters
Defines the clang::SanitizerKind enum.
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
DiagnosticBuilder Diag(unsigned DiagID) const
std::string ResourceDir
The path to the compiler resource directory.
llvm::vfs::FileSystem & getVFS() const
bool isUsingLTO(bool IsOffload=false) const
Returns true if we are performing any kind of LTO.
bool CCCIsCXX() const
Whether the driver should follow g++ like behavior.
bool needsFuzzerInterceptors() const
bool needsStatsRt() const
bool needsCfiDiagRt() const
bool needsUbsanRt() const
SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, bool DiagnoseErrors=true)
Parses the sanitizer arguments from an argument list.
bool needsHwasanRt() const
bool requiresMinimalRuntime() const
bool needsUnwindTables() const
bool needsDfsanRt() const
bool needsScudoRt() const
void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const
bool isCXX(ID Id)
isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
StringRef AsanDtorKindToString(llvm::AsanDtorKind kind)
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds)
For each sanitizer group bit set in Kinds, set the bits for sanitizers this group enables.
SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups)
Parse a single value from a -fsanitize= or -fno-sanitize= value list.
llvm::AsanDtorKind AsanDtorKindFromString(StringRef kind)
llvm::AsanDetectStackUseAfterReturnMode AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr)
StringRef AsanDetectStackUseAfterReturnModeToString(llvm::AsanDetectStackUseAfterReturnMode mode)
bool empty() const
Returns true if no sanitizers are enabled.
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.
SanitizerMask Mask
Bitmask of enabled sanitizers.
bool hasOneOf(SanitizerMask K) const
Check if one or more sanitizers are enabled.