Skip to content

Commit

Permalink
[CompilerRT] Add support for numerical sanitizer (llvm#94322)
Browse files Browse the repository at this point in the history
This diff contains the compiler-rt changes / preparations for nsan.

Test plan:

1. cd build/runtimes/runtimes-bins && ninja check-nsan
2. ninja check-all
  • Loading branch information
alexander-shaposhnikov committed Jun 19, 2024
1 parent 86eb6bf commit cae6d45
Show file tree
Hide file tree
Showing 23 changed files with 2,390 additions and 1 deletion.
1 change: 1 addition & 0 deletions compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ else()
endif()
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
${LOONGARCH64})
set(ALL_NSAN_SUPPORTED_ARCH ${X86_64})
set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${RISCV64})
set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64}
Expand Down
13 changes: 12 additions & 1 deletion compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ if(APPLE)
list_intersect(MSAN_SUPPORTED_ARCH
ALL_MSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(NSAN_SUPPORTED_ARCH
ALL_NSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(HWASAN_SUPPORTED_ARCH
ALL_HWASAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
Expand Down Expand Up @@ -678,6 +681,7 @@ else()
filter_available_targets(SHADOWCALLSTACK_SUPPORTED_ARCH
${ALL_SHADOWCALLSTACK_SUPPORTED_ARCH})
filter_available_targets(GWP_ASAN_SUPPORTED_ARCH ${ALL_GWP_ASAN_SUPPORTED_ARCH})
filter_available_targets(NSAN_SUPPORTED_ARCH ${ALL_NSAN_SUPPORTED_ARCH})
filter_available_targets(ORC_SUPPORTED_ARCH ${ALL_ORC_SUPPORTED_ARCH})
endif()

Expand Down Expand Up @@ -712,7 +716,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
endif()
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")

set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;asan_abi)
set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
"sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
Expand Down Expand Up @@ -897,4 +901,11 @@ if (GWP_ASAN_SUPPORTED_ARCH AND
else()
set(COMPILER_RT_HAS_GWP_ASAN FALSE)
endif()

if (COMPILER_RT_HAS_SANITIZER_COMMON AND NSAN_SUPPORTED_ARCH AND
OS_NAME MATCHES "Linux")
set(COMPILER_RT_HAS_NSAN TRUE)
else()
set(COMPILER_RT_HAS_NSAN FALSE)
endif()
pythonize_bool(COMPILER_RT_HAS_GWP_ASAN)
75 changes: 75 additions & 0 deletions compiler-rt/include/sanitizer/nsan_interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===-- sanitizer/nsan_interface.h ------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Public interface for nsan.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_NSAN_INTERFACE_H
#define SANITIZER_NSAN_INTERFACE_H

#include <sanitizer/common_interface_defs.h>

#ifdef __cplusplus
extern "C" {
#endif

/// User-provided default option settings.
///
/// You can provide your own implementation of this function to return a string
/// containing NSan runtime options (for example,
/// <c>verbosity=1:halt_on_error=0</c>).
///
/// \returns Default options string.
const char *__nsan_default_options(void);

// Dumps nsan shadow data for a block of `size_bytes` bytes of application
// memory at location `addr`.
//
// Each line contains application address, shadow types, then values.
// Unknown types are shown as `__`, while known values are shown as
// `f`, `d`, `l` for float, double, and long double respectively. Position is
// shown as a single hex digit. The shadow value itself appears on the line that
// contains the first byte of the value.
// FIXME: Show both shadow and application value.
//
// Example: `__nsan_dump_shadow_mem(addr, 32, 8, 0)` might print:
//
// 0x0add7359: __ f0 f1 f2 f3 __ __ __ (42.000)
// 0x0add7361: __ d1 d2 d3 d4 d5 d6 d7
// 0x0add7369: d8 f0 f1 f2 f3 __ __ f2 (-1.000) (12.5)
// 0x0add7371: f3 __ __ __ __ __ __ __
//
// This means that there is:
// - a shadow double for the float at address 0x0add7360, with value 42;
// - a shadow float128 for the double at address 0x0add7362, with value -1;
// - a shadow double for the float at address 0x0add736a, with value 12.5;
// There was also a shadow double for the float at address 0x0add736e, but bytes
// f0 and f1 were overwritten by one or several stores, so that the shadow value
// is no longer valid.
// The argument `reserved` can be any value. Its true value is provided by the
// instrumentation.
void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes,
size_t bytes_per_line, size_t reserved);

// Explicitly dumps a value.
// FIXME: vector versions ?
void __nsan_dump_float(float value);
void __nsan_dump_double(double value);
void __nsan_dump_longdouble(long double value);

// Explicitly checks a value.
// FIXME: vector versions ?
void __nsan_check_float(float value);
void __nsan_check_double(double value);
void __nsan_check_longdouble(long double value);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // SANITIZER_NSAN_INTERFACE_H
56 changes: 56 additions & 0 deletions compiler-rt/lib/nsan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
add_compiler_rt_component(nsan)

include_directories(..)

set(NSAN_SOURCES
nsan.cc
nsan_flags.cc
nsan_interceptors.cc
nsan_stats.cc
nsan_suppressions.cc
)

set(NSAN_HEADERS
nsan.h
nsan_flags.h
nsan_flags.inc
nsan_platform.h
nsan_stats.h
nsan_suppressions.h
)

append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC NSAN_CFLAGS)

set(NSAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})

set(NSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})

if (COMPILER_RT_HAS_NSAN)
foreach(arch ${NSAN_SUPPORTED_ARCH})
add_compiler_rt_runtime(
clang_rt.nsan
STATIC
ARCHS ${arch}
SOURCES ${NSAN_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
$<TARGET_OBJECTS:RTUbsan.${arch}>
ADDITIONAL_HEADERS ${NSAN_HEADERS}
CFLAGS ${NSAN_CFLAGS}
PARENT_TARGET nsan
)
endforeach()

add_compiler_rt_object_libraries(RTNsan
ARCHS ${NSAN_SUPPORTED_ARCH}
SOURCES ${NSAN_SOURCES}
ADDITIONAL_HEADERS ${NSAN_HEADERS}
CFLAGS ${NSAN_CFLAGS})
endif()

if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
Loading

0 comments on commit cae6d45

Please sign in to comment.