Skip to content

Commit 9afe716

Browse files
committed
[sanitizer] Refactor -f(no-)?sanitize-recover parsing
This moves the functionality into a generic parseSanitizerArgs function, and then uses it for parsing both -f(no-)?sanitize-recover and -f(no-)?sanitize-trap. Note: for backwards compatibility, we compute the sanitizer mask as: Default + AlwaysIn + Arguments - AlwaysOut instead of: Default + Arguments + AlwaysIn - AlwaysOut
1 parent 60325ab commit 9afe716

File tree

1 file changed

+56
-64
lines changed

1 file changed

+56
-64
lines changed

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 56 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -247,48 +247,72 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
247247
return Kinds;
248248
}
249249

250-
// Computes the sanitizer mask based on the default plus opt-in (if supported)
251-
// minus opt-out.
250+
// Computes the sanitizer mask as:
251+
// Default + AlwaysIn + Arguments - AlwaysOut
252+
// with arguments parsed from left to right.
253+
//
254+
// Error messages are optionally printed if the AlwaysIn or AlwaysOut
255+
// invariants are violated.
252256
static SanitizerMask
253257
parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
254-
bool DiagnoseErrors, SanitizerMask Supported,
255-
SanitizerMask Default, int OptInID, int OptOutID) {
256-
SanitizerMask Remove; // During the loop below, the accumulated set of
257-
// sanitizers disabled by the current sanitizer
258-
// argument or any argument after it.
259-
SanitizerMask Kinds;
260-
SanitizerMask SupportedWithGroups = setGroupBits(Supported);
261-
262-
for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
258+
bool DiagnoseErrors, SanitizerMask Default,
259+
SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
260+
int OptOutID) {
261+
262+
SanitizerMask Output = Default | AlwaysIn;
263+
// Keep track of which violations we have already reported, to avoid
264+
// duplicate error messages.
265+
SanitizerMask DiagnosedAlwaysInViolations;
266+
SanitizerMask DiagnosedAlwaysOutViolations;
267+
for (const auto *Arg : Args) {
263268
if (Arg->getOption().matches(OptInID)) {
264-
Arg->claim();
265-
SanitizerMask Add = parseArgValues(D, Arg, true);
266-
Add &= ~Remove;
267-
SanitizerMask InvalidValues = Add & ~SupportedWithGroups;
268-
if (InvalidValues && DiagnoseErrors) {
269-
SanitizerSet S;
270-
S.Mask = InvalidValues;
271-
D.Diag(diag::err_drv_unsupported_option_argument)
272-
<< Arg->getSpelling() << toString(S);
269+
SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
270+
// Report error if user explicitly tries to opt-in to an always-out
271+
// sanitizer.
272+
if (SanitizerMask KindsToDiagnose =
273+
Add & AlwaysOut & ~DiagnosedAlwaysOutViolations) {
274+
if (DiagnoseErrors) {
275+
SanitizerSet SetToDiagnose;
276+
SetToDiagnose.Mask |= KindsToDiagnose;
277+
D.Diag(diag::err_drv_unsupported_option_argument)
278+
<< Arg->getSpelling() << toString(SetToDiagnose);
279+
DiagnosedAlwaysOutViolations |= KindsToDiagnose;
280+
}
273281
}
274-
Kinds |= expandSanitizerGroups(Add) & ~Remove;
282+
Output |= expandSanitizerGroups(Add);
283+
Arg->claim();
275284
} else if (Arg->getOption().matches(OptOutID)) {
285+
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
286+
// Report error if user explicitly tries to opt-out of an always-in
287+
// sanitizer.
288+
if (SanitizerMask KindsToDiagnose =
289+
Remove & AlwaysIn & ~DiagnosedAlwaysInViolations) {
290+
if (DiagnoseErrors) {
291+
SanitizerSet SetToDiagnose;
292+
SetToDiagnose.Mask |= KindsToDiagnose;
293+
D.Diag(diag::err_drv_unsupported_option_argument)
294+
<< Arg->getSpelling() << toString(SetToDiagnose);
295+
DiagnosedAlwaysInViolations |= KindsToDiagnose;
296+
}
297+
}
298+
Output &= ~expandSanitizerGroups(Remove);
276299
Arg->claim();
277-
Remove |= expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors));
278300
}
279301
}
280302

281-
// Apply default behavior.
282-
Kinds |= Default & ~Remove;
303+
Output &= ~AlwaysOut;
283304

284-
return Kinds;
305+
return Output;
285306
}
286307

287308
static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
288309
const llvm::opt::ArgList &Args,
289310
bool DiagnoseErrors) {
290-
return parseSanitizeArgs(D, Args, DiagnoseErrors, TrappingSupported,
291-
TrappingDefault, options::OPT_fsanitize_trap_EQ,
311+
SanitizerMask AlwaysTrap; // Empty
312+
SanitizerMask NeverTrap = ~(setGroupBits(TrappingSupported));
313+
314+
return parseSanitizeArgs(D, Args, DiagnoseErrors, TrappingDefault, AlwaysTrap,
315+
NeverTrap, options::OPT_fsanitize_trap_EQ,
292316
options::OPT_fno_sanitize_trap_EQ);
293317
}
294318

@@ -652,44 +676,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
652676
// default in ASan?
653677

654678
// Parse -f(no-)?sanitize-recover flags.
655-
SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable;
656-
SanitizerMask DiagnosedUnrecoverableKinds;
657-
SanitizerMask DiagnosedAlwaysRecoverableKinds;
658-
for (const auto *Arg : Args) {
659-
if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
660-
SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
661-
// Report error if user explicitly tries to recover from unrecoverable
662-
// sanitizer.
663-
if (SanitizerMask KindsToDiagnose =
664-
Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
665-
SanitizerSet SetToDiagnose;
666-
SetToDiagnose.Mask |= KindsToDiagnose;
667-
if (DiagnoseErrors)
668-
D.Diag(diag::err_drv_unsupported_option_argument)
669-
<< Arg->getSpelling() << toString(SetToDiagnose);
670-
DiagnosedUnrecoverableKinds |= KindsToDiagnose;
671-
}
672-
RecoverableKinds |= expandSanitizerGroups(Add);
673-
Arg->claim();
674-
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
675-
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
676-
// Report error if user explicitly tries to disable recovery from
677-
// always recoverable sanitizer.
678-
if (SanitizerMask KindsToDiagnose =
679-
Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
680-
SanitizerSet SetToDiagnose;
681-
SetToDiagnose.Mask |= KindsToDiagnose;
682-
if (DiagnoseErrors)
683-
D.Diag(diag::err_drv_unsupported_option_argument)
684-
<< Arg->getSpelling() << toString(SetToDiagnose);
685-
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
686-
}
687-
RecoverableKinds &= ~expandSanitizerGroups(Remove);
688-
Arg->claim();
689-
}
690-
}
679+
SanitizerMask RecoverableKinds = parseSanitizeArgs(
680+
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
681+
Unrecoverable, options::OPT_fsanitize_recover_EQ,
682+
options::OPT_fno_sanitize_recover_EQ);
683+
691684
RecoverableKinds &= Kinds;
692-
RecoverableKinds &= ~Unrecoverable;
693685

694686
TrappingKinds &= Kinds;
695687
RecoverableKinds &= ~TrappingKinds;

0 commit comments

Comments
 (0)