forked from OSchip/llvm-project
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
This commit is contained in:
parent
bdb2594cb3
commit
627b10f712
|
@ -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<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());
|
||||
}
|
||||
|
||||
/// 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_
|
|
@ -31,6 +31,8 @@
|
|||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
#include "SanitizerArgs.h"
|
||||
|
||||
#include <cstdlib> // ::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");
|
||||
|
||||
|
|
|
@ -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<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());
|
||||
}
|
||||
|
||||
/// 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())
|
||||
|
|
Loading…
Reference in New Issue