-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Add fine-grained __has_feature() cutout
#170822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This is a follow-up to pull 148323. It mints `-fsanitize-ignore-for-ubsan-feature=...`, accepting a list of (UBSan) sanitizers that should not cause `__has_feature(undefined_behavior_sanitizer)` to evaluate true.
|
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
|
@llvm/pr-subscribers-clang-driver Author: Kalvin (j39m) ChangesThis is a follow-up to pull 148323. It mints Full diff: https://github.com/llvm/llvm-project/pull/170822.diff 8 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index aeffe96e806bd..9e5ca9f76397b 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -277,6 +277,7 @@ def err_drv_malformed_sanitizer_metadata_ignorelist : Error<
"malformed sanitizer metadata ignorelist: '%0'">;
def err_drv_unsupported_static_sanitizer_darwin : Error<
"static %0 runtime is not supported on darwin">;
+def err_drv_not_a_ubsan_sanitizer : Error<"not a UBSan sanitizer: '%0'">;
def err_drv_duplicate_config : Error<
"no more than one option '--config' is allowed">;
def err_drv_cannot_open_config_file : Error<
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 0e91b42a132c1..52dd3a72392ee 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -53,7 +53,7 @@ FEATURE(memtag_globals,
LangOpts.Sanitize.has(SanitizerKind::MemtagGlobals))
FEATURE(xray_instrument, LangOpts.XRayInstrument)
FEATURE(undefined_behavior_sanitizer,
- LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined))
+ LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined & ~LangOpts.UBSanFeatureSuppressedSanitize.Mask))
FEATURE(undefined_behavior_sanitizer_finegrained_feature_checks, true)
// These are all part of undefined_behavior_sanitizer:
FEATURE(alignment_sanitizer,
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 3f042f8ddb5a1..66fe01e877cb1 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -441,6 +441,9 @@ class LangOptions : public LangOptionsBase {
SanitizerSet Sanitize;
/// Is at least one coverage instrumentation type enabled.
bool SanitizeCoverage = false;
+ /// Set of enabled (undefined behavior) sanitizers that do not cause
+ /// `__has_feature(undefined_behavior_sanitizer)` to evaluate true.
+ SanitizerSet UBSanFeatureSuppressedSanitize;
/// Paths to files specifying which objects
/// (files, functions, variables) should not be instrumented.
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 84fb66e16bee3..aa8aa9be287c6 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -28,6 +28,7 @@ class SanitizerArgs {
SanitizerSet MergeHandlers;
SanitizerMaskCutoffs SkipHotCutoffs;
SanitizerSet AnnotateDebugInfo;
+ SanitizerSet SuppressUBSanFeature;
std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c6841937c8d39..84243ad80f2a1 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2404,6 +2404,14 @@ def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
"or suspicious behavior. See user manual for available checks">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
Visibility<[ClangOption, CLOption]>;
+def fsanitize_ignore_for_ubsan_feature_EQ
+ : CommaJoined<["-"], "fsanitize-ignore-for-ubsan-feature=">,
+ Group<f_clang_Group>,
+ MetaVarName<"<check>">,
+ HelpText<
+ "Prevents `__has_feature(undefined_behavior_sanitizer)` from "
+ "evaluating true for "
+ "these UBSan checks. See user manual for available UBSan checks">;
def fsanitize_ignorelist_EQ : Joined<["-"], "fsanitize-ignorelist=">,
Group<f_clang_Group>, HelpText<"Path to ignorelist file for sanitizers">;
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index be068b2381d06..08db579626437 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -408,6 +408,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// unused-argument diagnostics.
SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
// Used to deduplicate diagnostics.
+ SanitizerMask IgnoreForUbsanFeature; // Accumulated set of values passed to
+ // `-fsanitize-ignore-for-ubsan-feature`.
SanitizerMask Kinds;
const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
@@ -612,6 +614,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Arg->claim();
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
AllRemove |= expandSanitizerGroups(Remove);
+ } else if (Arg->getOption().matches(
+ options::OPT_fsanitize_ignore_for_ubsan_feature_EQ)) {
+ Arg->claim();
+ SanitizerMask Suppress = parseArgValues(D, Arg, DiagnoseErrors);
+ IgnoreForUbsanFeature |= expandSanitizerGroups(Suppress);
}
}
@@ -736,6 +743,22 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// -f(-no)sanitize=leak should change whether leak detection is enabled by
// default in ASan?
+ // Error if a non-UBSan sanitizer is passed to
+ // `-fsanitize-ignore-for-ubsan-feature=`.
+ //
+ // `shift` is a `SANITIZER_GROUP()`, and so is expanded into its constituents
+ // by `expandSanitizerGroups()` above, though the physical bit is not included
+ // in `SanitizerKind::Undefined`.
+ const SanitizerMask not_ubsan_mask =
+ IgnoreForUbsanFeature &
+ ~(SanitizerKind::Undefined | SanitizerKind::ShiftGroup);
+ if (not_ubsan_mask && DiagnoseErrors) {
+ SanitizerSet not_ubsan;
+ not_ubsan.set(not_ubsan_mask);
+ D.Diag(clang::diag::err_drv_not_a_ubsan_sanitizer) << toString(not_ubsan);
+ }
+ IgnoreForUbsanFeature &= SanitizerKind::Undefined;
+
// Parse -f(no-)?sanitize-recover flags.
SanitizerMask RecoverableKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
@@ -1212,6 +1235,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MergeHandlers.Mask |= MergeKinds;
AnnotateDebugInfo.Mask |= AnnotateDebugInfoKinds;
+ SuppressUBSanFeature.Mask |= IgnoreForUbsanFeature;
// Zero out SkipHotCutoffs for unused sanitizers
SkipHotCutoffs.clear(~Sanitizers.Mask);
@@ -1392,6 +1416,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
return;
CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
+ if (!SuppressUBSanFeature.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize-ignore-for-ubsan-feature=" +
+ toString(SuppressUBSanFeature)));
+
if (!RecoverableSanitizers.empty())
CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
toString(RecoverableSanitizers)));
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b42c263abd2c7..66dd3bc458efe 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3693,6 +3693,10 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_pic_is_pie);
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+ for (StringRef Sanitizer :
+ serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ,
+ Sanitizer);
return;
}
@@ -3892,6 +3896,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+ for (StringRef Sanitizer :
+ serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ, Sanitizer);
// Conflating '-fsanitize-system-ignorelist' and '-fsanitize-ignorelist'.
for (const std::string &F : Opts.NoSanitizeFiles)
@@ -3973,6 +3980,10 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.PIE = Args.hasArg(OPT_pic_is_pie);
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ parseSanitizerKinds(
+ "-fsanitize-ignore-for-ubsan-feature=",
+ Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
+ Opts.UBSanFeatureSuppressedSanitize);
return Diags.getNumErrors() == NumErrorsBefore;
}
@@ -4390,6 +4401,10 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Parse -fsanitize= arguments.
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ parseSanitizerKinds(
+ "-fsanitize-ignore-for-ubsan-feature=",
+ Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
+ Opts.UBSanFeatureSuppressedSanitize);
Opts.NoSanitizeFiles = Args.getAllArgValues(OPT_fsanitize_ignorelist_EQ);
std::vector<std::string> systemIgnorelists =
Args.getAllArgValues(OPT_fsanitize_system_ignorelist_EQ);
diff --git a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
index e1a07d215b549..de4dd1f1cfebc 100644
--- a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
+++ b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
@@ -23,6 +23,36 @@
// RUN: %clang -E %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// Specifying a specific sanitizer under UBSan and immediately suppressing
+// `__has_feature(undefined_behavior_sanitizer)` for the same should result in
+// "no-UBSan."
+// BUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=undefined -fsanitize-ignore-for-ubsan-feature=undefined %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=alignment -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=bool -fsanitize-ignore-for-ubsan-feature=bool %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=builtin -fsanitize-ignore-for-ubsan-feature=builtin %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=array-bounds -fsanitize-ignore-for-ubsan-feature=array-bounds %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=enum -fsanitize-ignore-for-ubsan-feature=enum %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=float-cast-overflow -fsanitize-ignore-for-ubsan-feature=float-cast-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=integer-divide-by-zero -fsanitize-ignore-for-ubsan-feature=integer-divide-by-zero %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=nonnull-attribute -fsanitize-ignore-for-ubsan-feature=nonnull-attribute %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=null -fsanitize-ignore-for-ubsan-feature=null %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// object-size is a no-op at O0.
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -O2 -fsanitize=object-size -fsanitize-ignore-for-ubsan-feature=object-size %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=pointer-overflow -fsanitize-ignore-for-ubsan-feature=pointer-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=return -fsanitize-ignore-for-ubsan-feature=return %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=returns-nonnull-attribute -fsanitize-ignore-for-ubsan-feature=returns-nonnull-attribute %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift-base -fsanitize-ignore-for-ubsan-feature=shift-base %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift-exponent -fsanitize-ignore-for-ubsan-feature=shift-exponent %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift -fsanitize-ignore-for-ubsan-feature=shift %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignore-for-ubsan-feature=signed-integer-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=unreachable -fsanitize-ignore-for-ubsan-feature=unreachable %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=vla-bound -fsanitize-ignore-for-ubsan-feature=vla-bound %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=function -fsanitize-ignore-for-ubsan-feature=function %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+
+// Spot check: suppressing an unrelated sanitizer should still result in a "has
+// UBSan" configuration.
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=function -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-UBSAN,CHECK-FUNCTION %s
+
// REQUIRES: x86-registered-target
#if !__has_feature(undefined_behavior_sanitizer_finegrained_feature_checks)
|
|
@llvm/pr-subscribers-clang Author: Kalvin (j39m) ChangesThis is a follow-up to pull 148323. It mints Full diff: https://github.com/llvm/llvm-project/pull/170822.diff 8 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index aeffe96e806bd..9e5ca9f76397b 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -277,6 +277,7 @@ def err_drv_malformed_sanitizer_metadata_ignorelist : Error<
"malformed sanitizer metadata ignorelist: '%0'">;
def err_drv_unsupported_static_sanitizer_darwin : Error<
"static %0 runtime is not supported on darwin">;
+def err_drv_not_a_ubsan_sanitizer : Error<"not a UBSan sanitizer: '%0'">;
def err_drv_duplicate_config : Error<
"no more than one option '--config' is allowed">;
def err_drv_cannot_open_config_file : Error<
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 0e91b42a132c1..52dd3a72392ee 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -53,7 +53,7 @@ FEATURE(memtag_globals,
LangOpts.Sanitize.has(SanitizerKind::MemtagGlobals))
FEATURE(xray_instrument, LangOpts.XRayInstrument)
FEATURE(undefined_behavior_sanitizer,
- LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined))
+ LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined & ~LangOpts.UBSanFeatureSuppressedSanitize.Mask))
FEATURE(undefined_behavior_sanitizer_finegrained_feature_checks, true)
// These are all part of undefined_behavior_sanitizer:
FEATURE(alignment_sanitizer,
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 3f042f8ddb5a1..66fe01e877cb1 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -441,6 +441,9 @@ class LangOptions : public LangOptionsBase {
SanitizerSet Sanitize;
/// Is at least one coverage instrumentation type enabled.
bool SanitizeCoverage = false;
+ /// Set of enabled (undefined behavior) sanitizers that do not cause
+ /// `__has_feature(undefined_behavior_sanitizer)` to evaluate true.
+ SanitizerSet UBSanFeatureSuppressedSanitize;
/// Paths to files specifying which objects
/// (files, functions, variables) should not be instrumented.
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 84fb66e16bee3..aa8aa9be287c6 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -28,6 +28,7 @@ class SanitizerArgs {
SanitizerSet MergeHandlers;
SanitizerMaskCutoffs SkipHotCutoffs;
SanitizerSet AnnotateDebugInfo;
+ SanitizerSet SuppressUBSanFeature;
std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c6841937c8d39..84243ad80f2a1 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2404,6 +2404,14 @@ def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
"or suspicious behavior. See user manual for available checks">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
Visibility<[ClangOption, CLOption]>;
+def fsanitize_ignore_for_ubsan_feature_EQ
+ : CommaJoined<["-"], "fsanitize-ignore-for-ubsan-feature=">,
+ Group<f_clang_Group>,
+ MetaVarName<"<check>">,
+ HelpText<
+ "Prevents `__has_feature(undefined_behavior_sanitizer)` from "
+ "evaluating true for "
+ "these UBSan checks. See user manual for available UBSan checks">;
def fsanitize_ignorelist_EQ : Joined<["-"], "fsanitize-ignorelist=">,
Group<f_clang_Group>, HelpText<"Path to ignorelist file for sanitizers">;
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index be068b2381d06..08db579626437 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -408,6 +408,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// unused-argument diagnostics.
SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
// Used to deduplicate diagnostics.
+ SanitizerMask IgnoreForUbsanFeature; // Accumulated set of values passed to
+ // `-fsanitize-ignore-for-ubsan-feature`.
SanitizerMask Kinds;
const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
@@ -612,6 +614,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Arg->claim();
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
AllRemove |= expandSanitizerGroups(Remove);
+ } else if (Arg->getOption().matches(
+ options::OPT_fsanitize_ignore_for_ubsan_feature_EQ)) {
+ Arg->claim();
+ SanitizerMask Suppress = parseArgValues(D, Arg, DiagnoseErrors);
+ IgnoreForUbsanFeature |= expandSanitizerGroups(Suppress);
}
}
@@ -736,6 +743,22 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// -f(-no)sanitize=leak should change whether leak detection is enabled by
// default in ASan?
+ // Error if a non-UBSan sanitizer is passed to
+ // `-fsanitize-ignore-for-ubsan-feature=`.
+ //
+ // `shift` is a `SANITIZER_GROUP()`, and so is expanded into its constituents
+ // by `expandSanitizerGroups()` above, though the physical bit is not included
+ // in `SanitizerKind::Undefined`.
+ const SanitizerMask not_ubsan_mask =
+ IgnoreForUbsanFeature &
+ ~(SanitizerKind::Undefined | SanitizerKind::ShiftGroup);
+ if (not_ubsan_mask && DiagnoseErrors) {
+ SanitizerSet not_ubsan;
+ not_ubsan.set(not_ubsan_mask);
+ D.Diag(clang::diag::err_drv_not_a_ubsan_sanitizer) << toString(not_ubsan);
+ }
+ IgnoreForUbsanFeature &= SanitizerKind::Undefined;
+
// Parse -f(no-)?sanitize-recover flags.
SanitizerMask RecoverableKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
@@ -1212,6 +1235,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MergeHandlers.Mask |= MergeKinds;
AnnotateDebugInfo.Mask |= AnnotateDebugInfoKinds;
+ SuppressUBSanFeature.Mask |= IgnoreForUbsanFeature;
// Zero out SkipHotCutoffs for unused sanitizers
SkipHotCutoffs.clear(~Sanitizers.Mask);
@@ -1392,6 +1416,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
return;
CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
+ if (!SuppressUBSanFeature.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize-ignore-for-ubsan-feature=" +
+ toString(SuppressUBSanFeature)));
+
if (!RecoverableSanitizers.empty())
CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
toString(RecoverableSanitizers)));
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b42c263abd2c7..66dd3bc458efe 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3693,6 +3693,10 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_pic_is_pie);
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+ for (StringRef Sanitizer :
+ serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ,
+ Sanitizer);
return;
}
@@ -3892,6 +3896,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+ for (StringRef Sanitizer :
+ serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ, Sanitizer);
// Conflating '-fsanitize-system-ignorelist' and '-fsanitize-ignorelist'.
for (const std::string &F : Opts.NoSanitizeFiles)
@@ -3973,6 +3980,10 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.PIE = Args.hasArg(OPT_pic_is_pie);
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ parseSanitizerKinds(
+ "-fsanitize-ignore-for-ubsan-feature=",
+ Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
+ Opts.UBSanFeatureSuppressedSanitize);
return Diags.getNumErrors() == NumErrorsBefore;
}
@@ -4390,6 +4401,10 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Parse -fsanitize= arguments.
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ parseSanitizerKinds(
+ "-fsanitize-ignore-for-ubsan-feature=",
+ Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
+ Opts.UBSanFeatureSuppressedSanitize);
Opts.NoSanitizeFiles = Args.getAllArgValues(OPT_fsanitize_ignorelist_EQ);
std::vector<std::string> systemIgnorelists =
Args.getAllArgValues(OPT_fsanitize_system_ignorelist_EQ);
diff --git a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
index e1a07d215b549..de4dd1f1cfebc 100644
--- a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
+++ b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
@@ -23,6 +23,36 @@
// RUN: %clang -E %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// Specifying a specific sanitizer under UBSan and immediately suppressing
+// `__has_feature(undefined_behavior_sanitizer)` for the same should result in
+// "no-UBSan."
+// BUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=undefined -fsanitize-ignore-for-ubsan-feature=undefined %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=alignment -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=bool -fsanitize-ignore-for-ubsan-feature=bool %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=builtin -fsanitize-ignore-for-ubsan-feature=builtin %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=array-bounds -fsanitize-ignore-for-ubsan-feature=array-bounds %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=enum -fsanitize-ignore-for-ubsan-feature=enum %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=float-cast-overflow -fsanitize-ignore-for-ubsan-feature=float-cast-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=integer-divide-by-zero -fsanitize-ignore-for-ubsan-feature=integer-divide-by-zero %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=nonnull-attribute -fsanitize-ignore-for-ubsan-feature=nonnull-attribute %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=null -fsanitize-ignore-for-ubsan-feature=null %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// object-size is a no-op at O0.
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -O2 -fsanitize=object-size -fsanitize-ignore-for-ubsan-feature=object-size %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=pointer-overflow -fsanitize-ignore-for-ubsan-feature=pointer-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=return -fsanitize-ignore-for-ubsan-feature=return %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=returns-nonnull-attribute -fsanitize-ignore-for-ubsan-feature=returns-nonnull-attribute %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift-base -fsanitize-ignore-for-ubsan-feature=shift-base %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift-exponent -fsanitize-ignore-for-ubsan-feature=shift-exponent %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift -fsanitize-ignore-for-ubsan-feature=shift %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignore-for-ubsan-feature=signed-integer-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=unreachable -fsanitize-ignore-for-ubsan-feature=unreachable %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=vla-bound -fsanitize-ignore-for-ubsan-feature=vla-bound %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=function -fsanitize-ignore-for-ubsan-feature=function %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+
+// Spot check: suppressing an unrelated sanitizer should still result in a "has
+// UBSan" configuration.
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=function -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-UBSAN,CHECK-FUNCTION %s
+
// REQUIRES: x86-registered-target
#if !__has_feature(undefined_behavior_sanitizer_finegrained_feature_checks)
|
|
CC @fmayer (for general observation from afar) |
This is a follow-up to pull 148323. It mints
-fsanitize-ignore-for-ubsan-feature=..., accepting a list of (UBSan) sanitizers that should not cause__has_feature(undefined_behavior_sanitizer)to evaluate true.