From 627b10f712d3311ea9db356ab6aef4d77e65d177 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Tue, 6 Nov 2012 15:09:03 +0000 Subject: [PATCH] Follow-up for r167411 to un-break ASan on Mac. Move SanitizerArgs to a header file and use it on Darwin toolchain. llvm-svn: 167460 --- clang/lib/Driver/SanitizerArgs.h | 106 +++++++++++++++++++++++ clang/lib/Driver/ToolChains.cpp | 9 +- clang/lib/Driver/Tools.cpp | 139 ++++++------------------------- 3 files changed, 138 insertions(+), 116 deletions(-) create mode 100644 clang/lib/Driver/SanitizerArgs.h diff --git a/clang/lib/Driver/SanitizerArgs.h b/clang/lib/Driver/SanitizerArgs.h new file mode 100644 index 000000000000..ecb396ea06cf --- /dev/null +++ b/clang/lib/Driver/SanitizerArgs.h @@ -0,0 +1,106 @@ +//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_ +#define CLANG_LIB_DRIVER_SANITIZERARGS_H_ + +#include "clang/Driver/ArgList.h" + +namespace clang { +namespace driver { + +class SanitizerArgs { + /// Assign ordinals to sanitizer flags. We'll use the ordinal values as + /// bit positions within \c Kind. + enum SanitizeOrdinal { +#define SANITIZER(NAME, ID) SO_##ID, +#include "clang/Basic/Sanitizers.def" + SO_Count + }; + + /// Bugs to catch at runtime. + enum SanitizeKind { +#define SANITIZER(NAME, ID) ID = 1 << SO_##ID, +#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS, +#include "clang/Basic/Sanitizers.def" + NeedsAsanRt = Address, + NeedsTsanRt = Thread, + NeedsUbsanRt = Undefined + }; + unsigned Kind; + + public: + SanitizerArgs() : Kind(0) {} + /// Parses the sanitizer arguments from an argument list. + SanitizerArgs(const Driver &D, const ArgList &Args); + + bool needsAsanRt() const { return Kind & NeedsAsanRt; } + bool needsTsanRt() const { return Kind & NeedsTsanRt; } + bool needsUbsanRt() const { return Kind & NeedsUbsanRt; } + + bool sanitizesVptr() const { return Kind & Vptr; } + + void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + if (!Kind) + return; + llvm::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)); + } + + private: + /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. + /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value + /// is not known. + static unsigned parse(const char *Value) { + return llvm::StringSwitch(Value) +#define SANITIZER(NAME, ID) .Case(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) +#include "clang/Basic/Sanitizers.def" + .Default(SanitizeKind()); + } + + /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any + /// invalid components. + static unsigned parse(const Driver &D, const Arg *A) { + unsigned Kind = 0; + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { + if (unsigned K = parse(A->getValue(I))) + Kind |= K; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(I); + } + return Kind; + } + + /// Produce an argument string from argument \p A, which shows how it provides + /// a value in \p Mask. For instance, the argument + /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce + /// "-fsanitize=alignment". + static std::string describeSanitizeArg(const ArgList &Args, const 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"); + } +}; + +} // namespace driver +} // namespace clang + +#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_ diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp index 67258bc434b7..149b8a1f34c5 100644 --- a/clang/lib/Driver/ToolChains.cpp +++ b/clang/lib/Driver/ToolChains.cpp @@ -31,6 +31,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" +#include "SanitizerArgs.h" + #include // ::getenv #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX @@ -359,15 +361,16 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } + SanitizerArgs Sanitize(getDriver(), Args); + // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. - if (Args.hasFlag(options::OPT_faddress_sanitizer, - options::OPT_fno_address_sanitizer, false)) { + if (Sanitize.needsAsanRt()) { if (Args.hasArg(options::OPT_dynamiclib) || Args.hasArg(options::OPT_bundle)) return; if (isTargetIPhoneOS()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) - << "-faddress-sanitizer"; + << "-fsanitize=address"; } else { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a"); diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 973df104d52e..2eca3fe7b782 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/ErrorHandling.h" #include "InputInfo.h" +#include "SanitizerArgs.h" #include "ToolChains.h" using namespace clang::driver; @@ -1452,128 +1453,44 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -namespace { -struct SanitizerArgs { - /// Assign ordinals to sanitizer flags. We'll use the ordinal values as - /// bit positions within \c Kind. - enum SanitizeOrdinal { -#define SANITIZER(NAME, ID) SO_##ID, -#include "clang/Basic/Sanitizers.def" - SO_Count - }; - - /// Bugs to catch at runtime. - enum SanitizeKind { -#define SANITIZER(NAME, ID) ID = 1 << SO_##ID, -#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS, -#include "clang/Basic/Sanitizers.def" - - NeedsAsanRt = Address, - NeedsTsanRt = Thread, - NeedsUbsanRt = Undefined - }; - unsigned Kind; - - SanitizerArgs() : Kind(0) {} - - bool needsAsanRt() const { return Kind & NeedsAsanRt; } - bool needsTsanRt() const { return Kind & NeedsTsanRt; } - bool needsUbsanRt() const { return Kind & NeedsUbsanRt; } - - /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. - /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value - /// is not known. - static unsigned parse(const char *Value) { - return llvm::StringSwitch(Value) -#define SANITIZER(NAME, ID) .Case(NAME, ID) -#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) -#include "clang/Basic/Sanitizers.def" - .Default(SanitizeKind()); - } - - /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any - /// invalid components. - static unsigned parse(const Driver &D, const Arg *A) { - unsigned Kind = 0; - for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { - if (unsigned K = parse(A->getValue(I))) - Kind |= K; - else - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(I); - } - return Kind; - } - - void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (!Kind) - return; - llvm::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)); - } -}; -} - -/// Produce an argument string from argument \p A, which shows how it provides a -/// value in \p Mask. For instance, the argument "-fsanitize=address,alignment" -/// with mask \c NeedsUbsanRt would produce "-fsanitize=alignment". -static std::string describeSanitizeArg(const ArgList &Args, const 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 (SanitizerArgs::parse(A->getValue(I)) & Mask) - return std::string("-fsanitize=") + A->getValue(I); - - llvm_unreachable("arg didn't provide expected value"); -} - -/// Parse the sanitizer arguments from an argument list. -static SanitizerArgs getSanitizerArgs(const Driver &D, const ArgList &Args) { - SanitizerArgs Sanitize; +SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) { + Kind = 0; const Arg *AsanArg, *TsanArg, *UbsanArg; - for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { unsigned Add = 0, Remove = 0; const char *DeprecatedReplacement = 0; if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) { - Add = SanitizerArgs::Address; + Add = Address; DeprecatedReplacement = "-fsanitize=address"; } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) { - Remove = SanitizerArgs::Address; + Remove = Address; DeprecatedReplacement = "-fno-sanitize=address"; } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) { - Add = SanitizerArgs::Thread; + Add = Thread; DeprecatedReplacement = "-fsanitize=thread"; } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) { - Remove = SanitizerArgs::Thread; + Remove = Thread; DeprecatedReplacement = "-fno-sanitize=thread"; } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) { - Add = SanitizerArgs::Undefined; + Add = Undefined; DeprecatedReplacement = "-fsanitize=undefined"; } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) { - Add = SanitizerArgs::parse(D, *I); + Add = parse(D, *I); } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) { - Remove = SanitizerArgs::parse(D, *I); + Remove = parse(D, *I); } else { continue; } (*I)->claim(); - Sanitize.Kind |= Add; - Sanitize.Kind &= ~Remove; + Kind |= Add; + Kind &= ~Remove; - if (Add & SanitizerArgs::NeedsAsanRt) AsanArg = *I; - if (Add & SanitizerArgs::NeedsTsanRt) TsanArg = *I; - if (Add & SanitizerArgs::NeedsUbsanRt) UbsanArg = *I; + if (Add & NeedsAsanRt) AsanArg = *I; + if (Add & NeedsTsanRt) TsanArg = *I; + if (Add & NeedsUbsanRt) UbsanArg = *I; // If this is a deprecated synonym, produce a warning directing users // towards the new spelling. @@ -1584,19 +1501,15 @@ static SanitizerArgs getSanitizerArgs(const Driver &D, const ArgList &Args) { // Only one runtime library can be used at once. // FIXME: Allow Ubsan to be combined with the other two. - bool NeedsAsan = Sanitize.needsAsanRt(); - bool NeedsTsan = Sanitize.needsTsanRt(); - bool NeedsUbsan = Sanitize.needsUbsanRt(); + bool NeedsAsan = needsAsanRt(); + bool NeedsTsan = needsTsanRt(); + bool NeedsUbsan = needsUbsanRt(); if (NeedsAsan + NeedsTsan + NeedsUbsan > 1) D.Diag(diag::err_drv_argument_not_allowed_with) << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg, - NeedsAsan ? SanitizerArgs::NeedsAsanRt - : SanitizerArgs::NeedsTsanRt) + NeedsAsan ? NeedsAsanRt : NeedsTsanRt) << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg, - NeedsUbsan ? SanitizerArgs::NeedsUbsanRt - : SanitizerArgs::NeedsTsanRt); - - return Sanitize; + NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt); } /// If AddressSanitizer is enabled, add appropriate linker flags (Linux). @@ -2518,7 +2431,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); - SanitizerArgs Sanitize = getSanitizerArgs(D, Args); + SanitizerArgs Sanitize(D, Args); Sanitize.addArgs(Args, CmdArgs); // Report and error for -faltivec on anything other then PowerPC. @@ -2681,7 +2594,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-rtti"); // -fno-rtti cannot usefully be combined with -fsanitize=vptr. - if (Sanitize.Kind & SanitizerArgs::Vptr) { + if (Sanitize.sanitizesVptr()) { llvm::StringRef NoRttiArg = Args.getLastArg(options::OPT_mkernel, options::OPT_fapple_kext, @@ -4768,11 +4681,11 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - // If we're building a dynamic lib with -faddress-sanitizer, unresolved + SanitizerArgs Sanitize(getToolChain().getDriver(), Args); + // If we're building a dynamic lib with -fsanitize=address, unresolved // symbols may appear. Mark all of them as dynamic_lookup. // Linking executables is handled in lib/Driver/ToolChains.cpp. - if (Args.hasFlag(options::OPT_faddress_sanitizer, - options::OPT_fno_address_sanitizer, false)) { + if (Sanitize.needsAsanRt()) { if (Args.hasArg(options::OPT_dynamiclib) || Args.hasArg(options::OPT_bundle)) { CmdArgs.push_back("-undefined"); @@ -6116,7 +6029,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - SanitizerArgs Sanitize = getSanitizerArgs(D, Args); + SanitizerArgs Sanitize(D, Args); // Call this before we add the C++ ABI library. if (Sanitize.needsUbsanRt()) -- 2.34.1