diff options
Diffstat (limited to 'clang/lib/Driver/SanitizerArgs.cpp')
-rw-r--r-- | clang/lib/Driver/SanitizerArgs.cpp | 129 |
1 files changed, 102 insertions, 27 deletions
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 68fe90c7a69d..52bee6a755ff 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -37,7 +37,8 @@ static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Function | SanitizerKind::Vptr; static const SanitizerMask RequiresPIE = - SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo; + SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo | + SanitizerKind::KCFI; static const SanitizerMask NeedsUnwindTables = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow; @@ -52,15 +53,16 @@ static const SanitizerMask SupportsCoverage = SanitizerKind::DataFlow | SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero | SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack | - SanitizerKind::Thread | SanitizerKind::ObjCCast; + SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI; static const SanitizerMask RecoverableByDefault = SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast; static const SanitizerMask Unrecoverable = SanitizerKind::Unreachable | SanitizerKind::Return; -static const SanitizerMask AlwaysRecoverable = - SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress; +static const SanitizerMask AlwaysRecoverable = SanitizerKind::KernelAddress | + SanitizerKind::KernelHWAddress | + SanitizerKind::KCFI; static const SanitizerMask NeedsLTO = SanitizerKind::CFI; static const SanitizerMask TrappingSupported = (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | SanitizerKind::Integer | @@ -96,6 +98,13 @@ enum CoverageFeature { CoverageInlineBoolFlag = 1 << 15, CoverageTraceLoads = 1 << 16, CoverageTraceStores = 1 << 17, + CoverageControlFlow = 1 << 18, +}; + +enum BinaryMetadataFeature { + BinaryMetadataCovered = 1 << 0, + BinaryMetadataAtomics = 1 << 1, + BinaryMetadataUAR = 1 << 2, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -108,6 +117,11 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors); +/// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid +/// components. Returns OR of members of \c BinaryMetadataFeature enumeration. +static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors); + /// Produce an argument string from ArgList \p Args, which shows how it /// provides some sanitizer kind from \p Mask. For example, the argument list /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt @@ -236,7 +250,7 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, SanitizerSet S; S.Mask = InvalidValues; D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(S); + << Arg->getSpelling() << toString(S); } TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { @@ -591,7 +605,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SetToDiagnose.Mask |= KindsToDiagnose; if (DiagnoseErrors) D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(SetToDiagnose); + << Arg->getSpelling() << toString(SetToDiagnose); DiagnosedUnrecoverableKinds |= KindsToDiagnose; } RecoverableKinds |= expandSanitizerGroups(Add); @@ -606,7 +620,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SetToDiagnose.Mask |= KindsToDiagnose; if (DiagnoseErrors) D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(SetToDiagnose); + << Arg->getSpelling() << toString(SetToDiagnose); DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; } RecoverableKinds &= ~expandSanitizerGroups(Remove); @@ -636,14 +650,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (AllAddedKinds & SanitizerKind::Memory) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, - options::OPT_fsanitize_memory_track_origins, options::OPT_fno_sanitize_memory_track_origins)) { - if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { - MsanTrackOrigins = 2; - } else if (A->getOption().matches( - options::OPT_fno_sanitize_memory_track_origins)) { - MsanTrackOrigins = 0; - } else { + if (!A->getOption().matches( + options::OPT_fno_sanitize_memory_track_origins)) { StringRef S = A->getValue(); if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || MsanTrackOrigins > 2) { @@ -712,6 +721,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, options::OPT_fno_sanitize_cfi_canonical_jump_tables, true); } + if (AllAddedKinds & SanitizerKind::KCFI && DiagnoseErrors) { + if (AllAddedKinds & SanitizerKind::CFI) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fsanitize=kcfi" + << lastArgumentForMask(D, Args, SanitizerKind::CFI); + } + Stats = Args.hasFlag(options::OPT_fsanitize_stats, options::OPT_fno_sanitize_stats, false); @@ -789,19 +805,21 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters | CoverageTraceLoads | - CoverageTraceStores | CoverageInlineBoolFlag; + CoverageTraceStores | CoverageInlineBoolFlag | + CoverageControlFlow; if ((CoverageFeatures & InsertionPointTypes) && !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) { D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=[func|bb|edge]" - << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; + << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],[" + "control-flow]"; } // trace-pc w/o func/bb/edge implies edge. if (!(CoverageFeatures & InsertionPointTypes)) { if (CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters | - CoverageInlineBoolFlag)) + CoverageInlineBoolFlag | CoverageControlFlow)) CoverageFeatures |= CoverageEdge; if (CoverageFeatures & CoverageStackDepth) @@ -825,6 +843,22 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, DiagnoseErrors); } + // Parse -f(no-)?sanitize-metadata. + for (const auto *Arg : + Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ, + options::OPT_fno_experimental_sanitize_metadata_EQ)) { + if (Arg->getOption().matches( + options::OPT_fexperimental_sanitize_metadata_EQ)) { + Arg->claim(); + BinaryMetadataFeatures |= + parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors); + } else { + Arg->claim(); + BinaryMetadataFeatures &= + ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors); + } + } + SharedRuntime = Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || @@ -885,10 +919,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || TC.getTriple().isPS()); + // Enable ODR indicators which allow better handling of mixed instrumented + // and uninstrumented globals. Disable them for Windows where weak odr + // indicators (.weak.__odr_asan_gen*) may cause multiple definition linker + // errors in the absence of -lldmingw. AsanUseOdrIndicator = Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator, options::OPT_fno_sanitize_address_use_odr_indicator, - AsanUseOdrIndicator); + !TC.getTriple().isOSWindows()); if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) { AsanInvalidPointerCmp = true; @@ -909,7 +947,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue()); if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << Arg->getValue(); + << Arg->getSpelling() << Arg->getValue(); } AsanDtorKind = parsedAsanDtorKind; } @@ -922,7 +960,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, llvm::AsanDetectStackUseAfterReturnMode::Invalid && DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << Arg->getValue(); + << Arg->getSpelling() << Arg->getValue(); } AsanUseAfterReturn = parsedAsanUseAfterReturn; } @@ -1076,7 +1114,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"), std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"), - std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores")}; + std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"), + std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(F.second); @@ -1086,6 +1125,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=", CoverageIgnorelistFiles); + // Translate available BinaryMetadataFeatures to corresponding clang-cc1 + // flags. Does not depend on any other sanitizers. + const std::pair<int, std::string> BinaryMetadataFlags[] = { + std::make_pair(BinaryMetadataCovered, "covered"), + std::make_pair(BinaryMetadataAtomics, "atomics"), + std::make_pair(BinaryMetadataUAR, "uar")}; + for (const auto &F : BinaryMetadataFlags) { + if (BinaryMetadataFeatures & F.first) + CmdArgs.push_back( + Args.MakeArgString("-fexperimental-sanitize-metadata=" + F.second)); + } + if (TC.getTriple().isOSWindows() && needsUbsanRt()) { // Instruct the code generator to embed linker directives in the object file // that cause the required runtime libraries to be linked. @@ -1134,8 +1185,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanUseAfterDtor) CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); - if (MsanParamRetval) - CmdArgs.push_back("-fsanitize-memory-param-retval"); + if (!MsanParamRetval) + CmdArgs.push_back("-fno-sanitize-memory-param-retval"); // FIXME: Pass these parameters as function attributes, not as -llvm flags. if (!TsanMemoryAccess) { @@ -1186,8 +1237,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (AsanGlobalsDeadStripping) CmdArgs.push_back("-fsanitize-address-globals-dead-stripping"); - if (AsanUseOdrIndicator) - CmdArgs.push_back("-fsanitize-address-use-odr-indicator"); + if (!AsanUseOdrIndicator) + CmdArgs.push_back("-fno-sanitize-address-use-odr-indicator"); if (AsanInvalidPointerCmp) { CmdArgs.push_back("-mllvm"); @@ -1292,7 +1343,7 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, Kinds |= Kind; else if (DiagnoseErrors) D.Diag(clang::diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } return Kinds; } @@ -1323,10 +1374,34 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, .Case("stack-depth", CoverageStackDepth) .Case("trace-loads", CoverageTraceLoads) .Case("trace-stores", CoverageTraceStores) + .Case("control-flow", CoverageControlFlow) + .Default(0); + if (F == 0 && DiagnoseErrors) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + Features |= F; + } + return Features; +} + +int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors) { + assert( + A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) || + A->getOption().matches( + options::OPT_fno_experimental_sanitize_metadata_EQ)); + int Features = 0; + for (int i = 0, n = A->getNumValues(); i != n; ++i) { + const char *Value = A->getValue(i); + int F = llvm::StringSwitch<int>(Value) + .Case("covered", BinaryMetadataCovered) + .Case("atomics", BinaryMetadataAtomics) + .Case("uar", BinaryMetadataUAR) + .Case("all", ~0) .Default(0); if (F == 0 && DiagnoseErrors) D.Diag(clang::diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; Features |= F; } return Features; |