Skip to content

Commit d5617ad

Browse files
[compiler-rt][nsan] Add more tests for shadow memory (#100906)
Add more tests for shadow memory.
1 parent e306db0 commit d5617ad

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

compiler-rt/test/nsan/stable_sort.cpp

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

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)