@@ -248,48 +248,76 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
248
248
return Kinds;
249
249
}
250
250
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.
253
257
static SanitizerMask
254
258
parseSanitizeArgs (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) {
264
271
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
+ }
274
284
}
275
- Kinds |= expandSanitizerGroups (Add) & ~Remove;
285
+ Output |= expandSanitizerGroups (Add);
286
+ Arg->claim ();
276
287
} 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);
277
302
Arg->claim ();
278
- Remove |= expandSanitizerGroups (parseArgValues (D, Arg, DiagnoseErrors));
279
303
}
280
304
}
281
305
282
- // Apply default behavior.
283
- Kinds |= Default & ~Remove;
284
-
285
- return Kinds;
306
+ return Output;
286
307
}
287
308
288
309
static SanitizerMask parseSanitizeTrapArgs (const Driver &D,
289
310
const llvm::opt::ArgList &Args,
290
311
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,
293
321
options::OPT_fno_sanitize_trap_EQ);
294
322
}
295
323
@@ -657,44 +685,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
657
685
// default in ASan?
658
686
659
687
// 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;
697
693
RecoverableKinds &= ~Unrecoverable;
694
+ RecoverableKinds &= Kinds;
698
695
699
696
TrappingKinds &= Kinds;
700
697
RecoverableKinds &= ~TrappingKinds;
0 commit comments