1 // RUN: %clangxx_asan -fexceptions -O %s -o %t && %env_asan_opts=detect_stack_use_after_return=0 %run %t
3 // Test __sanitizer_copy_contiguous_container_annotations.
12 #include <sanitizer/asan_interface.h>
17 static constexpr size_t kGranularity
= 8;
19 template <class T
> static constexpr T
RoundDown(T x
) {
20 return reinterpret_cast<T
>(reinterpret_cast<uintptr_t>(x
) &
23 template <class T
> static constexpr T
RoundUp(T x
) {
24 return reinterpret_cast<T
>(
25 RoundDown(reinterpret_cast<uintptr_t>(x
) + kGranularity
- 1));
28 static std::vector
<int> GetPoisonedState(char *begin
, char *end
) {
29 std::vector
<int> result
;
30 for (char *ptr
= begin
; ptr
!= end
; ++ptr
) {
31 result
.push_back(__asan_address_is_poisoned(ptr
));
36 static void RandomPoison(char *beg
, char *end
) {
37 assert(beg
== RoundDown(beg
));
38 assert(end
== RoundDown(end
));
39 __asan_poison_memory_region(beg
, end
- beg
);
40 for (beg
= RoundUp(beg
); beg
< end
; beg
+= kGranularity
) {
41 __asan_unpoison_memory_region(beg
, rand() % (kGranularity
+ 1));
45 template <bool benchmark
>
46 static void Test(size_t capacity
, size_t off_src
, size_t off_dst
,
47 char *src_buffer_beg
, char *src_buffer_end
,
48 char *dst_buffer_beg
, char *dst_buffer_end
) {
49 size_t dst_buffer_size
= dst_buffer_end
- dst_buffer_beg
;
50 char *src_beg
= src_buffer_beg
+ off_src
;
51 char *src_end
= src_beg
+ capacity
;
53 char *dst_beg
= dst_buffer_beg
+ off_dst
;
54 char *dst_end
= dst_beg
+ capacity
;
56 __sanitizer_copy_contiguous_container_annotations(src_beg
, src_end
, dst_beg
,
61 std::vector
<int> src_poison_states
=
62 GetPoisonedState(src_buffer_beg
, src_buffer_end
);
63 std::vector
<int> dst_poison_before
=
64 GetPoisonedState(dst_buffer_beg
, dst_buffer_end
);
65 __sanitizer_copy_contiguous_container_annotations(src_beg
, src_end
, dst_beg
,
67 std::vector
<int> dst_poison_after
=
68 GetPoisonedState(dst_buffer_beg
, dst_buffer_end
);
70 // Create ideal copy of src over dst.
71 std::vector
<int> dst_poison_exp
= dst_poison_before
;
72 for (size_t cur
= 0; cur
< capacity
; ++cur
)
73 dst_poison_exp
[off_dst
+ cur
] = src_poison_states
[off_src
+ cur
];
75 // Unpoison prefixes of Asan granules.
76 for (size_t cur
= dst_buffer_size
- 1; cur
> 0; --cur
) {
77 if (cur
% kGranularity
!= 0 && !dst_poison_exp
[cur
])
78 dst_poison_exp
[cur
- 1] = 0;
81 if (dst_poison_after
!= dst_poison_exp
) {
82 std::cerr
<< "[" << off_dst
<< ", " << off_dst
+ capacity
<< ")\n";
83 for (size_t i
= 0; i
< dst_poison_after
.size(); ++i
) {
84 std::cerr
<< i
<< ":\t" << dst_poison_before
[i
] << "\t"
85 << dst_poison_after
[i
] << "\t" << dst_poison_exp
[i
] << "\n";
87 std::cerr
<< "----------\n";
89 assert(dst_poison_after
== dst_poison_exp
);
93 template <bool benchmark
>
94 static void TestNonOverlappingContainers(size_t capacity
, size_t off_src
,
96 // Test will copy [off_src, off_src + capacity) to [off_dst, off_dst + capacity).
97 // Allocate buffers to have additional granule before and after tested ranges.
98 off_src
+= kGranularity
;
99 off_dst
+= kGranularity
;
100 size_t src_buffer_size
= RoundUp(off_src
+ capacity
) + kGranularity
;
101 size_t dst_buffer_size
= RoundUp(off_dst
+ capacity
) + kGranularity
;
103 std::unique_ptr
<char[]> src_buffer
=
104 std::make_unique
<char[]>(src_buffer_size
);
105 std::unique_ptr
<char[]> dst_buffer
=
106 std::make_unique
<char[]>(dst_buffer_size
);
108 char *src_buffer_beg
= src_buffer
.get();
109 char *src_buffer_end
= src_buffer_beg
+ src_buffer_size
;
110 assert(RoundDown(src_buffer_beg
) == src_buffer_beg
);
112 char *dst_buffer_beg
= dst_buffer
.get();
113 char *dst_buffer_end
= dst_buffer_beg
+ dst_buffer_size
;
114 assert(RoundDown(dst_buffer_beg
) == dst_buffer_beg
);
116 for (int i
= 0; i
< 35; i
++) {
117 if (!benchmark
|| !i
) {
118 RandomPoison(src_buffer_beg
, src_buffer_end
);
119 RandomPoison(dst_buffer_beg
, dst_buffer_end
);
122 Test
<benchmark
>(capacity
, off_src
, off_dst
, src_buffer_beg
, src_buffer_end
,
123 dst_buffer_beg
, dst_buffer_end
);
126 __asan_unpoison_memory_region(src_buffer_beg
, src_buffer_size
);
127 __asan_unpoison_memory_region(dst_buffer_beg
, dst_buffer_size
);
130 template <bool benchmark
>
131 static void TestOverlappingContainers(size_t capacity
, size_t off_src
,
133 // Test will copy [off_src, off_src + capacity) to [off_dst, off_dst + capacity).
134 // Allocate buffers to have additional granule before and after tested ranges.
135 off_src
+= kGranularity
;
136 off_dst
+= kGranularity
;
138 RoundUp(std::max(off_src
, off_dst
) + capacity
) + kGranularity
;
140 // Use unique_ptr with a custom deleter to manage the buffer
141 std::unique_ptr
<char[]> buffer
= std::make_unique
<char[]>(buffer_size
);
143 char *buffer_beg
= buffer
.get();
144 char *buffer_end
= buffer_beg
+ buffer_size
;
145 assert(RoundDown(buffer_beg
) == buffer_beg
);
147 for (int i
= 0; i
< 35; i
++) {
148 if (!benchmark
|| !i
)
149 RandomPoison(buffer_beg
, buffer_end
);
150 Test
<benchmark
>(capacity
, off_src
, off_dst
, buffer_beg
, buffer_end
,
151 buffer_beg
, buffer_end
);
154 __asan_unpoison_memory_region(buffer_beg
, buffer_size
);
157 int main(int argc
, char **argv
) {
158 int n
= argc
== 1 ? 64 : atoi(argv
[1]);
159 for (size_t off_src
= 0; off_src
< kGranularity
; off_src
++) {
160 for (size_t off_dst
= 0; off_dst
< kGranularity
; off_dst
++) {
161 for (int capacity
= 0; capacity
<= n
; capacity
++) {
163 TestNonOverlappingContainers
<false>(capacity
, off_src
, off_dst
);
164 TestOverlappingContainers
<false>(capacity
, off_src
, off_dst
);
166 TestNonOverlappingContainers
<true>(capacity
, off_src
, off_dst
);
167 TestOverlappingContainers
<true>(capacity
, off_src
, off_dst
);