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
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 09c2cb0..bd7bc21 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -44,7 +44,10 @@
NotAllowedWithTrap = Vptr,
RequiresPIE = Memory | DataFlow,
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
- SupportsCoverage = Address | Memory | Leak | Undefined | Integer
+ SupportsCoverage = Address | Memory | Leak | Undefined | Integer,
+ RecoverableByDefault = Undefined | Integer,
+ Unrecoverable = Address | Unreachable | Return,
+ LegacyFsanitizeRecoverMask = Undefined | Integer
};
}
@@ -145,7 +148,7 @@
void SanitizerArgs::clear() {
Sanitizers.clear();
- SanitizeRecover = false;
+ RecoverableSanitizers.clear();
BlacklistFile = "";
SanitizeCoverage = 0;
MsanTrackOrigins = 0;
@@ -204,8 +207,40 @@
}
addAllOf(Sanitizers, Kinds);
- SanitizeRecover = Args.hasFlag(options::OPT_fsanitize_recover,
- options::OPT_fno_sanitize_recover, true);
+ // Parse -f(no-)?sanitize-recover flags.
+ unsigned RecoverableKinds = RecoverableByDefault;
+ unsigned DiagnosedUnrecoverableKinds = 0;
+ for (const auto *Arg : Args) {
+ if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
+ // FIXME: Add deprecation notice, and then remove this flag.
+ RecoverableKinds |= expandGroups(LegacyFsanitizeRecoverMask);
+ Arg->claim();
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) {
+ // FIXME: Add deprecation notice, and then remove this flag.
+ RecoverableKinds &= ~expandGroups(LegacyFsanitizeRecoverMask);
+ Arg->claim();
+ } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
+ unsigned Add = parseArgValues(D, Arg, true);
+ // Report error if user explicitly tries to recover from unrecoverable
+ // sanitizer.
+ if (unsigned KindsToDiagnose =
+ Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
+ SanitizerSet SetToDiagnose;
+ addAllOf(SetToDiagnose, KindsToDiagnose);
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << Arg->getOption().getName() << toString(SetToDiagnose);
+ DiagnosedUnrecoverableKinds |= KindsToDiagnose;
+ }
+ RecoverableKinds |= expandGroups(Add);
+ Arg->claim();
+ } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
+ RecoverableKinds &= ~expandGroups(parseArgValues(D, Arg, true));
+ Arg->claim();
+ }
+ }
+ RecoverableKinds &= Kinds;
+ RecoverableKinds &= ~Unrecoverable;
+ addAllOf(RecoverableSanitizers, RecoverableKinds);
UbsanTrapOnError =
Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
@@ -361,8 +396,9 @@
return;
CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
- if (!SanitizeRecover)
- CmdArgs.push_back("-fno-sanitize-recover");
+ if (!RecoverableSanitizers.empty())
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
+ toString(RecoverableSanitizers)));
if (UbsanTrapOnError)
CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
@@ -426,7 +462,9 @@
unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors) {
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
- A->getOption().matches(options::OPT_fno_sanitize_EQ)) &&
+ A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
+ A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
+ A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) &&
"Invalid argument in parseArgValues!");
unsigned Kinds = 0;
for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {