From c36b2afb1f38e1d955f75b8e54310aedfcdf0a55 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Wed, 24 Jul 2024 00:12:50 +0000 Subject: [PATCH] [compiler-rt][nsan] Add lit config for tests --- compiler-rt/test/nsan/CMakeLists.txt | 16 ++++++ compiler-rt/test/nsan/alloca.cpp | 26 +++++++++ compiler-rt/test/nsan/helpers.h | 4 ++ compiler-rt/test/nsan/lit.cfg.py | 35 ++++++++++++ compiler-rt/test/nsan/lit.site.cfg.py.in | 2 - compiler-rt/test/nsan/sum.cpp | 70 ++++++++++++++++++++++++ 6 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 compiler-rt/test/nsan/alloca.cpp create mode 100644 compiler-rt/test/nsan/helpers.h create mode 100644 compiler-rt/test/nsan/sum.cpp diff --git a/compiler-rt/test/nsan/CMakeLists.txt b/compiler-rt/test/nsan/CMakeLists.txt index d702e122a85ef..78a1f4baee116 100644 --- a/compiler-rt/test/nsan/CMakeLists.txt +++ b/compiler-rt/test/nsan/CMakeLists.txt @@ -3,6 +3,22 @@ set(NSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(NSAN_TESTSUITES) set(NSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} nsan) +macro(add_nsan_testsuite arch) + set(NSAN_TEST_TARGET_ARCH ${arch}) + get_test_cc_for_arch(${arch} NSAN_TEST_TARGET_CC NSAN_TEST_TARGET_CFLAGS) + + string(TOUPPER ${arch} CONFIG_NAME) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND NSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endmacro() + +set(NSAN_TEST_ARCH ${NSAN_SUPPORTED_ARCH}) +foreach(arch ${NSAN_TEST_ARCH}) + add_nsan_testsuite(${arch}) +endforeach() + if(COMPILER_RT_LIBCXX_PATH AND COMPILER_RT_LIBCXXABI_PATH) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in diff --git a/compiler-rt/test/nsan/alloca.cpp b/compiler-rt/test/nsan/alloca.cpp new file mode 100644 index 0000000000000..33f7c1364e664 --- /dev/null +++ b/compiler-rt/test/nsan/alloca.cpp @@ -0,0 +1,26 @@ +// RUN: %clangxx_nsan -O0 -g %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// RUN: %clangxx_nsan -O3 -g %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include + +#include "helpers.h" + +extern "C" void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes, + size_t bytes_per_line, size_t reserved); + +int main() { + int size = 3 * sizeof(float); + // Make sure we allocate dynamically: https://godbolt.org/z/T3h998. + DoNotOptimize(size); + float *array = reinterpret_cast(__builtin_alloca(size)); + DoNotOptimize(array); + array[0] = 1.0; + array[1] = 2.0; + // The third float is uninitialized. + __nsan_dump_shadow_mem((const char *)array, 3 * sizeof(float), 16, 0); + // CHECK: {{.*}} f0 f1 f2 f3 f0 f1 f2 f3 __ __ __ __ (1.00000000000000000000) (2.00000000000000000000) + return 0; +} diff --git a/compiler-rt/test/nsan/helpers.h b/compiler-rt/test/nsan/helpers.h new file mode 100644 index 0000000000000..487707a0a8fa3 --- /dev/null +++ b/compiler-rt/test/nsan/helpers.h @@ -0,0 +1,4 @@ +// Prevents the compiler from optimizing everything away. +template void DoNotOptimize(const T &var) { + asm volatile("" : "+m"(const_cast(var))); +} diff --git a/compiler-rt/test/nsan/lit.cfg.py b/compiler-rt/test/nsan/lit.cfg.py index 8b137891791fe..2d67911a7d5d8 100644 --- a/compiler-rt/test/nsan/lit.cfg.py +++ b/compiler-rt/test/nsan/lit.cfg.py @@ -1 +1,36 @@ +config.name = "NSan" + config.name_suffix +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Test suffixes. +config.suffixes = [".c", ".cpp", ".test"] + +# C & CXX flags. +c_flags = [config.target_cflags] + +# CXX flags +cxx_flags = c_flags + config.cxx_mode_flags + ["-std=c++17"] + +nsan_flags = [ + "-fsanitize=numerical", + "-g", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", +] + + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + + +# Add substitutions. +config.substitutions.append(("%clang ", build_invocation(c_flags))) +config.substitutions.append(("%clang_nsan ", build_invocation(c_flags + nsan_flags))) +config.substitutions.append( + ("%clangxx_nsan ", build_invocation(cxx_flags + nsan_flags)) +) + +# NSan tests are currently supported on Linux only. +if config.host_os not in ["Linux"]: + config.unsupported = True diff --git a/compiler-rt/test/nsan/lit.site.cfg.py.in b/compiler-rt/test/nsan/lit.site.cfg.py.in index 69fd057e75748..496a9d5277a06 100644 --- a/compiler-rt/test/nsan/lit.site.cfg.py.in +++ b/compiler-rt/test/nsan/lit.site.cfg.py.in @@ -4,8 +4,6 @@ config.name_suffix = "-@CONFIG_NAME@" config.target_cflags = "@NSAN_TEST_TARGET_CFLAGS@" config.target_arch = "@NSAN_TEST_TARGET_ARCH@" -config.use_lld = @NSAN_TEST_USE_LLD@ -config.use_thinlto = @NSAN_TEST_USE_THINLTO@ # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") diff --git a/compiler-rt/test/nsan/sum.cpp b/compiler-rt/test/nsan/sum.cpp new file mode 100644 index 0000000000000..31bd62e73966b --- /dev/null +++ b/compiler-rt/test/nsan/sum.cpp @@ -0,0 +1,70 @@ +// RUN: %clangxx_nsan -O0 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=NaiveSum -DFLT=float %s -o %t +// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 not %run %t 2>&1 | FileCheck %s + +// RUN: %clangxx_nsan -O3 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=NaiveSum -DFLT=float %s -o %t +// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 not %run %t 2>&1 | FileCheck %s + +// RUN: %clangxx_nsan -O0 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=KahanSum -DFLT=float %s -o %t +// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t + +// RUN: %clangxx_nsan -O3 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=KahanSum -DFLT=float %s -o %t +// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t + +#include +#include +#include +#include + +// A naive, unstable summation. +template +__attribute__((noinline)) // To check call stack reporting. +T NaiveSum(const std::vector& values) { + T sum = 0; + for (T v : values) { + sum += v; + } + return sum; + // CHECK: WARNING: NumericalStabilitySanitizer: inconsistent shadow results while checking return + // CHECK: float{{ *}}precision (native): + // CHECK: double{{ *}}precision (shadow): + // CHECK: {{#0 .*in .* NaiveSum}} +} + +// Kahan's summation is a numerically stable sum. +// https://en.wikipedia.org/wiki/Kahan_summation_algorithm +template +__attribute__((noinline)) T KahanSum(const std::vector &values) { + T sum = 0; + T c = 0; + for (T v : values) { + T y = v - c; + T t = sum + y; + c = (t - sum) - y; + sum = t; + } + return sum; +} + +int main() { + std::vector values; + constexpr int kNumValues = 1000000; + values.reserve(kNumValues); + // Using a seed to avoid flakiness. + constexpr uint32_t kSeed = 0x123456; + std::mt19937 gen(kSeed); + std::uniform_real_distribution dis(0.0f, 1000.0f); + for (int i = 0; i < kNumValues; ++i) { + values.push_back(dis(gen)); + } + + const auto t1 = std::chrono::high_resolution_clock::now(); + const auto sum = SUM(values); + const auto t2 = std::chrono::high_resolution_clock::now(); + printf("sum: %.8f\n", sum); + std::cout << "runtime: " + << std::chrono::duration_cast(t2 - t1) + .count() / + 1000.0 + << "ms\n"; + return 0; +}