Skip to content

Commit f932900

Browse files
Add numerical sanitizer
1 parent 9fd1c41 commit f932900

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+7863
-4
lines changed

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
102102
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
103103
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
104104
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
105+
FEATURE(numericalstability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
105106
FEATURE(swiftasynccc,
106107
PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
107108
clang::TargetInfo::CCCR_OK)

clang/include/clang/Basic/Sanitizers.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink)
7676
// ThreadSanitizer
7777
SANITIZER("thread", Thread)
7878

79+
// Numerical stability sanitizer.
80+
SANITIZER("numerical", NumericalStability)
81+
7982
// LeakSanitizer
8083
SANITIZER("leak", Leak)
8184

clang/include/clang/Driver/SanitizerArgs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ class SanitizerArgs {
103103
bool needsCfiDiagRt() const;
104104
bool needsStatsRt() const { return Stats; }
105105
bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); }
106+
bool needsNsanRt() const {
107+
return Sanitizers.has(SanitizerKind::NumericalStability);
108+
}
106109

107110
bool hasMemTag() const {
108111
return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
#include "llvm/Transforms/Instrumentation/KCFI.h"
7676
#include "llvm/Transforms/Instrumentation/MemProfiler.h"
7777
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
78+
#include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h"
7879
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
7980
#include "llvm/Transforms/Instrumentation/RemoveTrapsPass.h"
8081
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
@@ -734,6 +735,12 @@ static void addSanitizers(const Triple &TargetTriple,
734735
if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) {
735736
MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles));
736737
}
738+
739+
if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability)) {
740+
MPM.addPass(NumericalStabilitySanitizerPass());
741+
MPM.addPass(
742+
createModuleToFunctionPassAdaptor(NumericalStabilitySanitizerPass()));
743+
}
737744
};
738745
if (ClSanitizeOnOptimizerEarlyEP) {
739746
PB.registerOptimizerEarlyEPCallback(

clang/lib/CodeGen/CGDeclCXX.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
476476
!isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
477477
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
478478

479+
if (getLangOpts().Sanitize.has(SanitizerKind::NumericalStability) &&
480+
!isInNoSanitizeList(SanitizerKind::NumericalStability, Fn, Loc))
481+
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
482+
479483
if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
480484
!isInNoSanitizeList(SanitizerKind::Memory, Fn, Loc))
481485
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
795795
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
796796
if (SanOpts.has(SanitizerKind::Thread))
797797
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
798+
if (SanOpts.has(SanitizerKind::NumericalStability))
799+
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
798800
if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
799801
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
800802
}

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ static const SanitizerMask NotAllowedWithExecuteOnly =
4141
SanitizerKind::Function | SanitizerKind::KCFI;
4242
static const SanitizerMask NeedsUnwindTables =
4343
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
44-
SanitizerKind::Memory | SanitizerKind::DataFlow;
44+
SanitizerKind::Memory | SanitizerKind::DataFlow |
45+
SanitizerKind::NumericalStability;
4546
static const SanitizerMask SupportsCoverage =
4647
SanitizerKind::Address | SanitizerKind::HWAddress |
4748
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
@@ -53,7 +54,8 @@ static const SanitizerMask SupportsCoverage =
5354
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
5455
SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
5556
SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
56-
SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
57+
SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI |
58+
SanitizerKind::NumericalStability;
5759
static const SanitizerMask RecoverableByDefault =
5860
SanitizerKind::Undefined | SanitizerKind::Integer |
5961
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
@@ -175,6 +177,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
175177
{"hwasan_ignorelist.txt", SanitizerKind::HWAddress},
176178
{"memtag_ignorelist.txt", SanitizerKind::MemTag},
177179
{"msan_ignorelist.txt", SanitizerKind::Memory},
180+
{"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
178181
{"tsan_ignorelist.txt", SanitizerKind::Thread},
179182
{"dfsan_abilist.txt", SanitizerKind::DataFlow},
180183
{"cfi_ignorelist.txt", SanitizerKind::CFI},

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,11 +1526,14 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
15261526
if (SanArgs.linkCXXRuntimes())
15271527
StaticRuntimes.push_back("msan_cxx");
15281528
}
1529+
if (SanArgs.needsNsanRt())
1530+
StaticRuntimes.push_back("nsan");
15291531
if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt()) {
15301532
StaticRuntimes.push_back("tsan");
15311533
if (SanArgs.linkCXXRuntimes())
15321534
StaticRuntimes.push_back("tsan_cxx");
15331535
}
1536+
15341537
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
15351538
if (SanArgs.requiresMinimalRuntime()) {
15361539
StaticRuntimes.push_back("ubsan_minimal");

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,10 @@ SanitizerMask Linux::getSupportedSanitizers() const {
825825
if (IsX86_64 || IsAArch64) {
826826
Res |= SanitizerKind::KernelHWAddress;
827827
}
828+
if (IsX86_64) {
829+
Res |= SanitizerKind::NumericalStability;
830+
}
831+
828832
// Work around "Cannot represent a difference across sections".
829833
if (getTriple().getArch() == llvm::Triple::ppc64)
830834
Res &= ~SanitizerKind::Function;

clang/runtime/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
122122
COMPONENT compiler-rt)
123123

124124
# Add top-level targets that build specific compiler-rt runtimes.
125-
set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal)
125+
set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan nsan profile tsan ubsan ubsan-minimal)
126126
foreach(runtime ${COMPILER_RT_RUNTIMES})
127127
get_ext_project_build_command(build_runtime_cmd ${runtime})
128128
add_custom_target(${runtime}
@@ -149,6 +149,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
149149
check-hwasan
150150
check-lsan
151151
check-msan
152+
check-nsan
152153
check-profile
153154
check-safestack
154155
check-sanitizer

compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ else()
6161
endif()
6262
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
6363
${LOONGARCH64})
64+
set(ALL_NSAN_SUPPORTED_ARCH ${X86} ${X86_64})
6465
set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${RISCV64})
6566
set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
6667
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64}

compiler-rt/cmake/config-ix.cmake

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,9 @@ if(APPLE)
621621
list_intersect(MSAN_SUPPORTED_ARCH
622622
ALL_MSAN_SUPPORTED_ARCH
623623
SANITIZER_COMMON_SUPPORTED_ARCH)
624+
list_intersect(NSAN_SUPPORTED_ARCH
625+
ALL_NSAN_SUPPORTED_ARCH
626+
SANITIZER_COMMON_SUPPORTED_ARCH)
624627
list_intersect(HWASAN_SUPPORTED_ARCH
625628
ALL_HWASAN_SUPPORTED_ARCH
626629
SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -686,6 +689,7 @@ else()
686689
filter_available_targets(SHADOWCALLSTACK_SUPPORTED_ARCH
687690
${ALL_SHADOWCALLSTACK_SUPPORTED_ARCH})
688691
filter_available_targets(GWP_ASAN_SUPPORTED_ARCH ${ALL_GWP_ASAN_SUPPORTED_ARCH})
692+
filter_available_targets(NSAN_SUPPORTED_ARCH ${ALL_NSAN_SUPPORTED_ARCH})
689693
filter_available_targets(ORC_SUPPORTED_ARCH ${ALL_ORC_SUPPORTED_ARCH})
690694
endif()
691695

@@ -720,7 +724,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
720724
endif()
721725
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
722726

723-
set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;asan_abi)
727+
set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
724728
set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
725729
"sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
726730
list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
@@ -898,4 +902,11 @@ if (GWP_ASAN_SUPPORTED_ARCH AND
898902
else()
899903
set(COMPILER_RT_HAS_GWP_ASAN FALSE)
900904
endif()
905+
906+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND NSAN_SUPPORTED_ARCH AND
907+
OS_NAME MATCHES "Linux")
908+
set(COMPILER_RT_HAS_NSAN TRUE)
909+
else()
910+
set(COMPILER_RT_HAS_NSAN FALSE)
911+
endif()
901912
pythonize_bool(COMPILER_RT_HAS_GWP_ASAN)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===-- sanitizer/nsan_interface.h ------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Public interface for nsan.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#ifndef SANITIZER_NSAN_INTERFACE_H
13+
#define SANITIZER_NSAN_INTERFACE_H
14+
15+
#include <sanitizer/common_interface_defs.h>
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
/// User-provided default option settings.
22+
///
23+
/// You can provide your own implementation of this function to return a string
24+
/// containing NSan runtime options (for example,
25+
/// <c>verbosity=1:halt_on_error=0</c>).
26+
///
27+
/// \returns Default options string.
28+
const char *__nsan_default_options(void);
29+
30+
// Dumps nsan shadow data for a block of `size_bytes` bytes of application
31+
// memory at location `addr`.
32+
//
33+
// Each line contains application address, shadow types, then values.
34+
// Unknown types are shown as `__`, while known values are shown as
35+
// `f`, `d`, `l` for float, double, and long double respectively. Position is
36+
// shown as a single hex digit. The shadow value itself appears on the line that
37+
// contains the first byte of the value.
38+
// FIXME: Show both shadow and application value.
39+
//
40+
// Example: `__nsan_dump_shadow_mem(addr, 32, 8, 0)` might print:
41+
//
42+
// 0x0add7359: __ f0 f1 f2 f3 __ __ __ (42.000)
43+
// 0x0add7361: __ d1 d2 d3 d4 d5 d6 d7
44+
// 0x0add7369: d8 f0 f1 f2 f3 __ __ f2 (-1.000) (12.5)
45+
// 0x0add7371: f3 __ __ __ __ __ __ __
46+
//
47+
// This means that there is:
48+
// - a shadow double for the float at address 0x0add7360, with value 42;
49+
// - a shadow float128 for the double at address 0x0add7362, with value -1;
50+
// - a shadow double for the float at address 0x0add736a, with value 12.5;
51+
// There was also a shadow double for the float at address 0x0add736e, but bytes
52+
// f0 and f1 were overwritten by one or several stores, so that the shadow value
53+
// is no longer valid.
54+
// The argument `reserved` can be any value. Its true value is provided by the
55+
// instrumentation.
56+
void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes,
57+
size_t bytes_per_line, size_t reserved);
58+
59+
// Explicitly dumps a value.
60+
// FIXME: vector versions ?
61+
void __nsan_dump_float(float value);
62+
void __nsan_dump_double(double value);
63+
void __nsan_dump_longdouble(long double value);
64+
65+
// Explicitly checks a value.
66+
// FIXME: vector versions ?
67+
void __nsan_check_float(float value);
68+
void __nsan_check_double(double value);
69+
void __nsan_check_longdouble(long double value);
70+
71+
#ifdef __cplusplus
72+
} // extern "C"
73+
#endif
74+
75+
#endif // SANITIZER_NSAN_INTERFACE_H

compiler-rt/lib/nsan/CMakeLists.txt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
add_compiler_rt_component(nsan)
2+
3+
include_directories(..)
4+
5+
set(NSAN_SOURCES
6+
nsan.cc
7+
nsan_flags.cc
8+
nsan_interceptors.cc
9+
nsan_stats.cc
10+
nsan_suppressions.cc
11+
)
12+
13+
set(NSAN_HEADERS
14+
nsan.h
15+
nsan_flags.h
16+
nsan_flags.inc
17+
nsan_platform.h
18+
nsan_stats.h
19+
nsan_suppressions.h
20+
)
21+
22+
append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC NSAN_CFLAGS)
23+
24+
set(NSAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
25+
26+
set(NSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
27+
#-fno-rtti -fno-exceptions
28+
# -nostdinc++ -pthread -fno-omit-frame-pointer)
29+
30+
# Remove -stdlib= which is unused when passing -nostdinc++.
31+
# string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
32+
33+
if (COMPILER_RT_HAS_NSAN)
34+
foreach(arch ${NSAN_SUPPORTED_ARCH})
35+
add_compiler_rt_runtime(
36+
clang_rt.nsan
37+
STATIC
38+
ARCHS ${arch}
39+
SOURCES ${NSAN_SOURCES}
40+
$<TARGET_OBJECTS:RTInterception.${arch}>
41+
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
42+
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
43+
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
44+
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
45+
$<TARGET_OBJECTS:RTUbsan.${arch}>
46+
ADDITIONAL_HEADERS ${NSAN_HEADERS}
47+
CFLAGS ${NSAN_CFLAGS}
48+
PARENT_TARGET nsan
49+
)
50+
endforeach()
51+
52+
add_compiler_rt_object_libraries(RTNsan
53+
ARCHS ${NSAN_SUPPORTED_ARCH}
54+
SOURCES ${NSAN_SOURCES}
55+
ADDITIONAL_HEADERS ${NSAN_HEADERS}
56+
CFLAGS ${NSAN_CFLAGS})
57+
endif()
58+
59+
if(COMPILER_RT_INCLUDE_TESTS)
60+
add_subdirectory(tests)
61+
endif()

0 commit comments

Comments
 (0)