diff options
author | Alexey Samsonov <samsonov@google.com> | 2013-08-08 10:11:02 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2013-08-08 10:11:02 +0000 |
commit | 442c60a92b6e3980e0f69a195a264ec2ffa2dd6d (patch) | |
tree | 67e43a17a706be8fb9387978addabd0a5adde350 | |
parent | b26404a7505dab7ec3a16f6e3b85f95cfd59ba93 (diff) |
Move SanitizerArgs implementation from .h to .cpp
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187972 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Driver/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Driver/SanitizerArgs.cpp | 293 | ||||
-rw-r--r-- | lib/Driver/SanitizerArgs.h | 152 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 124 |
4 files changed, 308 insertions, 262 deletions
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index f380e50388..69d18adce1 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -6,6 +6,7 @@ add_clang_library(clangDriver DriverOptions.cpp Job.cpp Phases.cpp + SanitizerArgs.cpp Tool.cpp ToolChain.cpp ToolChains.cpp diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp new file mode 100644 index 0000000000..5d2ea89224 --- /dev/null +++ b/lib/Driver/SanitizerArgs.cpp @@ -0,0 +1,293 @@ +//===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "SanitizerArgs.h" + +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace llvm::opt; + +SanitizerArgs::SanitizerArgs() + : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), + AsanZeroBaseShadow(false), UbsanTrapOnError(false) {} + +SanitizerArgs::SanitizerArgs(const ToolChain &TC, + const llvm::opt::ArgList &Args) + : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), + AsanZeroBaseShadow(false) { + unsigned AllKinds = 0; // All kinds of sanitizers that were turned on + // at least once (possibly, disabled further). + const Driver &D = TC.getDriver(); + for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { + unsigned Add, Remove; + if (!parse(D, Args, *I, Add, Remove, true)) + continue; + (*I)->claim(); + Kind |= Add; + Kind &= ~Remove; + AllKinds |= Add; + } + + UbsanTrapOnError = + Args.hasArg(options::OPT_fcatch_undefined_behavior) || + Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, + options::OPT_fno_sanitize_undefined_trap_on_error, false); + + if (Args.hasArg(options::OPT_fcatch_undefined_behavior) && + !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, + options::OPT_fno_sanitize_undefined_trap_on_error, true)) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fcatch-undefined-behavior" + << "-fno-sanitize-undefined-trap-on-error"; + } + + // Warn about undefined sanitizer options that require runtime support. + if (UbsanTrapOnError && notAllowedWithTrap()) { + if (Args.hasArg(options::OPT_fcatch_undefined_behavior)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NotAllowedWithTrap) + << "-fcatch-undefined-behavior"; + else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, + options::OPT_fno_sanitize_undefined_trap_on_error, + false)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NotAllowedWithTrap) + << "-fsanitize-undefined-trap-on-error"; + } + + // Only one runtime library can be used at once. + bool NeedsAsan = needsAsanRt(); + bool NeedsTsan = needsTsanRt(); + bool NeedsMsan = needsMsanRt(); + bool NeedsLsan = needsLeakDetection(); + if (NeedsAsan && NeedsTsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsAsanRt) + << lastArgumentForKind(D, Args, NeedsTsanRt); + if (NeedsAsan && NeedsMsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsAsanRt) + << lastArgumentForKind(D, Args, NeedsMsanRt); + if (NeedsTsan && NeedsMsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsTsanRt) + << lastArgumentForKind(D, Args, NeedsMsanRt); + if (NeedsLsan && NeedsTsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsLeakDetection) + << lastArgumentForKind(D, Args, NeedsTsanRt); + if (NeedsLsan && NeedsMsan) + D.Diag(diag::err_drv_argument_not_allowed_with) + << lastArgumentForKind(D, Args, NeedsLeakDetection) + << lastArgumentForKind(D, Args, NeedsMsanRt); + // FIXME: Currenly -fsanitize=leak is silently ignored in the presence of + // -fsanitize=address. Perhaps it should print an error, or perhaps + // -f(-no)sanitize=leak should change whether leak detection is enabled by + // default in ASan? + + // If -fsanitize contains extra features of ASan, it should also + // explicitly contain -fsanitize=address (probably, turned off later in the + // command line). + if ((Kind & AddressFull) != 0 && (AllKinds & Address) == 0) + D.Diag(diag::warn_drv_unused_sanitizer) + << lastArgumentForKind(D, Args, AddressFull) + << "-fsanitize=address"; + + // Parse -f(no-)sanitize-blacklist options. + if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, + options::OPT_fno_sanitize_blacklist)) { + if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { + std::string BLPath = BLArg->getValue(); + if (llvm::sys::fs::exists(BLPath)) + BlacklistFile = BLPath; + else + D.Diag(diag::err_drv_no_such_file) << BLPath; + } + } else { + // If no -fsanitize-blacklist option is specified, try to look up for + // blacklist in the resource directory. + std::string BLPath; + if (getDefaultBlacklistForKind(D, Kind, BLPath) && + llvm::sys::fs::exists(BLPath)) + BlacklistFile = BLPath; + } + + // Parse -f(no-)sanitize-memory-track-origins options. + if (NeedsMsan) + MsanTrackOrigins = + Args.hasFlag(options::OPT_fsanitize_memory_track_origins, + options::OPT_fno_sanitize_memory_track_origins, + /* Default */false); + + // Parse -f(no-)sanitize-address-zero-base-shadow options. + if (NeedsAsan) { + bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android); + bool ZeroBaseShadowDefault = IsAndroid; + AsanZeroBaseShadow = + Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, + options::OPT_fno_sanitize_address_zero_base_shadow, + ZeroBaseShadowDefault); + // Zero-base shadow is a requirement on Android. + if (IsAndroid && !AsanZeroBaseShadow) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fno-sanitize-address-zero-base-shadow" + << lastArgumentForKind(D, Args, Address); + } + } +} + +void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (!Kind) + return; + SmallString<256> SanitizeOpt("-fsanitize="); +#define SANITIZER(NAME, ID) \ + if (Kind & ID) \ + SanitizeOpt += NAME ","; +#include "clang/Basic/Sanitizers.def" + SanitizeOpt.pop_back(); + CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); + if (!BlacklistFile.empty()) { + SmallString<64> BlacklistOpt("-fsanitize-blacklist="); + BlacklistOpt += BlacklistFile; + CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); + } + + if (MsanTrackOrigins) + CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins")); + + if (AsanZeroBaseShadow) + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-address-zero-base-shadow")); + + // Workaround for PR16386. + if (needsMsanRt()) + CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); +} + +unsigned SanitizerArgs::parse(const char *Value) { + unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) +#define SANITIZER(NAME, ID) .Case(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) +#include "clang/Basic/Sanitizers.def" + .Default(SanitizeKind()); + // Assume -fsanitize=address implies -fsanitize=init-order. + // FIXME: This should be either specified in Sanitizers.def, or go away when + // we get rid of "-fsanitize=init-order" flag at all. + if (ParsedKind & Address) + ParsedKind |= InitOrder; + return ParsedKind; +} + +unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors) { + unsigned Kind = 0; + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { + if (unsigned K = parse(A->getValue(I))) + Kind |= K; + else if (DiagnoseErrors) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(I); + } + return Kind; +} + +bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, unsigned &Add, + unsigned &Remove, bool DiagnoseErrors) { + Add = 0; + Remove = 0; + const char *DeprecatedReplacement = 0; + if (A->getOption().matches(options::OPT_faddress_sanitizer)) { + Add = Address; + DeprecatedReplacement = "-fsanitize=address"; + } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) { + Remove = Address; + DeprecatedReplacement = "-fno-sanitize=address"; + } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) { + Add = Thread; + DeprecatedReplacement = "-fsanitize=thread"; + } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) { + Remove = Thread; + DeprecatedReplacement = "-fno-sanitize=thread"; + } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) { + Add = UndefinedTrap; + DeprecatedReplacement = + "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error"; + } else if (A->getOption().matches(options::OPT_fbounds_checking) || + A->getOption().matches(options::OPT_fbounds_checking_EQ)) { + Add = Bounds; + DeprecatedReplacement = "-fsanitize=bounds"; + } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) { + Add = parse(D, A, DiagnoseErrors); + } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) { + Remove = parse(D, A, DiagnoseErrors); + } else { + // Flag is not relevant to sanitizers. + return false; + } + // If this is a deprecated synonym, produce a warning directing users + // towards the new spelling. + if (DeprecatedReplacement && DiagnoseErrors) + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) << DeprecatedReplacement; + return true; +} + +std::string SanitizerArgs::lastArgumentForKind(const Driver &D, + const llvm::opt::ArgList &Args, + unsigned Kind) { + for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), + E = Args.rend(); + I != E; ++I) { + unsigned Add, Remove; + if (parse(D, Args, *I, Add, Remove, false) && + (Add & Kind)) + return describeSanitizeArg(Args, *I, Kind); + Kind &= ~Remove; + } + llvm_unreachable("arg list didn't provide expected value"); +} + +std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, + unsigned Mask) { + if (!A->getOption().matches(options::OPT_fsanitize_EQ)) + return A->getAsString(Args); + + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) + if (parse(A->getValue(I)) & Mask) + return std::string("-fsanitize=") + A->getValue(I); + + llvm_unreachable("arg didn't provide expected value"); +} + +bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind, + std::string &BLPath) { + const char *BlacklistFile = 0; + if (Kind & NeedsAsanRt) + BlacklistFile = "asan_blacklist.txt"; + else if (Kind & NeedsMsanRt) + BlacklistFile = "msan_blacklist.txt"; + else if (Kind & NeedsTsanRt) + BlacklistFile = "tsan_blacklist.txt"; + if (BlacklistFile) { + SmallString<64> Path(D.ResourceDir); + llvm::sys::path::append(Path, BlacklistFile); + BLPath = Path.str(); + return true; + } + return false; +} diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h index 58dece9b56..e622d0010d 100644 --- a/lib/Driver/SanitizerArgs.h +++ b/lib/Driver/SanitizerArgs.h @@ -9,17 +9,17 @@ #ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_ #define CLANG_LIB_DRIVER_SANITIZERARGS_H_ -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Options.h" -#include "llvm/ADT/StringSwitch.h" +#include <string> + #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Path.h" namespace clang { namespace driver { +class Driver; +class ToolChain; + class SanitizerArgs { /// Assign ordinals to sanitizer flags. We'll use the ordinal values as /// bit positions within \c Kind. @@ -50,8 +50,7 @@ class SanitizerArgs { bool UbsanTrapOnError; public: - SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), - AsanZeroBaseShadow(false), UbsanTrapOnError(false) {} + SanitizerArgs(); /// Parses the sanitizer arguments from an argument list. SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args); @@ -63,9 +62,7 @@ class SanitizerArgs { return needsLeakDetection() && !needsAsanRt(); } bool needsUbsanRt() const { - if (UbsanTrapOnError) - return false; - return Kind & NeedsUbsanRt; + return !UbsanTrapOnError && (Kind & NeedsUbsanRt); } bool needsDfsanRt() const { return Kind & NeedsDfsanRt; } @@ -76,111 +73,25 @@ class SanitizerArgs { } void addArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { - if (!Kind) - return; - SmallString<256> SanitizeOpt("-fsanitize="); -#define SANITIZER(NAME, ID) \ - if (Kind & ID) \ - SanitizeOpt += NAME ","; -#include "clang/Basic/Sanitizers.def" - SanitizeOpt.pop_back(); - CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); - if (!BlacklistFile.empty()) { - SmallString<64> BlacklistOpt("-fsanitize-blacklist="); - BlacklistOpt += BlacklistFile; - CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); - } - - if (MsanTrackOrigins) - CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins")); - - if (AsanZeroBaseShadow) - CmdArgs.push_back( - Args.MakeArgString("-fsanitize-address-zero-base-shadow")); - - // Workaround for PR16386. - if (needsMsanRt()) - CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); - } + llvm::opt::ArgStringList &CmdArgs) const; private: /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0 /// if \p Value is not known. - static unsigned parse(const char *Value) { - unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value) -#define SANITIZER(NAME, ID) .Case(NAME, ID) -#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) -#include "clang/Basic/Sanitizers.def" - .Default(SanitizeKind()); - // Assume -fsanitize=address implies -fsanitize=init-order. - // FIXME: This should be either specified in Sanitizers.def, or go away when - // we get rid of "-fsanitize=init-order" flag at all. - if (ParsedKind & Address) - ParsedKind |= InitOrder; - return ParsedKind; - } + static unsigned parse(const char *Value); /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any /// invalid components. static unsigned parse(const Driver &D, const llvm::opt::Arg *A, - bool DiagnoseErrors) { - unsigned Kind = 0; - for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { - if (unsigned K = parse(A->getValue(I))) - Kind |= K; - else if (DiagnoseErrors) - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(I); - } - return Kind; - } + bool DiagnoseErrors); /// Parse a single flag of the form -f[no]sanitize=, or /// -f*-sanitizer. Sets the masks defining required change of Kind value. /// Returns true if the flag was parsed successfully. static bool parse(const Driver &D, const llvm::opt::ArgList &Args, const llvm::opt::Arg *A, unsigned &Add, unsigned &Remove, - bool DiagnoseErrors) { - Add = 0; - Remove = 0; - const char *DeprecatedReplacement = 0; - if (A->getOption().matches(options::OPT_faddress_sanitizer)) { - Add = Address; - DeprecatedReplacement = "-fsanitize=address"; - } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) { - Remove = Address; - DeprecatedReplacement = "-fno-sanitize=address"; - } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) { - Add = Thread; - DeprecatedReplacement = "-fsanitize=thread"; - } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) { - Remove = Thread; - DeprecatedReplacement = "-fno-sanitize=thread"; - } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) { - Add = UndefinedTrap; - DeprecatedReplacement = - "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error"; - } else if (A->getOption().matches(options::OPT_fbounds_checking) || - A->getOption().matches(options::OPT_fbounds_checking_EQ)) { - Add = Bounds; - DeprecatedReplacement = "-fsanitize=bounds"; - } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) { - Add = parse(D, A, DiagnoseErrors); - } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) { - Remove = parse(D, A, DiagnoseErrors); - } else { - // Flag is not relevant to sanitizers. - return false; - } - // If this is a deprecated synonym, produce a warning directing users - // towards the new spelling. - if (DeprecatedReplacement && DiagnoseErrors) - D.Diag(diag::warn_drv_deprecated_arg) - << A->getAsString(Args) << DeprecatedReplacement; - return true; - } + bool DiagnoseErrors); /// Produce an argument string from ArgList \p Args, which shows how it /// provides a sanitizer kind in \p Mask. For example, the argument list @@ -188,18 +99,7 @@ class SanitizerArgs { /// would produce "-fsanitize=vptr". static std::string lastArgumentForKind(const Driver &D, const llvm::opt::ArgList &Args, - unsigned Kind) { - for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(), - E = Args.rend(); - I != E; ++I) { - unsigned Add, Remove; - if (parse(D, Args, *I, Add, Remove, false) && - (Add & Kind)) - return describeSanitizeArg(Args, *I, Kind); - Kind &= ~Remove; - } - llvm_unreachable("arg list didn't provide expected value"); - } + unsigned Kind); /// Produce an argument string from argument \p A, which shows how it provides /// a value in \p Mask. For instance, the argument @@ -207,34 +107,10 @@ class SanitizerArgs { /// "-fsanitize=alignment". static std::string describeSanitizeArg(const llvm::opt::ArgList &Args, const llvm::opt::Arg *A, - unsigned Mask) { - if (!A->getOption().matches(options::OPT_fsanitize_EQ)) - return A->getAsString(Args); - - for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) - if (parse(A->getValue(I)) & Mask) - return std::string("-fsanitize=") + A->getValue(I); - - llvm_unreachable("arg didn't provide expected value"); - } + unsigned Mask); static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind, - std::string &BLPath) { - const char *BlacklistFile = 0; - if (Kind & NeedsAsanRt) - BlacklistFile = "asan_blacklist.txt"; - else if (Kind & NeedsMsanRt) - BlacklistFile = "msan_blacklist.txt"; - else if (Kind & NeedsTsanRt) - BlacklistFile = "tsan_blacklist.txt"; - if (BlacklistFile) { - SmallString<64> Path(D.ResourceDir); - llvm::sys::path::append(Path, BlacklistFile); - BLPath = Path.str(); - return true; - } - return false; - } + std::string &BLPath); }; } // namespace driver diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index ebfc3175f0..fb27bfde62 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1616,130 +1616,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } -SanitizerArgs::SanitizerArgs(const ToolChain &TC, const ArgList &Args) - : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), - AsanZeroBaseShadow(false) { - unsigned AllKinds = 0; // All kinds of sanitizers that were turned on - // at least once (possibly, disabled further). - const Driver &D = TC.getDriver(); - for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { - unsigned Add, Remove; - if (!parse(D, Args, *I, Add, Remove, true)) - continue; - (*I)->claim(); - Kind |= Add; - Kind &= ~Remove; - AllKinds |= Add; - } - - UbsanTrapOnError = - Args.hasArg(options::OPT_fcatch_undefined_behavior) || - Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, false); - - if (Args.hasArg(options::OPT_fcatch_undefined_behavior) && - !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, true)) { - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fcatch-undefined-behavior" - << "-fno-sanitize-undefined-trap-on-error"; - } - - // Warn about undefined sanitizer options that require runtime support. - if (UbsanTrapOnError && notAllowedWithTrap()) { - if (Args.hasArg(options::OPT_fcatch_undefined_behavior)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NotAllowedWithTrap) - << "-fcatch-undefined-behavior"; - else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, - false)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NotAllowedWithTrap) - << "-fsanitize-undefined-trap-on-error"; - } - - // Only one runtime library can be used at once. - bool NeedsAsan = needsAsanRt(); - bool NeedsTsan = needsTsanRt(); - bool NeedsMsan = needsMsanRt(); - bool NeedsLsan = needsLeakDetection(); - if (NeedsAsan && NeedsTsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsAsanRt) - << lastArgumentForKind(D, Args, NeedsTsanRt); - if (NeedsAsan && NeedsMsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsAsanRt) - << lastArgumentForKind(D, Args, NeedsMsanRt); - if (NeedsTsan && NeedsMsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsTsanRt) - << lastArgumentForKind(D, Args, NeedsMsanRt); - if (NeedsLsan && NeedsTsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsLeakDetection) - << lastArgumentForKind(D, Args, NeedsTsanRt); - if (NeedsLsan && NeedsMsan) - D.Diag(diag::err_drv_argument_not_allowed_with) - << lastArgumentForKind(D, Args, NeedsLeakDetection) - << lastArgumentForKind(D, Args, NeedsMsanRt); - // FIXME: Currenly -fsanitize=leak is silently ignored in the presence of - // -fsanitize=address. Perhaps it should print an error, or perhaps - // -f(-no)sanitize=leak should change whether leak detection is enabled by - // default in ASan? - - // If -fsanitize contains extra features of ASan, it should also - // explicitly contain -fsanitize=address (probably, turned off later in the - // command line). - if ((Kind & AddressFull) != 0 && (AllKinds & Address) == 0) - D.Diag(diag::warn_drv_unused_sanitizer) - << lastArgumentForKind(D, Args, AddressFull) - << "-fsanitize=address"; - - // Parse -f(no-)sanitize-blacklist options. - if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, - options::OPT_fno_sanitize_blacklist)) { - if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { - std::string BLPath = BLArg->getValue(); - if (llvm::sys::fs::exists(BLPath)) - BlacklistFile = BLPath; - else - D.Diag(diag::err_drv_no_such_file) << BLPath; - } - } else { - // If no -fsanitize-blacklist option is specified, try to look up for - // blacklist in the resource directory. - std::string BLPath; - if (getDefaultBlacklistForKind(D, Kind, BLPath) && - llvm::sys::fs::exists(BLPath)) - BlacklistFile = BLPath; - } - - // Parse -f(no-)sanitize-memory-track-origins options. - if (NeedsMsan) - MsanTrackOrigins = - Args.hasFlag(options::OPT_fsanitize_memory_track_origins, - options::OPT_fno_sanitize_memory_track_origins, - /* Default */false); - - // Parse -f(no-)sanitize-address-zero-base-shadow options. - if (NeedsAsan) { - bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android); - bool ZeroBaseShadowDefault = IsAndroid; - AsanZeroBaseShadow = - Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, - options::OPT_fno_sanitize_address_zero_base_shadow, - ZeroBaseShadowDefault); - // Zero-base shadow is a requirement on Android. - if (IsAndroid && !AsanZeroBaseShadow) { - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fno-sanitize-address-zero-base-shadow" - << lastArgumentForKind(D, Args, Address); - } - } -} - static void addProfileRTLinux( const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!(Args.hasArg(options::OPT_fprofile_arcs) || |