2013-08-08 18:11:02 +08:00
|
|
|
//===--- SanitizerArgs.cpp - Arguments for sanitizer tools ---------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-08-08 18:11:02 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2013-08-19 17:14:21 +08:00
|
|
|
#include "clang/Driver/SanitizerArgs.h"
|
[Driver] Consolidate tools and toolchains by target platform. (NFC)
Summary:
(This is a move-only refactoring patch. There are no functionality changes.)
This patch splits apart the Clang driver's tool and toolchain implementation
files. Each target platform toolchain is moved to its own file, along with the
closest-related tools. Each target platform toolchain has separate headers and
implementation files, so the hierarchy of classes is unchanged.
There are some remaining shared free functions, mostly from Tools.cpp. Several
of these move to their own architecture-specific files, similar to r296056. Some
of them are only used by a single target platform; since the tools and
toolchains are now together, some helpers now live in a platform-specific file.
The balance are helpers related to manipulating argument lists, so they are now
in a new file pair, CommonArgs.h and .cpp.
I've tried to cluster the code logically, which is fairly straightforward for
most of the target platforms and shared architectures. I think I've made
reasonable choices for these, as well as the various shared helpers; but of
course, I'm happy to hear feedback in the review.
There are some particular things I don't like about this patch, but haven't been
able to find a better overall solution. The first is the proliferation of files:
there are several files that are tiny because the toolchain is not very
different from its base (usually the Gnu tools/toolchain). I think this is
mostly a reflection of the true complexity, though, so it may not be "fixable"
in any reasonable sense. The second thing I don't like are the includes like
"../Something.h". I've avoided this largely by clustering into the current file
structure. However, a few of these includes remain, and in those cases it
doesn't make sense to me to sink an existing file any deeper.
Reviewers: rsmith, mehdi_amini, compnerd, rnk, javed.absar
Subscribers: emaste, jfb, danalbert, srhines, dschuff, jyknight, nemanjai, nhaehnle, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D30372
llvm-svn: 297250
2017-03-08 09:02:16 +08:00
|
|
|
#include "ToolChains/CommonArgs.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"
|
2018-04-05 05:55:44 +08:00
|
|
|
#include "llvm/Support/TargetParser.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 {
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
NeedsUbsanRt = Undefined | Integer | ImplicitConversion | Nullability | CFI,
|
2015-06-26 07:14:32 +08:00
|
|
|
NeedsUbsanCxxRt = Vptr | CFI,
|
2014-11-14 10:59:20 +08:00
|
|
|
NotAllowedWithTrap = Vptr,
|
2017-08-30 04:03:51 +08:00
|
|
|
NotAllowedWithMinimalRuntime = Vptr,
|
2018-03-24 03:47:45 +08:00
|
|
|
RequiresPIE = DataFlow | HWAddress | Scudo,
|
2017-12-09 09:32:07 +08:00
|
|
|
NeedsUnwindTables = Address | HWAddress | Thread | Memory | DataFlow,
|
2018-04-14 02:05:21 +08:00
|
|
|
SupportsCoverage = Address | HWAddress | KernelAddress | KernelHWAddress |
|
2018-09-07 17:21:09 +08:00
|
|
|
Memory | KernelMemory | Leak | Undefined | Integer |
|
|
|
|
ImplicitConversion | Nullability | DataFlow | Fuzzer |
|
|
|
|
FuzzerNoLink,
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
RecoverableByDefault = Undefined | Integer | ImplicitConversion | Nullability,
|
2015-11-11 18:45:48 +08:00
|
|
|
Unrecoverable = Unreachable | Return,
|
2018-04-14 02:05:21 +08:00
|
|
|
AlwaysRecoverable = KernelAddress | KernelHWAddress,
|
2015-02-21 04:30:56 +08:00
|
|
|
LegacyFsanitizeRecoverMask = Undefined | Integer,
|
2015-04-02 08:23:30 +08:00
|
|
|
NeedsLTO = CFI,
|
2017-03-14 09:56:34 +08:00
|
|
|
TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow |
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
ImplicitConversion | Nullability | LocalBounds | CFI,
|
2015-06-19 09:51:54 +08:00
|
|
|
TrappingDefault = CFI,
|
2018-06-26 10:15:47 +08:00
|
|
|
CFIClasses =
|
|
|
|
CFIVCall | CFINVCall | CFIMFCall | CFIDerivedCast | CFIUnrelatedCast,
|
2018-11-10 01:54:49 +08:00
|
|
|
CompatibleWithMinimalRuntime = TrappingSupported | Scudo | ShadowCallStack,
|
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,
|
2017-06-09 06:58:19 +08:00
|
|
|
CoverageTraceBB = 1 << 4, // Deprecated.
|
2015-05-08 06:34:06 +08:00
|
|
|
CoverageTraceCmp = 1 << 5,
|
2016-08-30 09:27:03 +08:00
|
|
|
CoverageTraceDiv = 1 << 6,
|
|
|
|
CoverageTraceGep = 1 << 7,
|
2017-06-09 06:58:19 +08:00
|
|
|
Coverage8bitCounters = 1 << 8, // Deprecated.
|
2016-08-30 09:27:03 +08:00
|
|
|
CoverageTracePC = 1 << 9,
|
2016-09-14 09:39:49 +08:00
|
|
|
CoverageTracePCGuard = 1 << 10,
|
2017-05-06 07:28:18 +08:00
|
|
|
CoverageNoPrune = 1 << 11,
|
2017-07-28 08:10:10 +08:00
|
|
|
CoverageInline8bitCounters = 1 << 12,
|
|
|
|
CoveragePCTable = 1 << 13,
|
2017-08-19 02:43:30 +08:00
|
|
|
CoverageStackDepth = 1 << 14,
|
2015-05-08 06:34:06 +08:00
|
|
|
};
|
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);
|
|
|
|
|
2018-02-21 07:17:41 +08:00
|
|
|
static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds,
|
|
|
|
std::vector<std::string> &BlacklistFiles) {
|
|
|
|
struct Blacklist {
|
|
|
|
const char *File;
|
|
|
|
SanitizerMask Mask;
|
|
|
|
} Blacklists[] = {{"asan_blacklist.txt", Address},
|
|
|
|
{"hwasan_blacklist.txt", HWAddress},
|
|
|
|
{"msan_blacklist.txt", Memory},
|
|
|
|
{"tsan_blacklist.txt", Thread},
|
|
|
|
{"dfsan_abilist.txt", DataFlow},
|
|
|
|
{"cfi_blacklist.txt", CFI},
|
|
|
|
{"ubsan_blacklist.txt", Undefined | Integer | Nullability}};
|
|
|
|
|
|
|
|
for (auto BL : Blacklists) {
|
|
|
|
if (!(Kinds & BL.Mask))
|
|
|
|
continue;
|
|
|
|
|
2015-03-21 02:45:06 +08:00
|
|
|
clang::SmallString<64> Path(D.ResourceDir);
|
2018-02-21 07:17:41 +08:00
|
|
|
llvm::sys::path::append(Path, "share", BL.File);
|
|
|
|
if (llvm::sys::fs::exists(Path))
|
|
|
|
BlacklistFiles.push_back(Path.str());
|
2018-05-08 04:54:05 +08:00
|
|
|
else if (BL.Mask == CFI)
|
|
|
|
// If cfi_blacklist.txt cannot be found in the resource dir, driver
|
|
|
|
// should fail.
|
|
|
|
D.Diag(clang::diag::err_drv_no_such_file) << Path;
|
2015-03-21 02:45:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
2017-10-17 02:02:57 +08:00
|
|
|
// All of these include ubsan.
|
2017-12-09 09:32:07 +08:00
|
|
|
if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt() ||
|
[Driver] Make scudo compatible with -fsanitize-minimal-runtime
Summary:
This is the clang side of the change, there is a compiler-rt counterpart.
Scudo works with UBSan using `-fsanitize=scudo,integer` for example, and to do
so it embeds UBSan runtime. This makes it not compatible with the UBSan minimal
runtime, but this is something we want for production purposes.
The idea is to have a Scudo minimal runtime on the compiler-rt side that will
not embed UBSan. This is basically the runtime that is currently in use for
Fuchsia, without coverage, stacktraces or symbolization. With this, Scudo
becomes compatible with `-fsanitize-minimal-runtime`.
If this approach is suitable, I'll add the tests as well, otherwise I am open
to other options.
Reviewers: eugenis
Reviewed By: eugenis
Subscribers: llvm-commits, cfe-commits
Differential Revision: https://reviews.llvm.org/D48373
llvm-svn: 335352
2018-06-22 22:31:30 +08:00
|
|
|
needsDfsanRt() || needsLsanRt() || needsCfiDiagRt() ||
|
|
|
|
(needsScudoRt() && !requiresMinimalRuntime()))
|
2017-10-17 02:02:57 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) ||
|
|
|
|
CoverageFeatures;
|
2015-12-16 07:00:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SanitizerArgs::needsCfiRt() const {
|
2017-10-17 02:02:57 +08:00
|
|
|
return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso &&
|
|
|
|
!ImplicitCfiRuntime;
|
2015-12-16 08:38:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SanitizerArgs::needsCfiDiagRt() const {
|
2017-10-17 02:02:57 +08:00
|
|
|
return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso &&
|
|
|
|
!ImplicitCfiRuntime;
|
2014-11-14 10:59:20 +08:00
|
|
|
}
|
|
|
|
|
2014-11-21 20:19:01 +08:00
|
|
|
bool SanitizerArgs::requiresPIE() const {
|
2015-10-22 05:28:49 +08:00
|
|
|
return NeedPIE || (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
|
|
|
}
|
|
|
|
|
2019-01-12 02:32:07 +08:00
|
|
|
bool SanitizerArgs::needsLTO() const { return Sanitizers.Mask & NeedsLTO; }
|
|
|
|
|
2013-11-02 02:16:25 +08:00
|
|
|
SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
|
|
|
const llvm::opt::ArgList &Args) {
|
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());
|
2018-06-26 10:15:47 +08:00
|
|
|
|
|
|
|
CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso,
|
|
|
|
options::OPT_fno_sanitize_cfi_cross_dso, false);
|
|
|
|
|
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
|
|
|
|
2017-08-30 04:03:51 +08:00
|
|
|
MinimalRuntime =
|
|
|
|
Args.hasFlag(options::OPT_fsanitize_minimal_runtime,
|
|
|
|
options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime);
|
|
|
|
|
2017-06-24 07:15:24 +08:00
|
|
|
// The object size sanitizer should not be enabled at -O0.
|
|
|
|
Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
|
|
|
|
bool RemoveObjectSizeAtO0 =
|
|
|
|
!OptLevel || OptLevel->getOption().matches(options::OPT_O0);
|
|
|
|
|
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();
|
2017-06-24 07:15:24 +08:00
|
|
|
SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true);
|
|
|
|
|
|
|
|
if (RemoveObjectSizeAtO0) {
|
|
|
|
AllRemove |= SanitizerKind::ObjectSize;
|
|
|
|
|
2019-01-24 19:44:24 +08:00
|
|
|
// The user explicitly enabled the object size sanitizer. Warn
|
2017-06-24 07:15:24 +08:00
|
|
|
// that this does nothing at -O0.
|
|
|
|
if (Add & SanitizerKind::ObjectSize)
|
|
|
|
D.Diag(diag::warn_drv_object_size_disabled_O0)
|
|
|
|
<< Arg->getAsString(Args);
|
|
|
|
}
|
|
|
|
|
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;
|
2017-08-30 04:03:51 +08:00
|
|
|
|
|
|
|
if (MinimalRuntime) {
|
|
|
|
if (SanitizerMask KindsToDiagnose =
|
|
|
|
Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) {
|
|
|
|
std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
|
|
|
|
D.Diag(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< Desc << "-fsanitize-minimal-runtime";
|
|
|
|
DiagnosedKinds |= KindsToDiagnose;
|
|
|
|
}
|
|
|
|
Add &= ~NotAllowedWithMinimalRuntime;
|
|
|
|
}
|
|
|
|
|
2018-06-26 10:15:47 +08:00
|
|
|
// FIXME: Make CFI on member function calls compatible with cross-DSO CFI.
|
|
|
|
// There are currently two problems:
|
|
|
|
// - Virtual function call checks need to pass a pointer to the function
|
|
|
|
// address to llvm.type.test and a pointer to the address point to the
|
|
|
|
// diagnostic function. Currently we pass the same pointer to both
|
|
|
|
// places.
|
|
|
|
// - Non-virtual function call checks may need to check multiple type
|
|
|
|
// identifiers.
|
|
|
|
// Fixing both of those may require changes to the cross-DSO CFI
|
|
|
|
// interface.
|
|
|
|
if (CfiCrossDso && (Add & CFIMFCall & ~DiagnosedKinds)) {
|
|
|
|
D.Diag(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize=cfi-mfcall"
|
|
|
|
<< "-fsanitize-cfi-cross-dso";
|
|
|
|
Add &= ~CFIMFCall;
|
|
|
|
DiagnosedKinds |= CFIMFCall;
|
|
|
|
}
|
|
|
|
|
2015-06-20 05:36:47 +08:00
|
|
|
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.
|
2018-05-19 07:32:01 +08:00
|
|
|
if ((Add & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) {
|
|
|
|
if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) {
|
|
|
|
assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) &&
|
|
|
|
"RTTI disabled without -fno-rtti option?");
|
|
|
|
// The user explicitly passed -fno-rtti with -fsanitize=vptr, but
|
|
|
|
// the vptr sanitizer requires RTTI, so this is a user error.
|
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
|
|
|
D.Diag(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
|
2018-05-19 07:32:01 +08:00
|
|
|
} else {
|
2018-07-31 03:24:48 +08:00
|
|
|
// The vptr sanitizer requires RTTI, but RTTI is disabled (by
|
2018-05-19 07:32:01 +08:00
|
|
|
// default). Warn that the vptr sanitizer is being disabled.
|
|
|
|
D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2017-08-30 04:03:51 +08:00
|
|
|
if (MinimalRuntime) {
|
|
|
|
Add &= ~NotAllowedWithMinimalRuntime;
|
|
|
|
}
|
2018-06-26 10:15:47 +08:00
|
|
|
if (CfiCrossDso)
|
|
|
|
Add &= ~CFIMFCall;
|
2015-06-20 05:36:47 +08:00
|
|
|
Add &= Supported;
|
2014-12-19 10:35:16 +08:00
|
|
|
|
2017-04-25 02:23:24 +08:00
|
|
|
if (Add & Fuzzer)
|
2017-08-12 01:22:58 +08:00
|
|
|
Add |= FuzzerNoLink;
|
|
|
|
|
2017-08-26 06:01:21 +08:00
|
|
|
// Enable coverage if the fuzzing flag is set.
|
2017-08-31 06:49:31 +08:00
|
|
|
if (Add & FuzzerNoLink) {
|
2017-09-02 02:34:36 +08:00
|
|
|
CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall |
|
2017-08-26 06:01:21 +08:00
|
|
|
CoverageTraceCmp | CoveragePCTable;
|
2017-08-31 06:49:31 +08:00
|
|
|
// Due to TLS differences, stack depth tracking is only enabled on Linux
|
|
|
|
if (TC.getTriple().isOSLinux())
|
|
|
|
CoverageFeatures |= CoverageStackDepth;
|
|
|
|
}
|
2017-04-25 02:23:24 +08:00
|
|
|
|
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
|
|
|
|
2018-03-07 09:27:03 +08:00
|
|
|
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
|
|
|
|
std::make_pair(Address, Thread | Memory),
|
|
|
|
std::make_pair(Thread, Memory),
|
|
|
|
std::make_pair(Leak, Thread | Memory),
|
|
|
|
std::make_pair(KernelAddress, Address | Leak | Thread | Memory),
|
|
|
|
std::make_pair(HWAddress, Address | Thread | Memory | KernelAddress),
|
|
|
|
std::make_pair(Efficiency, Address | HWAddress | Leak | Thread | Memory |
|
|
|
|
KernelAddress),
|
|
|
|
std::make_pair(Scudo, Address | HWAddress | Leak | Thread | Memory |
|
|
|
|
KernelAddress | Efficiency),
|
|
|
|
std::make_pair(SafeStack, Address | HWAddress | Leak | Thread | Memory |
|
2018-04-04 06:33:53 +08:00
|
|
|
KernelAddress | Efficiency),
|
2018-04-14 02:05:21 +08:00
|
|
|
std::make_pair(KernelHWAddress, Address | HWAddress | Leak | Thread |
|
|
|
|
Memory | KernelAddress | Efficiency |
|
2018-11-20 09:01:49 +08:00
|
|
|
SafeStack),
|
2018-09-07 17:21:09 +08:00
|
|
|
std::make_pair(KernelMemory, Address | HWAddress | Leak | Thread |
|
|
|
|
Memory | KernelAddress | Efficiency |
|
|
|
|
Scudo | SafeStack)};
|
2016-03-30 05:13:53 +08:00
|
|
|
// Enable toolchain specific default sanitizers if not explicitly disabled.
|
2018-03-07 09:27:03 +08:00
|
|
|
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
|
|
|
|
|
2018-03-12 08:23:37 +08:00
|
|
|
// Disable default sanitizers that are incompatible with explicitly requested
|
|
|
|
// ones.
|
2018-03-07 09:27:03 +08:00
|
|
|
for (auto G : IncompatibleGroups) {
|
|
|
|
SanitizerMask Group = G.first;
|
|
|
|
if ((Default & Group) && (Kinds & G.second))
|
|
|
|
Default &= ~Group;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kinds |= Default;
|
2016-03-30 05:13: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.
|
2018-05-19 07:32:01 +08:00
|
|
|
if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_Disabled)) {
|
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.
|
2015-10-16 04:35:53 +08:00
|
|
|
if ((Kinds & NeedsLTO) && !D.isUsingLTO()) {
|
2015-06-20 03:57:46 +08:00
|
|
|
D.Diag(diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto";
|
|
|
|
}
|
|
|
|
|
2018-04-05 05:55:44 +08:00
|
|
|
if ((Kinds & ShadowCallStack) &&
|
|
|
|
TC.getTriple().getArch() == llvm::Triple::aarch64 &&
|
|
|
|
!llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) &&
|
|
|
|
!Args.hasArg(options::OPT_ffixed_x18)) {
|
|
|
|
D.Diag(diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< lastArgumentForMask(D, Args, Kinds & ShadowCallStack)
|
|
|
|
<< "-ffixed-x18";
|
|
|
|
}
|
|
|
|
|
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) {
|
2015-07-09 05:08:05 +08:00
|
|
|
SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt;
|
|
|
|
// The runtime library supports the Microsoft C++ ABI, but only well enough
|
|
|
|
// for CFI. FIXME: Remove this once we support vptr on Windows.
|
|
|
|
if (TC.getTriple().isOSWindows())
|
|
|
|
KindsToDiagnose &= ~CFI;
|
|
|
|
if (KindsToDiagnose) {
|
2015-06-26 07:14:32 +08:00
|
|
|
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.
|
|
|
|
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.
|
2018-04-14 02:05:21 +08:00
|
|
|
SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable;
|
2015-05-12 05:39:14 +08:00
|
|
|
SanitizerMask DiagnosedUnrecoverableKinds = 0;
|
2018-04-14 02:05:21 +08:00
|
|
|
SanitizerMask DiagnosedAlwaysRecoverableKinds = 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)) {
|
2016-05-05 04:21:47 +08:00
|
|
|
DeprecatedReplacement =
|
|
|
|
"-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all";
|
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)) {
|
2016-05-05 04:21:47 +08:00
|
|
|
DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer' or "
|
|
|
|
"'-fno-sanitize-recover=all";
|
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)) {
|
2018-04-14 02:05:21 +08:00
|
|
|
SanitizerMask Remove = parseArgValues(D, Arg, true);
|
|
|
|
// Report error if user explicitly tries to disable recovery from
|
|
|
|
// always recoverable sanitizer.
|
|
|
|
if (SanitizerMask KindsToDiagnose =
|
|
|
|
Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
|
|
|
|
SanitizerSet SetToDiagnose;
|
|
|
|
SetToDiagnose.Mask |= KindsToDiagnose;
|
|
|
|
D.Diag(diag::err_drv_unsupported_option_argument)
|
|
|
|
<< Arg->getOption().getName() << toString(SetToDiagnose);
|
|
|
|
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
|
|
|
|
}
|
|
|
|
RecoverableKinds &= ~expandSanitizerGroups(Remove);
|
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;
|
2017-12-21 08:10:24 +08:00
|
|
|
RecoverableKinds &= ~TrappingKinds;
|
2015-06-19 07:59:22 +08:00
|
|
|
|
2015-02-05 01:40:08 +08:00
|
|
|
// Setup blacklist files.
|
|
|
|
// Add default blacklist from resource directory.
|
2018-02-21 07:17:41 +08:00
|
|
|
addDefaultBlacklists(D, Kinds, BlacklistFiles);
|
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();
|
2015-09-03 04:02:38 +08:00
|
|
|
if (llvm::sys::fs::exists(BLPath)) {
|
2015-02-05 01:40:08 +08:00
|
|
|
BlacklistFiles.push_back(BLPath);
|
2015-09-03 04:02:38 +08:00
|
|
|
ExtraDeps.push_back(BLPath);
|
2018-02-21 07:17:41 +08:00
|
|
|
} else {
|
2014-11-14 10:59:20 +08:00
|
|
|
D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
|
2018-02-21 07:17:41 +08:00
|
|
|
}
|
2015-02-05 01:40:08 +08:00
|
|
|
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
|
|
|
|
Arg->claim();
|
|
|
|
BlacklistFiles.clear();
|
2015-09-03 04:02:38 +08:00
|
|
|
ExtraDeps.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-10-22 05:28:49 +08:00
|
|
|
MsanUseAfterDtor =
|
2017-09-15 07:14:37 +08:00
|
|
|
Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor,
|
|
|
|
options::OPT_fno_sanitize_memory_use_after_dtor,
|
2017-09-15 07:53:56 +08:00
|
|
|
MsanUseAfterDtor);
|
2015-10-22 05:28:49 +08:00
|
|
|
NeedPIE |= !(TC.getTriple().isOSLinux() &&
|
|
|
|
TC.getTriple().getArch() == llvm::Triple::x86_64);
|
2017-09-15 07:53:56 +08:00
|
|
|
} else {
|
|
|
|
MsanUseAfterDtor = false;
|
2014-03-20 22:58:36 +08:00
|
|
|
}
|
|
|
|
|
2016-11-12 07:17:36 +08:00
|
|
|
if (AllAddedKinds & Thread) {
|
|
|
|
TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access,
|
|
|
|
options::OPT_fno_sanitize_thread_memory_access,
|
|
|
|
TsanMemoryAccess);
|
|
|
|
TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit,
|
|
|
|
options::OPT_fno_sanitize_thread_func_entry_exit,
|
|
|
|
TsanFuncEntryExit);
|
|
|
|
TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics,
|
|
|
|
options::OPT_fno_sanitize_thread_atomics,
|
|
|
|
TsanAtomics);
|
|
|
|
}
|
|
|
|
|
2015-12-16 07:00:20 +08:00
|
|
|
if (AllAddedKinds & CFI) {
|
|
|
|
// Without PIE, external function address may resolve to a PLT record, which
|
|
|
|
// can not be verified by the target module.
|
|
|
|
NeedPIE |= CfiCrossDso;
|
2017-11-01 06:39:44 +08:00
|
|
|
CfiICallGeneralizePointers =
|
|
|
|
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
|
|
|
|
|
|
|
|
if (CfiCrossDso && CfiICallGeneralizePointers)
|
|
|
|
D.Diag(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize-cfi-cross-dso"
|
|
|
|
<< "-fsanitize-cfi-icall-generalize-pointers";
|
2015-12-16 07:00:20 +08:00
|
|
|
}
|
|
|
|
|
2016-01-16 08:31:22 +08:00
|
|
|
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
|
|
|
|
options::OPT_fno_sanitize_stats, false);
|
|
|
|
|
2017-08-30 04:03:51 +08:00
|
|
|
if (MinimalRuntime) {
|
|
|
|
SanitizerMask IncompatibleMask =
|
|
|
|
Kinds & ~setGroupBits(CompatibleWithMinimalRuntime);
|
|
|
|
if (IncompatibleMask)
|
|
|
|
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fsanitize-minimal-runtime"
|
|
|
|
<< lastArgumentForMask(D, Args, IncompatibleMask);
|
|
|
|
|
|
|
|
SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds;
|
|
|
|
if (NonTrappingCfi)
|
|
|
|
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< "fsanitize-minimal-runtime"
|
|
|
|
<< "fsanitize-trap=cfi";
|
|
|
|
}
|
|
|
|
|
2015-05-08 06:34:06 +08:00
|
|
|
// Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
|
|
|
|
// enabled sanitizers.
|
2016-02-18 08:49:23 +08:00
|
|
|
for (const auto *Arg : Args) {
|
|
|
|
if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) {
|
|
|
|
int LegacySanitizeCoverage;
|
|
|
|
if (Arg->getNumValues() == 1 &&
|
|
|
|
!StringRef(Arg->getValue(0))
|
2017-04-20 03:57:16 +08:00
|
|
|
.getAsInteger(0, LegacySanitizeCoverage)) {
|
|
|
|
CoverageFeatures = 0;
|
|
|
|
Arg->claim();
|
|
|
|
if (LegacySanitizeCoverage != 0) {
|
2016-02-19 03:32:54 +08:00
|
|
|
D.Diag(diag::warn_drv_deprecated_arg)
|
2017-04-20 03:57:16 +08:00
|
|
|
<< Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
|
2015-05-08 06:34:06 +08:00
|
|
|
}
|
2016-02-18 08:49:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
CoverageFeatures |= parseCoverageFeatures(D, Arg);
|
2016-06-15 05:33:40 +08:00
|
|
|
|
|
|
|
// Disable coverage and not claim the flags if there is at least one
|
|
|
|
// non-supporting sanitizer.
|
2017-07-21 09:17:49 +08:00
|
|
|
if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) {
|
2015-05-08 06:34:06 +08:00
|
|
|
Arg->claim();
|
2016-04-19 05:30:17 +08:00
|
|
|
} else {
|
|
|
|
CoverageFeatures = 0;
|
2015-05-08 06:34:06 +08:00
|
|
|
}
|
2016-02-18 08:49:23 +08:00
|
|
|
} 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.
|
2017-04-20 05:31:11 +08:00
|
|
|
if (CoverageFeatures & CoverageTraceBB)
|
|
|
|
D.Diag(clang::diag::warn_drv_deprecated_arg)
|
2015-05-08 06:34:06 +08:00
|
|
|
<< "-fsanitize-coverage=trace-bb"
|
2017-04-20 05:31:11 +08:00
|
|
|
<< "-fsanitize-coverage=trace-pc-guard";
|
|
|
|
if (CoverageFeatures & Coverage8bitCounters)
|
2017-04-20 04:15:58 +08:00
|
|
|
D.Diag(clang::diag::warn_drv_deprecated_arg)
|
2015-05-08 06:34:06 +08:00
|
|
|
<< "-fsanitize-coverage=8bit-counters"
|
2017-04-20 04:15:58 +08:00
|
|
|
<< "-fsanitize-coverage=trace-pc-guard";
|
2017-05-03 09:27:28 +08:00
|
|
|
|
|
|
|
int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
|
2017-08-09 04:20:40 +08:00
|
|
|
int InstrumentationTypes =
|
|
|
|
CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters;
|
2017-05-03 09:27:28 +08:00
|
|
|
if ((CoverageFeatures & InsertionPointTypes) &&
|
2017-08-09 04:20:40 +08:00
|
|
|
!(CoverageFeatures & InstrumentationTypes)) {
|
2017-05-03 09:27:28 +08:00
|
|
|
D.Diag(clang::diag::warn_drv_deprecated_arg)
|
|
|
|
<< "-fsanitize-coverage=[func|bb|edge]"
|
|
|
|
<< "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:49:23 +08:00
|
|
|
// trace-pc w/o func/bb/edge implies edge.
|
2017-08-19 02:43:30 +08:00
|
|
|
if (!(CoverageFeatures & InsertionPointTypes)) {
|
|
|
|
if (CoverageFeatures &
|
|
|
|
(CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters))
|
|
|
|
CoverageFeatures |= CoverageEdge;
|
|
|
|
|
|
|
|
if (CoverageFeatures & CoverageStackDepth)
|
|
|
|
CoverageFeatures |= CoverageFunc;
|
|
|
|
}
|
2014-11-12 06:15:07 +08:00
|
|
|
|
2017-10-06 04:14:00 +08:00
|
|
|
SharedRuntime =
|
|
|
|
Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
|
2017-10-07 09:42:09 +08:00
|
|
|
TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
|
|
|
|
TC.getTriple().isOSDarwin());
|
2017-10-06 04:14:00 +08:00
|
|
|
|
2017-10-17 02:02:57 +08:00
|
|
|
ImplicitCfiRuntime = TC.getTriple().isAndroid();
|
|
|
|
|
2015-05-21 09:07:52 +08:00
|
|
|
if (AllAddedKinds & Address) {
|
2017-10-26 04:39:22 +08:00
|
|
|
NeedPIE |= TC.getTriple().isOSFuchsia();
|
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-08-09 06:47:17 +08:00
|
|
|
|
2017-05-09 05:11:55 +08:00
|
|
|
AsanUseAfterScope = Args.hasFlag(
|
|
|
|
options::OPT_fsanitize_address_use_after_scope,
|
|
|
|
options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
|
2017-05-10 05:57:43 +08:00
|
|
|
|
2018-11-03 01:29:04 +08:00
|
|
|
AsanPoisonCustomArrayCookie = Args.hasFlag(
|
|
|
|
options::OPT_fsanitize_address_poison_custom_array_cookie,
|
|
|
|
options::OPT_fno_sanitize_address_poison_custom_array_cookie,
|
|
|
|
AsanPoisonCustomArrayCookie);
|
|
|
|
|
2017-05-10 05:57:43 +08:00
|
|
|
// As a workaround for a bug in gold 2.26 and earlier, dead stripping of
|
|
|
|
// globals in ASan is disabled by default on ELF targets.
|
|
|
|
// See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
|
|
|
|
AsanGlobalsDeadStripping =
|
2017-08-04 07:02:22 +08:00
|
|
|
!TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() ||
|
2017-05-10 05:57:43 +08:00
|
|
|
Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
|
2018-12-05 09:44:31 +08:00
|
|
|
|
|
|
|
AsanUseOdrIndicator =
|
|
|
|
Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator,
|
|
|
|
options::OPT_fno_sanitize_address_use_odr_indicator,
|
|
|
|
AsanUseOdrIndicator);
|
2017-05-09 05:11:55 +08:00
|
|
|
} else {
|
|
|
|
AsanUseAfterScope = false;
|
2016-06-02 08:24:20 +08:00
|
|
|
}
|
|
|
|
|
2019-01-05 03:27:04 +08:00
|
|
|
if (AllAddedKinds & HWAddress) {
|
|
|
|
if (Arg *HwasanAbiArg =
|
|
|
|
Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) {
|
|
|
|
HwasanAbi = HwasanAbiArg->getValue();
|
|
|
|
if (HwasanAbi != "platform" && HwasanAbi != "interceptor")
|
|
|
|
D.Diag(clang::diag::err_drv_invalid_value)
|
|
|
|
<< HwasanAbiArg->getAsString(Args) << HwasanAbi;
|
|
|
|
} else {
|
|
|
|
HwasanAbi = "interceptor";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-17 03:06:05 +08:00
|
|
|
if (AllAddedKinds & SafeStack) {
|
|
|
|
// SafeStack runtime is built into the system on Fuchsia.
|
|
|
|
SafeStackRuntime = !TC.getTriple().isOSFuchsia();
|
|
|
|
}
|
|
|
|
|
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;
|
2017-12-21 08:10:24 +08:00
|
|
|
assert(!(RecoverableKinds & TrappingKinds) &&
|
|
|
|
"Overlap between recoverable and trapping sanitizers");
|
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;
|
|
|
|
}
|
|
|
|
|
2016-01-16 08:31:22 +08:00
|
|
|
static void addIncludeLinkerOption(const ToolChain &TC,
|
|
|
|
const llvm::opt::ArgList &Args,
|
|
|
|
llvm::opt::ArgStringList &CmdArgs,
|
|
|
|
StringRef SymbolName) {
|
|
|
|
SmallString<64> LinkerOptionFlag;
|
|
|
|
LinkerOptionFlag = "--linker-option=/include:";
|
|
|
|
if (TC.getTriple().getArch() == llvm::Triple::x86) {
|
|
|
|
// Win32 mangles C function names with a '_' prefix.
|
|
|
|
LinkerOptionFlag += '_';
|
|
|
|
}
|
|
|
|
LinkerOptionFlag += SymbolName;
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
|
|
|
|
}
|
|
|
|
|
2016-07-28 07:01:55 +08:00
|
|
|
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
2015-07-02 09:48:12 +08:00
|
|
|
llvm::opt::ArgStringList &CmdArgs,
|
|
|
|
types::ID InputType) const {
|
2016-09-16 07:44:13 +08:00
|
|
|
// NVPTX doesn't currently support sanitizers. Bailing out here means that
|
|
|
|
// e.g. -fsanitize=address applies only to host code, which is what we want
|
|
|
|
// for now.
|
|
|
|
if (TC.getTriple().isNVPTX())
|
|
|
|
return;
|
|
|
|
|
2016-02-18 08:49:23 +08:00
|
|
|
// Translate available CoverageFeatures to corresponding clang-cc1 flags.
|
|
|
|
// Do it even if Sanitizers.empty() since some forms of coverage don't require
|
|
|
|
// sanitizers.
|
|
|
|
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"),
|
2016-08-30 09:27:03 +08:00
|
|
|
std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"),
|
|
|
|
std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"),
|
2016-02-18 08:49:23 +08:00
|
|
|
std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"),
|
2016-09-14 09:39:49 +08:00
|
|
|
std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"),
|
2017-05-06 07:28:18 +08:00
|
|
|
std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"),
|
2017-06-09 06:58:19 +08:00
|
|
|
std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"),
|
2017-07-28 08:10:10 +08:00
|
|
|
std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"),
|
2017-08-19 02:43:30 +08:00
|
|
|
std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
|
|
|
|
std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")};
|
2016-02-18 08:49:23 +08:00
|
|
|
for (auto F : CoverageFlags) {
|
|
|
|
if (CoverageFeatures & F.first)
|
2017-05-10 05:57:39 +08:00
|
|
|
CmdArgs.push_back(F.second);
|
2016-02-18 08:49:23 +08:00
|
|
|
}
|
|
|
|
|
2016-06-15 07:21:19 +08:00
|
|
|
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
|
|
|
|
// Instruct the code generator to embed linker directives in the object file
|
|
|
|
// that cause the required runtime libraries to be linked.
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(
|
2016-07-28 07:01:55 +08:00
|
|
|
"--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone")));
|
2016-06-15 07:21:19 +08:00
|
|
|
if (types::isCXX(InputType))
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(
|
2016-07-28 07:01:55 +08:00
|
|
|
"--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
|
2016-06-15 07:21:19 +08:00
|
|
|
}
|
|
|
|
if (TC.getTriple().isOSWindows() && needsStatsRt()) {
|
2016-07-28 07:01:55 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
|
|
|
|
TC.getCompilerRT(Args, "stats_client")));
|
2016-06-15 07:21:19 +08:00
|
|
|
|
|
|
|
// The main executable must export the stats runtime.
|
|
|
|
// FIXME: Only exporting from the main executable (e.g. based on whether the
|
|
|
|
// translation unit defines main()) would save a little space, but having
|
|
|
|
// multiple copies of the runtime shouldn't hurt.
|
2016-07-28 07:01:55 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
|
|
|
|
TC.getCompilerRT(Args, "stats")));
|
2016-06-15 07:21:19 +08:00
|
|
|
addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
|
|
|
|
}
|
|
|
|
|
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));
|
|
|
|
}
|
2015-09-03 04:02:38 +08:00
|
|
|
for (const auto &Dep : ExtraDeps) {
|
|
|
|
SmallString<64> ExtraDepOpt("-fdepfile-entry=");
|
|
|
|
ExtraDepOpt += Dep;
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
|
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
|
|
|
|
if (MsanTrackOrigins)
|
2014-03-20 22:58:36 +08:00
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
|
2017-12-29 00:58:54 +08:00
|
|
|
Twine(MsanTrackOrigins)));
|
2015-07-11 04:07:16 +08:00
|
|
|
|
|
|
|
if (MsanUseAfterDtor)
|
2017-05-10 05:57:39 +08:00
|
|
|
CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
|
2015-07-11 04:07:16 +08:00
|
|
|
|
2016-11-12 07:17:36 +08:00
|
|
|
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
|
|
|
|
if (!TsanMemoryAccess) {
|
|
|
|
CmdArgs.push_back("-mllvm");
|
|
|
|
CmdArgs.push_back("-tsan-instrument-memory-accesses=0");
|
|
|
|
CmdArgs.push_back("-mllvm");
|
|
|
|
CmdArgs.push_back("-tsan-instrument-memintrinsics=0");
|
|
|
|
}
|
|
|
|
if (!TsanFuncEntryExit) {
|
|
|
|
CmdArgs.push_back("-mllvm");
|
|
|
|
CmdArgs.push_back("-tsan-instrument-func-entry-exit=0");
|
|
|
|
}
|
|
|
|
if (!TsanAtomics) {
|
|
|
|
CmdArgs.push_back("-mllvm");
|
|
|
|
CmdArgs.push_back("-tsan-instrument-atomics=0");
|
|
|
|
}
|
|
|
|
|
2015-12-16 07:00:20 +08:00
|
|
|
if (CfiCrossDso)
|
2017-05-10 05:57:39 +08:00
|
|
|
CmdArgs.push_back("-fsanitize-cfi-cross-dso");
|
2015-12-16 07:00:20 +08:00
|
|
|
|
2017-11-01 06:39:44 +08:00
|
|
|
if (CfiICallGeneralizePointers)
|
|
|
|
CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
|
|
|
|
|
2016-01-16 08:31:22 +08:00
|
|
|
if (Stats)
|
2017-05-10 05:57:39 +08:00
|
|
|
CmdArgs.push_back("-fsanitize-stats");
|
2016-01-16 08:31:22 +08:00
|
|
|
|
2017-08-30 04:03:51 +08:00
|
|
|
if (MinimalRuntime)
|
|
|
|
CmdArgs.push_back("-fsanitize-minimal-runtime");
|
|
|
|
|
2014-10-10 01:53:04 +08:00
|
|
|
if (AsanFieldPadding)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
|
2017-12-29 00:58:54 +08:00
|
|
|
Twine(AsanFieldPadding)));
|
2015-05-08 06:34:06 +08:00
|
|
|
|
2016-06-02 08:24:20 +08:00
|
|
|
if (AsanUseAfterScope)
|
2017-05-10 05:57:39 +08:00
|
|
|
CmdArgs.push_back("-fsanitize-address-use-after-scope");
|
2016-06-02 08:24:20 +08:00
|
|
|
|
2018-11-03 01:29:04 +08:00
|
|
|
if (AsanPoisonCustomArrayCookie)
|
|
|
|
CmdArgs.push_back("-fsanitize-address-poison-custom-array-cookie");
|
|
|
|
|
2017-05-10 05:57:43 +08:00
|
|
|
if (AsanGlobalsDeadStripping)
|
|
|
|
CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
|
|
|
|
|
2018-12-05 09:44:31 +08:00
|
|
|
if (AsanUseOdrIndicator)
|
|
|
|
CmdArgs.push_back("-fsanitize-address-use-odr-indicator");
|
|
|
|
|
2019-01-05 03:27:04 +08:00
|
|
|
if (!HwasanAbi.empty()) {
|
|
|
|
CmdArgs.push_back("-default-function-attr");
|
|
|
|
CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi));
|
|
|
|
}
|
|
|
|
|
2015-02-17 23:09:33 +08:00
|
|
|
// MSan: Workaround for PR16386.
|
|
|
|
// ASan: This is mainly to help LSan with cases such as
|
2017-11-14 07:27:54 +08:00
|
|
|
// https://github.com/google/sanitizers/issues/373
|
2015-02-17 23:09:33 +08:00
|
|
|
// 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))
|
2017-05-10 05:57:39 +08:00
|
|
|
CmdArgs.push_back("-fno-assume-sane-operator-new");
|
2015-07-02 09:48:12 +08:00
|
|
|
|
2016-04-29 01:09:37 +08:00
|
|
|
// Require -fvisibility= flag on non-Windows when compiling if vptr CFI is
|
|
|
|
// enabled.
|
|
|
|
if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() &&
|
|
|
|
!Args.hasArg(options::OPT_fvisibility_EQ)) {
|
|
|
|
TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< lastArgumentForMask(TC.getDriver(), Args,
|
|
|
|
Sanitizers.Mask & CFIClasses)
|
|
|
|
<< "-fvisibility=";
|
|
|
|
}
|
2013-08-08 18:11:02 +08:00
|
|
|
}
|
|
|
|
|
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;
|
2016-04-22 05:32:04 +08:00
|
|
|
// Similarly, don't accept -fsanitize=efficiency-all.
|
|
|
|
else if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
|
|
|
|
0 == strcmp("efficiency-all", Value))
|
|
|
|
Kind = 0;
|
2014-12-20 02:41:43 +08:00
|
|
|
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)
|
2016-08-30 09:27:03 +08:00
|
|
|
.Case("trace-div", CoverageTraceDiv)
|
|
|
|
.Case("trace-gep", CoverageTraceGep)
|
2015-05-08 06:34:06 +08:00
|
|
|
.Case("8bit-counters", Coverage8bitCounters)
|
2016-02-18 05:34:43 +08:00
|
|
|
.Case("trace-pc", CoverageTracePC)
|
2016-09-14 09:39:49 +08:00
|
|
|
.Case("trace-pc-guard", CoverageTracePCGuard)
|
2017-05-06 07:28:18 +08:00
|
|
|
.Case("no-prune", CoverageNoPrune)
|
2017-06-09 06:58:19 +08:00
|
|
|
.Case("inline-8bit-counters", CoverageInline8bitCounters)
|
2017-07-28 08:10:10 +08:00
|
|
|
.Case("pc-table", CoveragePCTable)
|
2017-08-19 02:43:30 +08:00
|
|
|
.Case("stack-depth", CoverageStackDepth)
|
2015-05-08 06:34:06 +08:00
|
|
|
.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
|
|
|
}
|