Skip to content

Commit 58e241a

Browse files
[compiler-rt][nsan] Add more tests for shadow memory
1 parent bccff3b commit 58e241a

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

compiler-rt/test/nsan/stable_sort.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %clangxx_nsan -O2 -g %s -o %t
2+
// RUN: %run %t 2>&1 | FileCheck %s
3+
4+
// RUN: %clangxx_nsan -fno-builtin -O2 -g %s -o %t
5+
// RUN: %run %t 2>&1 | FileCheck %s
6+
7+
// This tests a particularaly hard case of memory tracking. stable_sort does
8+
// conditional swaps of pairs of elements with mixed types (int/double).
9+
10+
#include <algorithm>
11+
#include <cstddef>
12+
#include <cstdio>
13+
#include <utility>
14+
#include <vector>
15+
16+
extern "C" void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes,
17+
size_t bytes_per_line, size_t reserved);
18+
19+
__attribute__((noinline)) void Run(std::vector<int> &indices,
20+
std::vector<double> &values) {
21+
const auto num_entries = indices.size();
22+
std::vector<std::pair<int, double>> entries;
23+
entries.reserve(num_entries);
24+
for (int i = 0; i < num_entries; ++i) {
25+
entries.emplace_back(indices[i], values[i]);
26+
}
27+
__nsan_dump_shadow_mem((const char *)&entries[0].second, sizeof(double),
28+
sizeof(double), 0);
29+
__nsan_dump_shadow_mem((const char *)&entries[1].second, sizeof(double),
30+
sizeof(double), 0);
31+
// CHECK: {{.*}}: d0 d1 d2 d3 d4 d5 d6 d7 (1.02800000000000002487)
32+
// CHECK-NEXT: {{.*}}: d0 d1 d2 d3 d4 d5 d6 d7 (7.95099999999999962341)
33+
std::stable_sort(
34+
entries.begin(), entries.end(),
35+
[](const std::pair<int, double> &a, const std::pair<int, double> &b) {
36+
return a.first < b.first;
37+
});
38+
__nsan_dump_shadow_mem((const char *)&entries[0].second, sizeof(double),
39+
sizeof(double), 0);
40+
__nsan_dump_shadow_mem((const char *)&entries[1].second, sizeof(double),
41+
sizeof(double), 0);
42+
// We make sure that the shadow values have been swapped correctly.
43+
// CHECK-NEXT: {{.*}}: d0 d1 d2 d3 d4 d5 d6 d7 (7.95099999999999962341)
44+
// CHECK-NEXT: {{.*}}: d0 d1 d2 d3 d4 d5 d6 d7 (1.02800000000000002487)
45+
}
46+
47+
int main() {
48+
std::vector<int> indices;
49+
std::vector<double> values;
50+
indices.push_back(75);
51+
values.push_back(1.028);
52+
indices.push_back(74);
53+
values.push_back(7.951);
54+
Run(indices, values);
55+
}

compiler-rt/test/nsan/swap.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %clangxx_nsan -O2 %s -o %t
2+
// RUN: %run %t 2>&1 | FileCheck %s
3+
4+
// RUN: %clangxx_nsan -fno-builtin -O2 %s -o %t
5+
// RUN: %run %t 2>&1 | FileCheck %s
6+
7+
// This verifies that shadow memory is tracked correcty across typed and
8+
// bitcasted swaps.
9+
10+
#include <cassert>
11+
#include <cstddef>
12+
#include <cstdint>
13+
#include <utility>
14+
15+
extern "C" void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes,
16+
size_t bytes_per_line, size_t reserved);
17+
18+
__attribute__((noinline)) void SwapFT(double *a, double *b) {
19+
// LLVM typically optimizes this to an untyped swap (through i64) anyway.
20+
std::swap(*a, *b);
21+
}
22+
23+
__attribute__((noinline)) void SwapBitcasted(uint64_t *a, uint64_t *b) {
24+
std::swap(*a, *b);
25+
}
26+
27+
int main() {
28+
double a = 1.0, b = 2.0;
29+
__nsan_dump_shadow_mem((const char *)&a, sizeof(a), sizeof(a), 0);
30+
__nsan_dump_shadow_mem((const char *)&b, sizeof(b), sizeof(b), 0);
31+
SwapFT(&a, &b);
32+
__nsan_dump_shadow_mem((const char *)&a, sizeof(a), sizeof(a), 0);
33+
__nsan_dump_shadow_mem((const char *)&b, sizeof(b), sizeof(b), 0);
34+
assert(a == 2.0 && b == 1.0);
35+
SwapBitcasted(reinterpret_cast<uint64_t *>(&a),
36+
reinterpret_cast<uint64_t *>(&b));
37+
__nsan_dump_shadow_mem((const char *)&a, sizeof(a), sizeof(a), 0);
38+
__nsan_dump_shadow_mem((const char *)&b, sizeof(b), sizeof(b), 0);
39+
assert(a == 1.0 && b == 2.0);
40+
// CHECK: 0x{{[a-f0-9]*}}: d0 d1 d2 d3 d4 d5 d6 d7 (1.0{{.*}}
41+
// CHECK-NEXT: 0x{{[a-f0-9]*}}: d0 d1 d2 d3 d4 d5 d6 d7 (2.0{{.*}}
42+
// CHECK-NEXT: 0x{{[a-f0-9]*}}: d0 d1 d2 d3 d4 d5 d6 d7 (2.0{{.*}}
43+
// CHECK-NEXT: 0x{{[a-f0-9]*}}: d0 d1 d2 d3 d4 d5 d6 d7 (1.0{{.*}}
44+
// CHECK-NEXT: 0x{{[a-f0-9]*}}: d0 d1 d2 d3 d4 d5 d6 d7 (1.0{{.*}}
45+
// CHECK-NEXT: 0x{{[a-f0-9]*}}: d0 d1 d2 d3 d4 d5 d6 d7 (2.0{{.*}}
46+
}

0 commit comments

Comments
 (0)