Skip to content

Commit

Permalink
[Clang][Sanitizers] Add numerical sanitizer
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-shaposhnikov committed May 30, 2024
1 parent 1f67f34 commit c02e191
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 2 deletions.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Sanitizers.def
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink)
// ThreadSanitizer
SANITIZER("thread", Thread)

// Numerical stability sanitizer.
SANITIZER("numerical", NumericalStability)

// LeakSanitizer
SANITIZER("leak", Leak)

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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 |
Expand Down Expand Up @@ -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},
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
49 changes: 49 additions & 0 deletions clang/test/CodeGen/sanitize-numerical-stability-attr.cpp
Original file line number Diff line number Diff line change
@@ -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 NumericalStabilitySanitizer 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("numerical_stability")))
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>();

11 changes: 11 additions & 0 deletions clang/test/Lexer/has_feature_numerical_stability_sanitizer.cpp
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c02e191

Please sign in to comment.