llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-llvm-ir Author: Alexander Shaposhnikov (alexander-shaposhnikov) <details> <summary>Changes</summary> Add plumbing for the numerical sanitizer on Clang's side. This patch was extracted from https://github.com/llvm/llvm-project/pull/85916 Test plan: ninja check-all --- Full diff: https://github.com/llvm/llvm-project/pull/93783.diff 10 Files Affected: - (modified) clang/include/clang/Basic/Features.def (+1) - (modified) clang/include/clang/Basic/Sanitizers.def (+3) - (modified) clang/include/clang/Driver/SanitizerArgs.h (+3) - (modified) clang/lib/CodeGen/CGDeclCXX.cpp (+4) - (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+2) - (modified) clang/lib/Driver/SanitizerArgs.cpp (+5-2) - (modified) clang/lib/Driver/ToolChains/Linux.cpp (+4) - (added) clang/test/CodeGen/sanitize-numerical-stability-attr.cpp (+49) - (added) clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp (+11) - (modified) llvm/include/llvm/IR/Attributes.td (+3) ``````````diff diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index b762e44e755ec..53f410d3cb4bd 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -96,6 +96,7 @@ FEATURE(nullability, true) FEATURE(nullability_on_arrays, true) FEATURE(nullability_on_classes, true) FEATURE(nullability_nullable_result, true) +FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::NumericalStability)) FEATURE(memory_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory)) diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index b228ffd07ee74..bee35e9dca7c3 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -76,6 +76,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink) // ThreadSanitizer SANITIZER("thread", Thread) +// Numerical stability sanitizer. +SANITIZER("numerical", NumericalStability) + // LeakSanitizer SANITIZER("leak", Leak) diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 07070ec4fc065..47ef175302679 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -103,6 +103,9 @@ class SanitizerArgs { bool needsCfiDiagRt() const; bool needsStatsRt() const { return Stats; } bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); } + bool needsNsanRt() const { + return Sanitizers.has(SanitizerKind::NumericalStability); + } bool hasMemTag() const { return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals(); diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index b047279912f6b..a88bb2af59fee 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -476,6 +476,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction( !isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); + if (getLangOpts().Sanitize.has(SanitizerKind::NumericalStability) && + !isInNoSanitizeList(SanitizerKind::NumericalStability, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability); + if (getLangOpts().Sanitize.has(SanitizerKind::Memory) && !isInNoSanitizeList(SanitizerKind::Memory, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeMemory); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index f0345f3b191b8..681ecfda004d4 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -818,6 +818,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); if (SanOpts.has(SanitizerKind::Thread)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); + if (SanOpts.has(SanitizerKind::NumericalStability)) + Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability); if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory)) Fn->addFnAttr(llvm::Attribute::SanitizeMemory); } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 273f215ca94a8..86825a6ccf7a1 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -41,7 +41,8 @@ static const SanitizerMask NotAllowedWithExecuteOnly = SanitizerKind::Function | SanitizerKind::KCFI; static const SanitizerMask NeedsUnwindTables = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | - SanitizerKind::Memory | SanitizerKind::DataFlow; + SanitizerKind::Memory | SanitizerKind::DataFlow | + SanitizerKind::NumericalStability; static const SanitizerMask SupportsCoverage = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | @@ -53,7 +54,8 @@ static const SanitizerMask SupportsCoverage = SanitizerKind::DataFlow | SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero | SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack | - SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI; + SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI | + SanitizerKind::NumericalStability; static const SanitizerMask RecoverableByDefault = SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | @@ -175,6 +177,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, {"hwasan_ignorelist.txt", SanitizerKind::HWAddress}, {"memtag_ignorelist.txt", SanitizerKind::MemTag}, {"msan_ignorelist.txt", SanitizerKind::Memory}, + {"nsan_ignorelist.txt", SanitizerKind::NumericalStability}, {"tsan_ignorelist.txt", SanitizerKind::Thread}, {"dfsan_abilist.txt", SanitizerKind::DataFlow}, {"cfi_ignorelist.txt", SanitizerKind::CFI}, diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index db2c20d7b461d..3ecf57a94ea89 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -826,6 +826,10 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86_64 || IsAArch64) { Res |= SanitizerKind::KernelHWAddress; } + if (IsX86_64) { + Res |= SanitizerKind::NumericalStability; + } + // Work around "Cannot represent a difference across sections". if (getTriple().getArch() == llvm::Triple::ppc64) Res &= ~SanitizerKind::Function; diff --git a/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp b/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp new file mode 100644 index 0000000000000..56634c54962f4 --- /dev/null +++ b/clang/test/CodeGen/sanitize-numerical-stability-attr.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=numerical | FileCheck -check-prefix=NSAN %s +// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=numerical -fsanitize-ignorelist=%t | FileCheck -check-prefix=BL %s + +// The sanitize_numerical_stability attribute should be attached to functions +// when ThreadSanitizer is enabled, unless no_sanitize_numerical_stability attribute +// is present. + +// WITHOUT: NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]] +// BL: NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]] +// NSAN: NoNSAN1{{.*}}) [[NOATTR:#[0-9]+]] +__attribute__((no_sanitize_numerical_stability)) +int NoNSAN1(int *a) { return *a; } + +// WITHOUT: NoNSAN2{{.*}}) [[NOATTR]] +// BL: NoNSAN2{{.*}}) [[NOATTR]] +// NSAN: NoNSAN2{{.*}}) [[NOATTR]] +__attribute__((no_sanitize_numerical_stability)) +int NoNSAN2(int *a); +int NoNSAN2(int *a) { return *a; } + +// WITHOUT: NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]] +// BL: NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]] +// NSAN: NoNSAN3{{.*}}) [[NOATTR:#[0-9]+]] +__attribute__((no_sanitize("thread"))) +int NoNSAN3(int *a) { return *a; } + +// WITHOUT: NSANOk{{.*}}) [[NOATTR]] +// BL: NSANOk{{.*}}) [[NOATTR]] +// NSAN: NSANOk{{.*}}) [[WITH:#[0-9]+]] +int NSANOk(int *a) { return *a; } + +// WITHOUT: TemplateNSANOk{{.*}}) [[NOATTR]] +// BL: TemplateNSANOk{{.*}}) [[NOATTR]] +// NSAN: TemplateNSANOk{{.*}}) [[WITH]] +template<int i> +int TemplateNSANOk() { return i; } + +// WITHOUT: TemplateNoNSAN{{.*}}) [[NOATTR]] +// BL: TemplateNoNSAN{{.*}}) [[NOATTR]] +// NSAN: TemplateNoNSAN{{.*}}) [[NOATTR]] +template<int i> +__attribute__((no_sanitize_numerical_stability)) +int TemplateNoNSAN() { return i; } + +int force_instance = TemplateNSANOk<42>() + + TemplateNoNSAN<42>(); + diff --git a/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp b/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp new file mode 100644 index 0000000000000..78884977322b8 --- /dev/null +++ b/clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -E -fsanitize=numerical %s -o - | FileCheck --check-prefix=CHECK-NSAN %s +// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-NSAN %s + +#if __has_feature(numerical_stability_sanitizer) +int NumericalStabilitySanitizerEnabled(); +#else +int NumericalStabilitySanitizerDisabled(); +#endif + +// CHECK-NSAN: NumericalStabilitySanitizerEnabled +// CHECK-NO-NSAN: NumericalStabilitySanitizerDisabled diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index cef8b17769f0d..00ec7393c2265 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -285,6 +285,9 @@ def SanitizeHWAddress : EnumAttr<"sanitize_hwaddress", [FnAttr]>; /// MemTagSanitizer is on. def SanitizeMemTag : EnumAttr<"sanitize_memtag", [FnAttr]>; +/// NumericalStabilitySanitizer is on. +def SanitizeNumericalStability : EnumAttr<"sanitize_numericalstability", [FnAttr]>; + /// Speculative Load Hardening is enabled. /// /// Note that this uses the default compatibility (always compatible during `````````` </details> https://github.com/llvm/llvm-project/pull/93783 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits