Skip to content

Commit f4e8fbc

Browse files
[compiler-rt][nsan] Add lit config for tests (llvm#100286)
Initial setup for tests. Test plan: ninja check-nsan
1 parent 9d45b45 commit f4e8fbc

File tree

6 files changed

+151
-2
lines changed

6 files changed

+151
-2
lines changed

compiler-rt/test/nsan/CMakeLists.txt

+16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@ set(NSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
33
set(NSAN_TESTSUITES)
44
set(NSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} nsan)
55

6+
macro(add_nsan_testsuite arch)
7+
set(NSAN_TEST_TARGET_ARCH ${arch})
8+
get_test_cc_for_arch(${arch} NSAN_TEST_TARGET_CC NSAN_TEST_TARGET_CFLAGS)
9+
10+
string(TOUPPER ${arch} CONFIG_NAME)
11+
configure_lit_site_cfg(
12+
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
13+
${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
14+
list(APPEND NSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
15+
endmacro()
16+
17+
set(NSAN_TEST_ARCH ${NSAN_SUPPORTED_ARCH})
18+
foreach(arch ${NSAN_TEST_ARCH})
19+
add_nsan_testsuite(${arch})
20+
endforeach()
21+
622
if(COMPILER_RT_LIBCXX_PATH AND COMPILER_RT_LIBCXXABI_PATH)
723
configure_lit_site_cfg(
824
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in

compiler-rt/test/nsan/alloca.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clangxx_nsan -O0 -g %s -o %t
2+
// RUN: %run %t 2>&1 | FileCheck %s
3+
4+
// RUN: %clangxx_nsan -O3 -g %s -o %t
5+
// RUN: %run %t 2>&1 | FileCheck %s
6+
7+
#include <cstddef>
8+
9+
#include "helpers.h"
10+
11+
extern "C" void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes,
12+
size_t bytes_per_line, size_t reserved);
13+
14+
int main() {
15+
int size = 3 * sizeof(float);
16+
// Make sure we allocate dynamically: https://godbolt.org/z/T3h998.
17+
DoNotOptimize(size);
18+
float *array = reinterpret_cast<float *>(__builtin_alloca(size));
19+
DoNotOptimize(array);
20+
array[0] = 1.0;
21+
array[1] = 2.0;
22+
// The third float is uninitialized.
23+
__nsan_dump_shadow_mem((const char *)array, 3 * sizeof(float), 16, 0);
24+
// CHECK: {{.*}} f0 f1 f2 f3 f0 f1 f2 f3 __ __ __ __ (1.00000000000000000000) (2.00000000000000000000)
25+
return 0;
26+
}

compiler-rt/test/nsan/helpers.h

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Prevents the compiler from optimizing everything away.
2+
template <class T> void DoNotOptimize(const T &var) {
3+
asm volatile("" : "+m"(const_cast<T &>(var)));
4+
}

compiler-rt/test/nsan/lit.cfg.py

+35
Original file line numberDiff line numberDiff line change
@@ -1 +1,36 @@
1+
config.name = "NSan" + config.name_suffix
12

3+
# Setup source root.
4+
config.test_source_root = os.path.dirname(__file__)
5+
6+
# Test suffixes.
7+
config.suffixes = [".c", ".cpp", ".test"]
8+
9+
# C & CXX flags.
10+
c_flags = [config.target_cflags]
11+
12+
# CXX flags
13+
cxx_flags = c_flags + config.cxx_mode_flags + ["-std=c++17"]
14+
15+
nsan_flags = [
16+
"-fsanitize=numerical",
17+
"-g",
18+
"-mno-omit-leaf-frame-pointer",
19+
"-fno-omit-frame-pointer",
20+
]
21+
22+
23+
def build_invocation(compile_flags):
24+
return " " + " ".join([config.clang] + compile_flags) + " "
25+
26+
27+
# Add substitutions.
28+
config.substitutions.append(("%clang ", build_invocation(c_flags)))
29+
config.substitutions.append(("%clang_nsan ", build_invocation(c_flags + nsan_flags)))
30+
config.substitutions.append(
31+
("%clangxx_nsan ", build_invocation(cxx_flags + nsan_flags))
32+
)
33+
34+
# NSan tests are currently supported on Linux only.
35+
if config.host_os not in ["Linux"]:
36+
config.unsupported = True

compiler-rt/test/nsan/lit.site.cfg.py.in

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
config.name_suffix = "-@CONFIG_NAME@"
55
config.target_cflags = "@NSAN_TEST_TARGET_CFLAGS@"
66
config.target_arch = "@NSAN_TEST_TARGET_ARCH@"
7-
config.use_lld = @NSAN_TEST_USE_LLD@
8-
config.use_thinlto = @NSAN_TEST_USE_THINLTO@
97

108
# Load common config for all compiler-rt lit tests.
119
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")

compiler-rt/test/nsan/sum.cpp

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %clangxx_nsan -O0 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=NaiveSum -DFLT=float %s -o %t
2+
// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 not %run %t 2>&1 | FileCheck %s
3+
4+
// RUN: %clangxx_nsan -O3 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=NaiveSum -DFLT=float %s -o %t
5+
// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 not %run %t 2>&1 | FileCheck %s
6+
7+
// RUN: %clangxx_nsan -O0 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=KahanSum -DFLT=float %s -o %t
8+
// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t
9+
10+
// RUN: %clangxx_nsan -O3 -mllvm -nsan-shadow-type-mapping=dqq -g -DSUM=KahanSum -DFLT=float %s -o %t
11+
// RUN: NSAN_OPTIONS=halt_on_error=1,log2_max_relative_error=19 %run %t
12+
13+
#include <chrono>
14+
#include <iostream>
15+
#include <random>
16+
#include <vector>
17+
18+
// A naive, unstable summation.
19+
template <typename T>
20+
__attribute__((noinline)) // To check call stack reporting.
21+
T NaiveSum(const std::vector<T>& values) {
22+
T sum = 0;
23+
for (T v : values) {
24+
sum += v;
25+
}
26+
return sum;
27+
// CHECK: WARNING: NumericalStabilitySanitizer: inconsistent shadow results while checking return
28+
// CHECK: float{{ *}}precision (native):
29+
// CHECK: double{{ *}}precision (shadow):
30+
// CHECK: {{#0 .*in .* NaiveSum}}
31+
}
32+
33+
// Kahan's summation is a numerically stable sum.
34+
// https://en.wikipedia.org/wiki/Kahan_summation_algorithm
35+
template <typename T>
36+
__attribute__((noinline)) T KahanSum(const std::vector<T> &values) {
37+
T sum = 0;
38+
T c = 0;
39+
for (T v : values) {
40+
T y = v - c;
41+
T t = sum + y;
42+
c = (t - sum) - y;
43+
sum = t;
44+
}
45+
return sum;
46+
}
47+
48+
int main() {
49+
std::vector<FLT> values;
50+
constexpr int kNumValues = 1000000;
51+
values.reserve(kNumValues);
52+
// Using a seed to avoid flakiness.
53+
constexpr uint32_t kSeed = 0x123456;
54+
std::mt19937 gen(kSeed);
55+
std::uniform_real_distribution<FLT> dis(0.0f, 1000.0f);
56+
for (int i = 0; i < kNumValues; ++i) {
57+
values.push_back(dis(gen));
58+
}
59+
60+
const auto t1 = std::chrono::high_resolution_clock::now();
61+
const auto sum = SUM(values);
62+
const auto t2 = std::chrono::high_resolution_clock::now();
63+
printf("sum: %.8f\n", sum);
64+
std::cout << "runtime: "
65+
<< std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1)
66+
.count() /
67+
1000.0
68+
<< "ms\n";
69+
return 0;
70+
}

0 commit comments

Comments
 (0)