2013-08-08 18:11:02 +08:00
|
|
|
//===--- 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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2013-08-19 17:14:21 +08:00
|
|
|
#include "clang/Driver/SanitizerArgs.h"
|
2015-05-12 05:39:20 +08:00
|
|
|
#include "clang/Basic/Sanitizers.h"
|
2013-08-08 18:11:02 +08:00
|
|
|
#include "clang/Driver/Driver.h"
|
|
|
|
#include "clang/Driver/DriverDiagnostic.h"
|
|
|
|
#include "clang/Driver/Options.h"
|
|
|
|
#include "clang/Driver/ToolChain.h"
|
2014-03-20 22:58:36 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2013-08-08 18:11:02 +08:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2014-07-10 03:40:08 +08:00
|
|
|
#include "llvm/Support/SpecialCaseList.h"
|
2014-03-09 19:36:40 +08:00
|
|
|
#include <memory>
|
2013-08-08 18:11:02 +08:00
|
|
|
|
2015-05-12 05:39:14 +08:00
|
|
|
using namespace clang;
|
|
|
|
using namespace clang::SanitizerKind;
|
2013-08-08 18:11:02 +08:00
|
|
|
using namespace clang::driver;
|
|
|
|
using namespace llvm::opt;
|
|
|
|
|
2015-05-12 05:39:14 +08:00
|
|
|
enum : SanitizerMask {
|
2015-06-19 09:51:54 +08:00
|
|
|
NeedsUbsanRt = Undefined | Integer | CFI,
|
2015-06-26 07:14:32 +08:00
|
|
|
NeedsUbsanCxxRt = Vptr | CFI,
|
2014-11-14 10:59:20 +08:00
|
|
|
NotAllowedWithTrap = Vptr,
|
2014-11-21 20:19:01 +08:00
|
|
|
RequiresPIE = Memory | DataFlow,
|
2015-01-06 09:02:48 +08:00
|
|
|
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
|
2015-03-20 08:06:52 +08:00
|
|
|
SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow,
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
RecoverableByDefault = Undefined | Integer,
|
|
|
|
Unrecoverable = Address | Unreachable | Return,
|
2015-02-21 04:30:56 +08:00
|
|
|
LegacyFsanitizeRecoverMask = Undefined | Integer,
|
2015-04-02 08:23:30 +08:00
|
|
|
NeedsLTO = CFI,
|
2015-06-19 07:59:22 +08:00
|
|
|
TrappingSupported =
|
2015-06-19 09:51:54 +08:00
|
|
|
(Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
|
|
|
|
TrappingDefault = CFI,
|
2014-11-14 10:59:20 +08:00
|
|
|
};
|
2015-05-08 06:34:06 +08:00
|
|
|
|
|
|
|
enum CoverageFeature {
|
|
|
|
CoverageFunc = 1 << 0,
|
|
|
|
CoverageBB = 1 << 1,
|
|
|
|
CoverageEdge = 1 << 2,
|
|
|
|
CoverageIndirCall = 1 << 3,
|
|
|
|
CoverageTraceBB = 1 << 4,
|
|
|
|
CoverageTraceCmp = 1 << 5,
|
|
|
|
Coverage8bitCounters = 1 << 6,
|
|
|
|
};
|
2014-11-14 10:59:20 +08:00
|
|
|
|
|
|
|
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
|
2015-05-12 05:39:14 +08:00
|
|
|
/// invalid components. Returns a SanitizerMask.
|
|
|
|
static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
|
|
|
|
bool DiagnoseErrors);
|
2014-11-14 10:59:20 +08:00
|
|
|
|
2015-05-08 06:34:06 +08:00
|
|
|
/// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid
|
|
|
|
/// components. Returns OR of members of \c CoverageFeature enumeration.
|
|
|
|
static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A);
|
|
|
|
|
2014-11-14 10:59:20 +08:00
|
|
|
/// 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
|
|
|
|
/// would produce "-fsanitize=vptr".
|
|
|
|
static std::string lastArgumentForMask(const Driver &D,
|
|
|
|
const llvm::opt::ArgList &Args,
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Mask);
|
2014-11-14 10:59:20 +08:00
|
|
|
|
|
|
|
/// 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".
|
2015-05-12 05:39:14 +08:00
|
|
|
static std::string describeSanitizeArg(const llvm::opt::Arg *A,
|
|
|
|
SanitizerMask Mask);
|
2014-11-14 10:59:20 +08:00
|
|
|
|
2014-11-17 04:53:53 +08:00
|
|
|
/// Produce a string containing comma-separated names of sanitizers in \p
|
|
|
|
/// Sanitizers set.
|
|
|
|
static std::string toString(const clang::SanitizerSet &Sanitizers);
|
|
|
|
|
2015-05-12 05:39:14 +08:00
|
|
|
static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
|
2015-03-21 02:45:06 +08:00
|
|
|
std::string &BLPath) {
|
|
|
|
const char *BlacklistFile = nullptr;
|
2015-05-12 05:39:14 +08:00
|
|
|
if (Kinds & Address)
|
2015-03-21 02:45:06 +08:00
|
|
|
BlacklistFile = "asan_blacklist.txt";
|
2015-05-12 05:39:14 +08:00
|
|
|
else if (Kinds & Memory)
|
2015-03-21 02:45:06 +08:00
|
|
|
BlacklistFile = "msan_blacklist.txt";
|
2015-05-12 05:39:14 +08:00
|
|
|
else if (Kinds & Thread)
|
2015-03-21 02:45:06 +08:00
|
|
|
BlacklistFile = "tsan_blacklist.txt";
|
2015-05-12 05:39:14 +08:00
|
|
|
else if (Kinds & DataFlow)
|
2015-03-21 02:45:06 +08:00
|
|
|
BlacklistFile = "dfsan_abilist.txt";
|
|
|
|
|
|
|
|
if (BlacklistFile) {
|
|
|
|
clang::SmallString<64> Path(D.ResourceDir);
|
|
|
|
llvm::sys::path::append(Path, BlacklistFile);
|
|
|
|
BLPath = Path.str();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-19 07:59:22 +08:00
|
|
|
/// Sets group bits for every group that has at least one representative already
|
|
|
|
/// enabled in \p Kinds.
|
|
|
|
static SanitizerMask setGroupBits(SanitizerMask Kinds) {
|
|
|
|
#define SANITIZER(NAME, ID)
|
|
|
|
#define SANITIZER_GROUP(NAME, ID, ALIAS) \
|
|
|
|
if (Kinds & SanitizerKind::ID) \
|
|
|
|
Kinds |= SanitizerKind::ID##Group;
|
|
|
|
#include "clang/Basic/Sanitizers.def"
|
|
|
|
return Kinds;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
|
|
|
|
const llvm::opt::ArgList &Args) {
|
|
|
|
SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of
|
|
|
|
// sanitizers disabled by the current sanitizer
|
|
|
|
// argument or any argument after it.
|
|
|
|
SanitizerMask TrappingKinds = 0;
|
|
|
|
SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported);
|
|
|
|
|
|
|
|
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
|
|
|
|
I != E; ++I) {
|
|
|
|
const auto *Arg = *I;
|
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) {
|
|
|
|
Arg->claim();
|
|
|
|
SanitizerMask Add = parseArgValues(D, Arg, true);
|
|
|
|
Add &= ~TrapRemove;
|
|
|
|
if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) {
|
|
|
|
SanitizerSet S;
|
|
|
|
S.Mask = InvalidValues;
|
|
|
|
D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap"
|
|
|
|
<< toString(S);
|
|
|
|
}
|
|
|
|
TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
|
|
|
|
Arg->claim();
|
|
|
|
TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true));
|
|
|
|
} else if (Arg->getOption().matches(
|
|
|
|
options::OPT_fsanitize_undefined_trap_on_error)) {
|
|
|
|
Arg->claim();
|
|
|
|
TrappingKinds |=
|
|
|
|
expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove;
|
|
|
|
} else if (Arg->getOption().matches(
|
|
|
|
options::OPT_fno_sanitize_undefined_trap_on_error)) {
|
|
|
|
Arg->claim();
|
|
|
|
TrapRemove |= expandSanitizerGroups(UndefinedGroup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-19 09:51:54 +08:00
|
|
|
// Apply default trapping behavior.
|
|
|
|
TrappingKinds |= TrappingDefault & ~TrapRemove;
|
|
|
|
|
2015-06-19 07:59:22 +08:00
|
|
|
return TrappingKinds;
|
|
|
|
}
|
|
|
|
|
2014-11-14 10:59:20 +08:00
|
|
|
bool SanitizerArgs::needsUbsanRt() const {
|
2015-06-19 07:59:22 +08:00
|
|
|
return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) &&
|
2015-05-12 05:39:14 +08:00
|
|
|
!Sanitizers.has(Address) &&
|
|
|
|
!Sanitizers.has(Memory) &&
|
|
|
|
!Sanitizers.has(Thread);
|
2014-11-14 10:59:20 +08:00
|
|
|
}
|
|
|
|
|
2014-11-21 20:19:01 +08:00
|
|
|
bool SanitizerArgs::requiresPIE() const {
|
2015-05-12 05:39:14 +08:00
|
|
|
return AsanZeroBaseShadow || (Sanitizers.Mask & RequiresPIE);
|
2014-11-14 10:59:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SanitizerArgs::needsUnwindTables() const {
|
2015-05-12 05:39:14 +08:00
|
|
|
return Sanitizers.Mask & NeedsUnwindTables;
|
2014-11-14 10:59:20 +08:00
|
|
|
}
|
|
|
|
|
2013-08-08 19:32:17 +08:00
|
|
|
void SanitizerArgs::clear() {
|
2014-11-14 10:59:20 +08:00
|
|
|
Sanitizers.clear();
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
RecoverableSanitizers.clear();
|
2015-06-19 07:59:22 +08:00
|
|
|
TrapSanitizers.clear();
|
2015-02-05 01:40:08 +08:00
|
|
|
BlacklistFiles.clear();
|
2015-05-08 06:34:06 +08:00
|
|
|
CoverageFeatures = 0;
|
2014-03-20 22:58:36 +08:00
|
|
|
MsanTrackOrigins = 0;
|
2014-10-10 01:53:04 +08:00
|
|
|
AsanFieldPadding = 0;
|
2013-11-02 02:16:25 +08:00
|
|
|
AsanZeroBaseShadow = false;
|
2014-04-01 21:31:10 +08:00
|
|
|
AsanSharedRuntime = false;
|
2014-08-09 06:47:17 +08:00
|
|
|
LinkCXXRuntimes = false;
|
2013-08-08 19:32:17 +08:00
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
|
|
|
const llvm::opt::ArgList &Args) {
|
2013-08-08 19:32:17 +08:00
|
|
|
clear();
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of
|
|
|
|
// sanitizers disabled by the current sanitizer
|
|
|
|
// argument or any argument after it.
|
2015-05-21 09:07:52 +08:00
|
|
|
SanitizerMask AllAddedKinds = 0; // Mask of all sanitizers ever enabled by
|
|
|
|
// -fsanitize= flags (directly or via group
|
|
|
|
// expansion), some of which may be disabled
|
|
|
|
// later. Used to carefully prune
|
|
|
|
// unused-argument diagnostics.
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now.
|
|
|
|
// Used to deduplicate diagnostics.
|
|
|
|
SanitizerMask Kinds = 0;
|
2015-06-26 07:14:32 +08:00
|
|
|
const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
|
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
const Driver &D = TC.getDriver();
|
2015-06-19 07:59:22 +08:00
|
|
|
SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
|
2015-06-20 05:36:47 +08:00
|
|
|
SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
|
2015-06-19 07:59:22 +08:00
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
|
|
|
|
I != E; ++I) {
|
2014-12-19 10:35:16 +08:00
|
|
|
const auto *Arg = *I;
|
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
|
|
|
|
Arg->claim();
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Add = parseArgValues(D, Arg, true);
|
2015-05-21 09:07:52 +08:00
|
|
|
AllAddedKinds |= expandSanitizerGroups(Add);
|
2014-12-19 10:35:16 +08:00
|
|
|
|
|
|
|
// Avoid diagnosing any sanitizer which is disabled later.
|
|
|
|
Add &= ~AllRemove;
|
|
|
|
// At this point we have not expanded groups, so any unsupported
|
|
|
|
// sanitizers in Add are those which have been explicitly enabled.
|
|
|
|
// Diagnose them.
|
2015-05-12 05:39:14 +08:00
|
|
|
if (SanitizerMask KindsToDiagnose =
|
2015-06-20 05:36:47 +08:00
|
|
|
Add & InvalidTrappingKinds & ~DiagnosedKinds) {
|
2015-06-19 07:59:22 +08:00
|
|
|
std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
|
|
|
|
D.Diag(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< Desc << "-fsanitize-trap=undefined";
|
|
|
|
DiagnosedKinds |= KindsToDiagnose;
|
|
|
|
}
|
2015-06-20 05:36:47 +08:00
|
|
|
Add &= ~InvalidTrappingKinds;
|
|
|
|
if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
|
2014-12-19 10:35:16 +08:00
|
|
|
std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
|
|
|
|
D.Diag(diag::err_drv_unsupported_opt_for_target)
|
|
|
|
<< Desc << TC.getTriple().str();
|
|
|
|
DiagnosedKinds |= KindsToDiagnose;
|
|
|
|
}
|
2015-06-20 05:36:47 +08:00
|
|
|
Add &= Supported;
|
2014-12-19 10:35:16 +08:00
|
|
|
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
// Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups
|
|
|
|
// so we don't error out if -fno-rtti and -fsanitize=undefined were
|
|
|
|
// passed.
|
2015-05-12 05:39:14 +08:00
|
|
|
if (Add & Vptr &&
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
(RTTIMode == ToolChain::RM_DisabledImplicitly ||
|
|
|
|
RTTIMode == ToolChain::RM_DisabledExplicitly)) {
|
|
|
|
if (RTTIMode == ToolChain::RM_DisabledImplicitly)
|
|
|
|
// Warn about not having rtti enabled if the vptr sanitizer is
|
|
|
|
// explicitly enabled
|
|
|
|
D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
|
|
|
|
else {
|
|
|
|
const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg();
|
|
|
|
assert(NoRTTIArg &&
|
|
|
|
"RTTI disabled explicitly but we have no argument!");
|
|
|
|
D.Diag(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Take out the Vptr sanitizer from the enabled sanitizers
|
2015-05-12 05:39:14 +08:00
|
|
|
AllRemove |= Vptr;
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
}
|
|
|
|
|
2015-05-12 05:39:20 +08:00
|
|
|
Add = expandSanitizerGroups(Add);
|
2014-12-19 10:35:16 +08:00
|
|
|
// Group expansion may have enabled a sanitizer which is disabled later.
|
|
|
|
Add &= ~AllRemove;
|
|
|
|
// Silently discard any unsupported sanitizers implicitly enabled through
|
|
|
|
// group expansion.
|
2015-06-20 05:36:47 +08:00
|
|
|
Add &= ~InvalidTrappingKinds;
|
|
|
|
Add &= Supported;
|
2014-12-19 10:35:16 +08:00
|
|
|
|
|
|
|
Kinds |= Add;
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
|
|
|
|
Arg->claim();
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Remove = parseArgValues(D, Arg, true);
|
2015-05-12 05:39:20 +08:00
|
|
|
AllRemove |= expandSanitizerGroups(Remove);
|
2014-11-17 04:53:53 +08:00
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
2014-11-17 04:53:53 +08:00
|
|
|
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
// We disable the vptr sanitizer if it was enabled by group expansion but RTTI
|
|
|
|
// is disabled.
|
2015-05-12 05:39:14 +08:00
|
|
|
if ((Kinds & Vptr) &&
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
(RTTIMode == ToolChain::RM_DisabledImplicitly ||
|
|
|
|
RTTIMode == ToolChain::RM_DisabledExplicitly)) {
|
2015-05-12 05:39:14 +08:00
|
|
|
Kinds &= ~Vptr;
|
Improve our handling of rtti/sanitize=vptr/sanitize=undefined
This patch removes the huge blob of code that is dealing with
rtti/exceptions/sanitizers and replaces it with:
A ToolChain function which, for a given set of Args, figures out if rtti
should be:
- enabled
- disabled implicitly
- disabled explicitly
A change in the way SanitizerArgs figures out what sanitizers to enable
(or if it should error out, or warn);
And a check for exceptions/rtti interaction inside addExceptionArgs.
The RTTIMode algorithm is:
- If -mkernel, -fapple-kext, or -fno-rtti are passed, rtti was disabled explicitly;
- If -frtti was passed or we're not targetting the PS4, rtti is enabled;
- If -fexceptions or -fcxx-exceptions was passed and we're targetting
the PS4, rtti was enabled implicitly;
- If we're targetting the PS4, rtti is disabled implicitly;
- Otherwise, rtti is enabled;
Since the only flag needed to pass to -cc1 is -fno-rtti if we want to
disable it, there's no problem in saying rtti is enabled if we're
compiling C code, so we don't look at the input file type.
addExceptionArgs now looks at the RTTIMode and warns that rtti is being
enabled implicitly if targetting the PS4 and exceptions are on. It also
errors out if, targetting the PS4, -fno-rtti was passed, and exceptions
were turned on.
SanitizerArgs now errors out if rtti was disabled explicitly and the vptr
sanitizer was enabled implicitly, but just turns off vptr if rtti is
disabled but -fsanitize=undefined was passed.
Also fixed tests, removed duplicate name from addExceptionArgs comment,
and added one or two surrounding lines when running clang-format.
This changes test/Driver/fsanitize.c to make it not expect a warning when
passed -fsanitize=undefined -fno-rtti, but expect vptr to not be on.
Removed all users and definition of SanitizerArgs::sanitizesVptr().
Reviewers: samsonov
Subscribers: llvm-commits, samsonov, rsmith
Differential Revision: http://reviews.llvm.org/D7525
llvm-svn: 229801
2015-02-19 09:04:49 +08:00
|
|
|
}
|
|
|
|
|
2015-06-20 03:57:46 +08:00
|
|
|
// Check that LTO is enabled if we need it.
|
|
|
|
if ((Kinds & NeedsLTO) && !D.IsUsingLTO(Args)) {
|
|
|
|
D.Diag(diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
|
|
|
|
}
|
|
|
|
|
2015-06-26 07:14:32 +08:00
|
|
|
// Report error if there are non-trapping sanitizers that require
|
|
|
|
// c++abi-specific parts of UBSan runtime, and they are not provided by the
|
|
|
|
// toolchain. We don't have a good way to check the latter, so we just
|
|
|
|
// check if the toolchan supports vptr.
|
|
|
|
if (~Supported & Vptr) {
|
|
|
|
if (SanitizerMask KindsToDiagnose =
|
|
|
|
Kinds & ~TrappingKinds & NeedsUbsanCxxRt) {
|
|
|
|
SanitizerSet S;
|
|
|
|
S.Mask = KindsToDiagnose;
|
|
|
|
D.Diag(diag::err_drv_unsupported_opt_for_target)
|
|
|
|
<< ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str();
|
|
|
|
Kinds &= ~KindsToDiagnose;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-21 02:45:06 +08:00
|
|
|
// Warn about incompatible groups of sanitizers.
|
2015-05-12 05:39:14 +08:00
|
|
|
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
|
|
|
|
std::make_pair(Address, Thread), std::make_pair(Address, Memory),
|
|
|
|
std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
|
2015-06-19 20:19:07 +08:00
|
|
|
std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
|
|
|
|
std::make_pair(KernelAddress, Leak),
|
|
|
|
std::make_pair(KernelAddress, Thread),
|
|
|
|
std::make_pair(KernelAddress, Memory)};
|
2015-03-21 02:45:06 +08:00
|
|
|
for (auto G : IncompatibleGroups) {
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Group = G.first;
|
2015-03-21 02:45:06 +08:00
|
|
|
if (Kinds & Group) {
|
2015-05-12 05:39:14 +08:00
|
|
|
if (SanitizerMask Incompatible = Kinds & G.second) {
|
2015-03-21 02:45:06 +08:00
|
|
|
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< lastArgumentForMask(D, Args, Group)
|
|
|
|
<< lastArgumentForMask(D, Args, Incompatible);
|
|
|
|
Kinds &= ~Incompatible;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// FIXME: Currently -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?
|
|
|
|
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
// Parse -f(no-)?sanitize-recover flags.
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask RecoverableKinds = RecoverableByDefault;
|
|
|
|
SanitizerMask DiagnosedUnrecoverableKinds = 0;
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
for (const auto *Arg : Args) {
|
2015-03-12 07:34:25 +08:00
|
|
|
const char *DeprecatedReplacement = nullptr;
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
|
2015-03-12 07:34:25 +08:00
|
|
|
DeprecatedReplacement = "-fsanitize-recover=undefined,integer";
|
2015-05-12 05:39:20 +08:00
|
|
|
RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask);
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
Arg->claim();
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
|
2015-03-12 07:34:25 +08:00
|
|
|
DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer";
|
2015-05-12 05:39:20 +08:00
|
|
|
RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask);
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
Arg->claim();
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Add = parseArgValues(D, Arg, true);
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
// Report error if user explicitly tries to recover from unrecoverable
|
|
|
|
// sanitizer.
|
2015-05-12 05:39:14 +08:00
|
|
|
if (SanitizerMask KindsToDiagnose =
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
|
|
|
|
SanitizerSet SetToDiagnose;
|
2015-05-12 05:39:14 +08:00
|
|
|
SetToDiagnose.Mask |= KindsToDiagnose;
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
D.Diag(diag::err_drv_unsupported_option_argument)
|
|
|
|
<< Arg->getOption().getName() << toString(SetToDiagnose);
|
|
|
|
DiagnosedUnrecoverableKinds |= KindsToDiagnose;
|
|
|
|
}
|
2015-05-12 05:39:20 +08:00
|
|
|
RecoverableKinds |= expandSanitizerGroups(Add);
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
Arg->claim();
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
|
2015-05-12 05:39:20 +08:00
|
|
|
RecoverableKinds &= ~expandSanitizerGroups(parseArgValues(D, Arg, true));
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
Arg->claim();
|
|
|
|
}
|
2015-03-12 07:34:25 +08:00
|
|
|
if (DeprecatedReplacement) {
|
|
|
|
D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
|
|
|
|
<< DeprecatedReplacement;
|
|
|
|
}
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
}
|
|
|
|
RecoverableKinds &= Kinds;
|
|
|
|
RecoverableKinds &= ~Unrecoverable;
|
2013-08-08 18:11:02 +08:00
|
|
|
|
2015-06-19 07:59:22 +08:00
|
|
|
TrappingKinds &= Kinds;
|
|
|
|
|
2015-02-05 01:40:08 +08:00
|
|
|
// Setup blacklist files.
|
|
|
|
// Add default blacklist from resource directory.
|
|
|
|
{
|
|
|
|
std::string BLPath;
|
2015-03-21 02:45:06 +08:00
|
|
|
if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath))
|
2015-02-05 01:40:08 +08:00
|
|
|
BlacklistFiles.push_back(BLPath);
|
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
// Parse -f(no-)sanitize-blacklist options.
|
2015-02-05 01:40:08 +08:00
|
|
|
for (const auto *Arg : Args) {
|
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
|
|
|
|
Arg->claim();
|
|
|
|
std::string BLPath = Arg->getValue();
|
|
|
|
if (llvm::sys::fs::exists(BLPath))
|
|
|
|
BlacklistFiles.push_back(BLPath);
|
|
|
|
else
|
2014-11-14 10:59:20 +08:00
|
|
|
D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
|
2015-02-05 01:40:08 +08:00
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
|
|
|
|
Arg->claim();
|
|
|
|
BlacklistFiles.clear();
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
2015-02-05 01:40:08 +08:00
|
|
|
}
|
|
|
|
// Validate blacklists format.
|
|
|
|
{
|
|
|
|
std::string BLError;
|
|
|
|
std::unique_ptr<llvm::SpecialCaseList> SCL(
|
|
|
|
llvm::SpecialCaseList::create(BlacklistFiles, BLError));
|
|
|
|
if (!SCL.get())
|
|
|
|
D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
2014-03-20 22:58:36 +08:00
|
|
|
// Parse -f[no-]sanitize-memory-track-origins[=level] options.
|
2015-05-21 09:07:52 +08:00
|
|
|
if (AllAddedKinds & Memory) {
|
2014-03-20 22:58:36 +08:00
|
|
|
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)) {
|
2015-02-26 23:59:30 +08:00
|
|
|
MsanTrackOrigins = 2;
|
2014-03-20 22:58:36 +08:00
|
|
|
} else if (A->getOption().matches(
|
|
|
|
options::OPT_fno_sanitize_memory_track_origins)) {
|
|
|
|
MsanTrackOrigins = 0;
|
|
|
|
} else {
|
|
|
|
StringRef S = A->getValue();
|
|
|
|
if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
|
|
|
|
MsanTrackOrigins > 2) {
|
2015-04-14 04:03:03 +08:00
|
|
|
D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
|
2014-03-20 22:58:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-08 06:34:06 +08:00
|
|
|
// Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
|
|
|
|
// enabled sanitizers.
|
2015-05-21 09:07:52 +08:00
|
|
|
if (AllAddedKinds & SupportsCoverage) {
|
2015-05-08 06:34:06 +08:00
|
|
|
for (const auto *Arg : Args) {
|
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
|
|
|
|
Arg->claim();
|
|
|
|
int LegacySanitizeCoverage;
|
|
|
|
if (Arg->getNumValues() == 1 &&
|
|
|
|
!StringRef(Arg->getValue(0))
|
|
|
|
.getAsInteger(0, LegacySanitizeCoverage) &&
|
|
|
|
LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
|
|
|
|
// TODO: Add deprecation notice for this form.
|
|
|
|
switch (LegacySanitizeCoverage) {
|
|
|
|
case 0:
|
|
|
|
CoverageFeatures = 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
CoverageFeatures = CoverageFunc;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
CoverageFeatures = CoverageBB;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
CoverageFeatures = CoverageEdge;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
CoverageFeatures = CoverageEdge | CoverageIndirCall;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
CoverageFeatures |= parseCoverageFeatures(D, Arg);
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) {
|
|
|
|
Arg->claim();
|
|
|
|
CoverageFeatures &= ~parseCoverageFeatures(D, Arg);
|
|
|
|
}
|
2014-11-12 06:15:07 +08:00
|
|
|
}
|
|
|
|
}
|
2015-05-08 06:34:06 +08:00
|
|
|
// Choose at most one coverage type: function, bb, or edge.
|
|
|
|
if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB))
|
|
|
|
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize-coverage=func"
|
|
|
|
<< "-fsanitize-coverage=bb";
|
|
|
|
if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge))
|
|
|
|
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize-coverage=func"
|
|
|
|
<< "-fsanitize-coverage=edge";
|
|
|
|
if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge))
|
|
|
|
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize-coverage=bb"
|
|
|
|
<< "-fsanitize-coverage=edge";
|
|
|
|
// Basic block tracing and 8-bit counters require some type of coverage
|
|
|
|
// enabled.
|
|
|
|
int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge;
|
|
|
|
if ((CoverageFeatures & CoverageTraceBB) &&
|
|
|
|
!(CoverageFeatures & CoverageTypes))
|
|
|
|
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< "-fsanitize-coverage=trace-bb"
|
|
|
|
<< "-fsanitize-coverage=(func|bb|edge)";
|
|
|
|
if ((CoverageFeatures & Coverage8bitCounters) &&
|
|
|
|
!(CoverageFeatures & CoverageTypes))
|
|
|
|
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< "-fsanitize-coverage=8bit-counters"
|
|
|
|
<< "-fsanitize-coverage=(func|bb|edge)";
|
2014-11-12 06:15:07 +08:00
|
|
|
|
2015-05-21 09:07:52 +08:00
|
|
|
if (AllAddedKinds & Address) {
|
2014-04-01 21:31:10 +08:00
|
|
|
AsanSharedRuntime =
|
2014-06-05 19:14:00 +08:00
|
|
|
Args.hasArg(options::OPT_shared_libasan) ||
|
|
|
|
(TC.getTriple().getEnvironment() == llvm::Triple::Android);
|
2013-11-02 02:16:25 +08:00
|
|
|
AsanZeroBaseShadow =
|
2014-01-16 18:19:31 +08:00
|
|
|
(TC.getTriple().getEnvironment() == llvm::Triple::Android);
|
2014-10-10 01:53:04 +08:00
|
|
|
if (Arg *A =
|
|
|
|
Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
|
|
|
|
StringRef S = A->getValue();
|
|
|
|
// Legal values are 0 and 1, 2, but in future we may add more levels.
|
|
|
|
if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
|
|
|
|
AsanFieldPadding > 2) {
|
2014-11-14 10:59:20 +08:00
|
|
|
D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
|
2014-10-10 01:53:04 +08:00
|
|
|
}
|
|
|
|
}
|
2014-10-15 07:15:44 +08:00
|
|
|
|
|
|
|
if (Arg *WindowsDebugRTArg =
|
|
|
|
Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT,
|
|
|
|
options::OPT__SLASH_MDd, options::OPT__SLASH_MD,
|
|
|
|
options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) {
|
|
|
|
switch (WindowsDebugRTArg->getOption().getID()) {
|
|
|
|
case options::OPT__SLASH_MTd:
|
|
|
|
case options::OPT__SLASH_MDd:
|
|
|
|
case options::OPT__SLASH_LDd:
|
2014-11-14 10:59:20 +08:00
|
|
|
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
|
2014-10-15 07:15:44 +08:00
|
|
|
<< WindowsDebugRTArg->getAsString(Args)
|
2015-05-12 05:39:14 +08:00
|
|
|
<< lastArgumentForMask(D, Args, Address);
|
2014-11-14 10:59:20 +08:00
|
|
|
D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
|
2014-10-15 07:15:44 +08:00
|
|
|
}
|
|
|
|
}
|
2014-04-01 21:31:10 +08:00
|
|
|
}
|
2014-08-09 06:47:17 +08:00
|
|
|
|
|
|
|
// Parse -link-cxx-sanitizer flag.
|
|
|
|
LinkCXXRuntimes =
|
|
|
|
Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
|
2015-03-21 02:45:06 +08:00
|
|
|
|
|
|
|
// Finally, initialize the set of available and recoverable sanitizers.
|
2015-05-12 05:39:14 +08:00
|
|
|
Sanitizers.Mask |= Kinds;
|
|
|
|
RecoverableSanitizers.Mask |= RecoverableKinds;
|
2015-06-19 07:59:22 +08:00
|
|
|
TrapSanitizers.Mask |= TrappingKinds;
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
2014-11-17 04:53:53 +08:00
|
|
|
static std::string toString(const clang::SanitizerSet &Sanitizers) {
|
|
|
|
std::string Res;
|
|
|
|
#define SANITIZER(NAME, ID) \
|
2015-05-12 05:39:14 +08:00
|
|
|
if (Sanitizers.has(ID)) { \
|
2014-11-17 04:53:53 +08:00
|
|
|
if (!Res.empty()) \
|
|
|
|
Res += ","; \
|
|
|
|
Res += NAME; \
|
|
|
|
}
|
|
|
|
#include "clang/Basic/Sanitizers.def"
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
|
2013-08-08 18:11:02 +08:00
|
|
|
llvm::opt::ArgStringList &CmdArgs) const {
|
2014-11-14 10:59:20 +08:00
|
|
|
if (Sanitizers.empty())
|
2013-08-08 18:11:02 +08:00
|
|
|
return;
|
2014-11-17 04:53:53 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
|
|
|
|
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
if (!RecoverableSanitizers.empty())
|
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
|
|
|
|
toString(RecoverableSanitizers)));
|
2014-11-17 04:53:53 +08:00
|
|
|
|
2015-06-19 07:59:22 +08:00
|
|
|
if (!TrapSanitizers.empty())
|
|
|
|
CmdArgs.push_back(
|
|
|
|
Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
|
2014-11-17 04:53:53 +08:00
|
|
|
|
2015-02-05 01:40:08 +08:00
|
|
|
for (const auto &BLPath : BlacklistFiles) {
|
2013-08-08 18:11:02 +08:00
|
|
|
SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
|
2015-02-05 01:40:08 +08:00
|
|
|
BlacklistOpt += BLPath;
|
2013-08-08 18:11:02 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MsanTrackOrigins)
|
2014-03-20 22:58:36 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
|
|
|
|
llvm::utostr(MsanTrackOrigins)));
|
2014-10-10 01:53:04 +08:00
|
|
|
if (AsanFieldPadding)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
|
|
|
|
llvm::utostr(AsanFieldPadding)));
|
2015-05-08 06:34:06 +08:00
|
|
|
// Translate available CoverageFeatures to corresponding clang-cc1 flags.
|
|
|
|
std::pair<int, const char *> CoverageFlags[] = {
|
|
|
|
std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"),
|
|
|
|
std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"),
|
|
|
|
std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"),
|
|
|
|
std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"),
|
|
|
|
std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"),
|
|
|
|
std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"),
|
|
|
|
std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters")};
|
|
|
|
for (auto F : CoverageFlags) {
|
|
|
|
if (CoverageFeatures & F.first)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(F.second));
|
2015-05-08 02:31:29 +08:00
|
|
|
}
|
2015-05-08 06:34:06 +08:00
|
|
|
|
|
|
|
|
2015-02-17 23:09:33 +08:00
|
|
|
// MSan: Workaround for PR16386.
|
|
|
|
// ASan: This is mainly to help LSan with cases such as
|
|
|
|
// https://code.google.com/p/address-sanitizer/issues/detail?id=373
|
|
|
|
// We can't make this conditional on -fsanitize=leak, as that flag shouldn't
|
|
|
|
// affect compilation.
|
2015-05-12 05:39:14 +08:00
|
|
|
if (Sanitizers.has(Memory) || Sanitizers.has(Address))
|
2013-08-08 18:11:02 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
|
|
|
|
}
|
|
|
|
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
|
|
|
|
bool DiagnoseErrors) {
|
2014-12-19 10:35:16 +08:00
|
|
|
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-13 06:39:12 +08:00
|
|
|
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
|
|
|
|
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
|
2015-06-19 07:59:22 +08:00
|
|
|
A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
|
|
|
|
A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
|
|
|
|
A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
|
2014-12-19 10:35:16 +08:00
|
|
|
"Invalid argument in parseArgValues!");
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Kinds = 0;
|
2015-03-04 06:15:32 +08:00
|
|
|
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
|
|
|
|
const char *Value = A->getValue(i);
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Kind;
|
2014-12-20 02:41:43 +08:00
|
|
|
// Special case: don't accept -fsanitize=all.
|
|
|
|
if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
|
|
|
|
0 == strcmp("all", Value))
|
|
|
|
Kind = 0;
|
|
|
|
else
|
2015-05-12 05:39:20 +08:00
|
|
|
Kind = parseSanitizerValue(Value, /*AllowGroups=*/true);
|
2014-12-20 02:41:43 +08:00
|
|
|
|
|
|
|
if (Kind)
|
|
|
|
Kinds |= Kind;
|
2013-08-08 18:11:02 +08:00
|
|
|
else if (DiagnoseErrors)
|
2014-11-14 10:59:20 +08:00
|
|
|
D.Diag(clang::diag::err_drv_unsupported_option_argument)
|
2014-12-20 02:41:43 +08:00
|
|
|
<< A->getOption().getName() << Value;
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
2014-12-20 02:41:43 +08:00
|
|
|
return Kinds;
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
2015-05-08 06:34:06 +08:00
|
|
|
int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
|
|
|
|
assert(A->getOption().matches(options::OPT_fsanitize_coverage) ||
|
|
|
|
A->getOption().matches(options::OPT_fno_sanitize_coverage));
|
|
|
|
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("func", CoverageFunc)
|
|
|
|
.Case("bb", CoverageBB)
|
|
|
|
.Case("edge", CoverageEdge)
|
|
|
|
.Case("indirect-calls", CoverageIndirCall)
|
|
|
|
.Case("trace-bb", CoverageTraceBB)
|
|
|
|
.Case("trace-cmp", CoverageTraceCmp)
|
|
|
|
.Case("8bit-counters", Coverage8bitCounters)
|
|
|
|
.Default(0);
|
|
|
|
if (F == 0)
|
|
|
|
D.Diag(clang::diag::err_drv_unsupported_option_argument)
|
|
|
|
<< A->getOption().getName() << Value;
|
|
|
|
Features |= F;
|
|
|
|
}
|
|
|
|
return Features;
|
|
|
|
}
|
|
|
|
|
2014-11-14 10:59:20 +08:00
|
|
|
std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask Mask) {
|
2013-08-08 18:11:02 +08:00
|
|
|
for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
|
|
|
|
E = Args.rend();
|
|
|
|
I != E; ++I) {
|
2014-12-19 10:35:16 +08:00
|
|
|
const auto *Arg = *I;
|
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
|
2015-05-12 05:39:20 +08:00
|
|
|
SanitizerMask AddKinds =
|
|
|
|
expandSanitizerGroups(parseArgValues(D, Arg, false));
|
2014-12-19 10:35:16 +08:00
|
|
|
if (AddKinds & Mask)
|
|
|
|
return describeSanitizeArg(Arg, Mask);
|
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
|
2015-05-12 05:39:20 +08:00
|
|
|
SanitizerMask RemoveKinds =
|
|
|
|
expandSanitizerGroups(parseArgValues(D, Arg, false));
|
2014-12-19 10:35:16 +08:00
|
|
|
Mask &= ~RemoveKinds;
|
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("arg list didn't provide expected value");
|
|
|
|
}
|
|
|
|
|
2015-05-12 05:39:14 +08:00
|
|
|
std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) {
|
2014-11-14 10:59:20 +08:00
|
|
|
assert(A->getOption().matches(options::OPT_fsanitize_EQ)
|
|
|
|
&& "Invalid argument in describeSanitizerArg!");
|
2013-08-08 18:11:02 +08:00
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
std::string Sanitizers;
|
2015-03-04 06:15:32 +08:00
|
|
|
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
|
2015-05-12 05:39:20 +08:00
|
|
|
if (expandSanitizerGroups(
|
|
|
|
parseSanitizerValue(A->getValue(i), /*AllowGroups=*/true)) &
|
|
|
|
Mask) {
|
2013-11-02 02:16:25 +08:00
|
|
|
if (!Sanitizers.empty())
|
|
|
|
Sanitizers += ",";
|
2015-03-04 06:15:32 +08:00
|
|
|
Sanitizers += A->getValue(i);
|
2013-11-02 02:16:25 +08:00
|
|
|
}
|
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
assert(!Sanitizers.empty() && "arg didn't provide expected value");
|
|
|
|
return "-fsanitize=" + Sanitizers;
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|