@@ -248,48 +248,76 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
248248 return Kinds;
249249}
250250
251- // Computes the sanitizer mask based on the default plus opt-in (if supported)
252- // minus opt-out.
251+ // Computes the sanitizer mask as:
252+ // Default + Arguments (in or out)
253+ // with arguments parsed from left to right.
254+ //
255+ // Error messages are printed if the AlwaysIn or AlwaysOut invariants are
256+ // violated, but the caller must enforce these invariants themselves.
253257static SanitizerMask
254258parseSanitizeArgs (const Driver &D, const llvm::opt::ArgList &Args,
255- bool DiagnoseErrors, SanitizerMask Supported,
256- SanitizerMask Default, int OptInID, int OptOutID) {
257- SanitizerMask Remove; // During the loop below, the accumulated set of
258- // sanitizers disabled by the current sanitizer
259- // argument or any argument after it.
260- SanitizerMask Kinds;
261- SanitizerMask SupportedWithGroups = setGroupBits (Supported);
262-
263- for (const llvm::opt::Arg *Arg : llvm::reverse (Args)) {
259+ bool DiagnoseErrors, SanitizerMask Default,
260+ SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
261+ int OptOutID) {
262+ assert (!(AlwaysIn & AlwaysOut) &&
263+ " parseSanitizeArgs called with contradictory in/out requirements" );
264+
265+ SanitizerMask Output = Default;
266+ // Keep track of which violations we have already reported, to avoid
267+ // duplicate error messages.
268+ SanitizerMask DiagnosedAlwaysInViolations;
269+ SanitizerMask DiagnosedAlwaysOutViolations;
270+ for (const auto *Arg : Args) {
264271 if (Arg->getOption ().matches (OptInID)) {
265- Arg->claim ();
266- SanitizerMask Add = parseArgValues (D, Arg, true );
267- Add &= ~Remove;
268- SanitizerMask InvalidValues = Add & ~SupportedWithGroups;
269- if (InvalidValues && DiagnoseErrors) {
270- SanitizerSet S;
271- S.Mask = InvalidValues;
272- D.Diag (diag::err_drv_unsupported_option_argument)
273- << Arg->getSpelling () << toString (S);
272+ SanitizerMask Add = parseArgValues (D, Arg, DiagnoseErrors);
273+ // Report error if user explicitly tries to opt-in to an always-out
274+ // sanitizer.
275+ if (SanitizerMask KindsToDiagnose =
276+ Add & AlwaysOut & ~DiagnosedAlwaysOutViolations) {
277+ if (DiagnoseErrors) {
278+ SanitizerSet SetToDiagnose;
279+ SetToDiagnose.Mask |= KindsToDiagnose;
280+ D.Diag (diag::err_drv_unsupported_option_argument)
281+ << Arg->getSpelling () << toString (SetToDiagnose);
282+ DiagnosedAlwaysOutViolations |= KindsToDiagnose;
283+ }
274284 }
275- Kinds |= expandSanitizerGroups (Add) & ~Remove;
285+ Output |= expandSanitizerGroups (Add);
286+ Arg->claim ();
276287 } else if (Arg->getOption ().matches (OptOutID)) {
288+ SanitizerMask Remove = parseArgValues (D, Arg, DiagnoseErrors);
289+ // Report error if user explicitly tries to opt-out of an always-in
290+ // sanitizer.
291+ if (SanitizerMask KindsToDiagnose =
292+ Remove & AlwaysIn & ~DiagnosedAlwaysInViolations) {
293+ if (DiagnoseErrors) {
294+ SanitizerSet SetToDiagnose;
295+ SetToDiagnose.Mask |= KindsToDiagnose;
296+ D.Diag (diag::err_drv_unsupported_option_argument)
297+ << Arg->getSpelling () << toString (SetToDiagnose);
298+ DiagnosedAlwaysInViolations |= KindsToDiagnose;
299+ }
300+ }
301+ Output &= ~expandSanitizerGroups (Remove);
277302 Arg->claim ();
278- Remove |= expandSanitizerGroups (parseArgValues (D, Arg, DiagnoseErrors));
279303 }
280304 }
281305
282- // Apply default behavior.
283- Kinds |= Default & ~Remove;
284-
285- return Kinds;
306+ return Output;
286307}
287308
288309static SanitizerMask parseSanitizeTrapArgs (const Driver &D,
289310 const llvm::opt::ArgList &Args,
290311 bool DiagnoseErrors) {
291- return parseSanitizeArgs (D, Args, DiagnoseErrors, TrappingSupported,
292- TrappingDefault, options::OPT_fsanitize_trap_EQ,
312+ SanitizerMask AlwaysTrap; // Empty
313+ SanitizerMask NeverTrap = ~(setGroupBits (TrappingSupported));
314+
315+ // N.B. We do *not* enforce NeverTrap. This maintains the behavior of
316+ // '-fsanitize=undefined -fsanitize-trap=undefined'
317+ // (clang/test/Driver/fsanitize.c ), which is that vptr is not enabled at all
318+ // (not even in recover mode) in order to avoid the need for a ubsan runtime.
319+ return parseSanitizeArgs (D, Args, DiagnoseErrors, TrappingDefault, AlwaysTrap,
320+ NeverTrap, options::OPT_fsanitize_trap_EQ,
293321 options::OPT_fno_sanitize_trap_EQ);
294322}
295323
@@ -657,44 +685,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
657685 // default in ASan?
658686
659687 // Parse -f(no-)?sanitize-recover flags.
660- SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable;
661- SanitizerMask DiagnosedUnrecoverableKinds;
662- SanitizerMask DiagnosedAlwaysRecoverableKinds;
663- for (const auto *Arg : Args) {
664- if (Arg->getOption ().matches (options::OPT_fsanitize_recover_EQ)) {
665- SanitizerMask Add = parseArgValues (D, Arg, DiagnoseErrors);
666- // Report error if user explicitly tries to recover from unrecoverable
667- // sanitizer.
668- if (SanitizerMask KindsToDiagnose =
669- Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
670- SanitizerSet SetToDiagnose;
671- SetToDiagnose.Mask |= KindsToDiagnose;
672- if (DiagnoseErrors)
673- D.Diag (diag::err_drv_unsupported_option_argument)
674- << Arg->getSpelling () << toString (SetToDiagnose);
675- DiagnosedUnrecoverableKinds |= KindsToDiagnose;
676- }
677- RecoverableKinds |= expandSanitizerGroups (Add);
678- Arg->claim ();
679- } else if (Arg->getOption ().matches (options::OPT_fno_sanitize_recover_EQ)) {
680- SanitizerMask Remove = parseArgValues (D, Arg, DiagnoseErrors);
681- // Report error if user explicitly tries to disable recovery from
682- // always recoverable sanitizer.
683- if (SanitizerMask KindsToDiagnose =
684- Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
685- SanitizerSet SetToDiagnose;
686- SetToDiagnose.Mask |= KindsToDiagnose;
687- if (DiagnoseErrors)
688- D.Diag (diag::err_drv_unsupported_option_argument)
689- << Arg->getSpelling () << toString (SetToDiagnose);
690- DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
691- }
692- RecoverableKinds &= ~expandSanitizerGroups (Remove);
693- Arg->claim ();
694- }
695- }
696- RecoverableKinds &= Kinds;
688+ SanitizerMask RecoverableKinds = parseSanitizeArgs (
689+ D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
690+ Unrecoverable, options::OPT_fsanitize_recover_EQ,
691+ options::OPT_fno_sanitize_recover_EQ);
692+ RecoverableKinds |= AlwaysRecoverable;
697693 RecoverableKinds &= ~Unrecoverable;
694+ RecoverableKinds &= Kinds;
698695
699696 TrappingKinds &= Kinds;
700697 RecoverableKinds &= ~TrappingKinds;
0 commit comments