1 // RUN: %clangxx_asan -fexceptions -O %s -o %t && %env_asan_opts=detect_stack_use_after_return=0 %run %t
3 // Test __sanitizer_annotate_contiguous_container.
10 #include <sanitizer/asan_interface.h>
15 static constexpr size_t kGranularity
= 8;
17 template <class T
> static constexpr T
RoundDown(T x
) {
18 return reinterpret_cast<T
>(reinterpret_cast<uintptr_t>(x
) &
22 static std::vector
<int> GetPoisonedState(char *begin
, char *end
) {
23 std::vector
<int> result
;
24 for (; begin
!= end
;) {
26 for (; begin
!= end
&& __asan_address_is_poisoned(begin
); ++begin
)
28 result
.push_back(poisoned
);
30 for (; begin
!= end
&& !__asan_address_is_poisoned(begin
); ++begin
)
32 result
.push_back(unpoisoned
);
37 static int GetFirstMismatch(const std::vector
<int> &a
,
38 const std::vector
<int> &b
) {
39 auto mismatch
= std::mismatch(a
.begin(), a
.end(), b
.begin(), b
.end());
40 return std::accumulate(a
.begin(), mismatch
.first
, 0) +
41 std::min(*mismatch
.first
, *mismatch
.second
);
44 void TestContainer(size_t capacity
, size_t off_begin
, bool poison_buffer
) {
45 size_t buffer_size
= capacity
+ off_begin
+ kGranularity
* 2;
46 char *buffer
= new char[buffer_size
];
48 __asan_poison_memory_region(buffer
, buffer_size
);
49 char *st_beg
= buffer
+ off_begin
;
50 char *st_end
= st_beg
+ capacity
;
51 char *end
= poison_buffer
? st_beg
: st_end
;
53 for (int i
= 0; i
< 1000; i
++) {
54 size_t size
= rand() % (capacity
+ 1);
55 assert(size
<= capacity
);
58 __sanitizer_annotate_contiguous_container(st_beg
, st_end
, old_end
, end
);
61 for (; cur
< RoundDown(st_beg
); ++cur
)
62 assert(__asan_address_is_poisoned(cur
) == poison_buffer
);
63 // The prefix of the first incomplete granule can switch from poisoned to
64 // unpoisoned but not otherwise.
65 for (; cur
< st_beg
; ++cur
)
66 assert(poison_buffer
|| !__asan_address_is_poisoned(cur
));
67 for (; cur
< end
; ++cur
)
68 assert(!__asan_address_is_poisoned(cur
));
69 for (; cur
< RoundDown(st_end
); ++cur
)
70 assert(__asan_address_is_poisoned(cur
));
71 // The suffix of the last incomplete granule must be poisoned the same as
72 // bytes after the end.
73 for (; cur
!= st_end
+ kGranularity
; ++cur
)
74 assert(__asan_address_is_poisoned(cur
) == poison_buffer
);
77 // Precalculate masks.
78 std::vector
<std::vector
<int>> masks(capacity
+ 1);
79 for (int i
= 0; i
<= capacity
; i
++) {
82 __sanitizer_annotate_contiguous_container(st_beg
, st_end
, old_end
, end
);
83 masks
[i
] = GetPoisonedState(st_beg
, st_end
);
85 for (int i
= 0; i
<= capacity
; i
++) {
88 __sanitizer_annotate_contiguous_container(st_beg
, st_end
, old_end
, end
);
90 char *cur_first
= std::max(end
- 2 * kGranularity
, st_beg
);
91 char *cur_last
= std::min(end
+ 2 * kGranularity
, st_end
);
92 for (char *cur
= cur_first
; cur
<= cur_last
; ++cur
) {
94 __sanitizer_verify_contiguous_container(st_beg
, cur
, st_end
);
95 const void *bad_address
=
96 __sanitizer_contiguous_container_find_bad_address(st_beg
, cur
,
99 // The last unaligned granule of the storage followed by unpoisoned
100 // bytes looks the same.
101 (!poison_buffer
&& RoundDown(st_end
) <= std::min(cur
, end
))) {
103 assert(!bad_address
);
107 assert(bad_address
== std::min(cur
, end
));
108 assert(bad_address
==
109 st_beg
+ GetFirstMismatch(masks
[i
], masks
[cur
- st_beg
]));
113 __asan_unpoison_memory_region(buffer
, buffer_size
);
117 void TestDoubleEndedContainer(size_t capacity
, size_t off_begin
,
118 bool poison_buffer
) {
119 size_t buffer_size
= capacity
+ off_begin
+ kGranularity
* 2;
120 char *buffer
= new char[buffer_size
];
122 __asan_poison_memory_region(buffer
, buffer_size
);
123 char *st_beg
= buffer
+ off_begin
;
124 char *st_end
= st_beg
+ capacity
;
126 char *end
= poison_buffer
? st_beg
: st_end
;
128 for (int i
= 0; i
< 1000; i
++) {
129 size_t size
= rand() % (capacity
+ 1);
130 size_t skipped
= rand() % (capacity
- size
+ 1);
131 assert(size
<= capacity
);
134 beg
= st_beg
+ skipped
;
137 __sanitizer_annotate_double_ended_contiguous_container(
138 st_beg
, st_end
, old_beg
, old_end
, beg
, end
);
141 for (; cur
< RoundDown(st_beg
); ++cur
)
142 assert(__asan_address_is_poisoned(cur
) == poison_buffer
);
143 // The prefix of the first incomplete granule can switch from poisoned to
144 // unpoisoned but not otherwise.
145 for (; cur
< st_beg
; ++cur
)
146 assert(poison_buffer
|| !__asan_address_is_poisoned(cur
));
148 for (; cur
< RoundDown(beg
); ++cur
)
149 assert(__asan_address_is_poisoned(cur
));
151 for (; cur
< end
; ++cur
)
152 assert(!__asan_address_is_poisoned(cur
));
154 for (; cur
< RoundDown(st_end
); ++cur
)
155 assert(__asan_address_is_poisoned(cur
));
156 // The suffix of the last incomplete granule must be poisoned the same as
157 // bytes after the end.
158 for (; cur
!= st_end
+ kGranularity
; ++cur
)
159 assert(__asan_address_is_poisoned(cur
) == poison_buffer
);
164 // Precalculate masks.
165 std::vector
<std::vector
<std::vector
<int>>> masks(
166 capacity
+ 1, std::vector
<std::vector
<int>>(capacity
+ 1));
167 for (int i
= 0; i
<= capacity
; i
++) {
168 for (int j
= i
; j
<= capacity
; j
++) {
173 __sanitizer_annotate_double_ended_contiguous_container(
174 st_beg
, st_end
, old_beg
, old_end
, beg
, end
);
175 masks
[i
][j
] = GetPoisonedState(st_beg
, st_end
);
179 for (int i
= 0; i
<= capacity
; i
++) {
180 for (int j
= i
; j
<= capacity
; j
++) {
185 __sanitizer_annotate_double_ended_contiguous_container(
186 st_beg
, st_end
, old_beg
, old_end
, beg
, end
);
188 // Try to mismatch the end of the container.
189 char *cur_first
= std::max(end
- 2 * kGranularity
, beg
);
190 char *cur_last
= std::min(end
+ 2 * kGranularity
, st_end
);
191 for (char *cur
= cur_first
; cur
<= cur_last
; ++cur
) {
192 bool is_valid
= __sanitizer_verify_double_ended_contiguous_container(
193 st_beg
, beg
, cur
, st_end
);
194 const void *bad_address
=
195 __sanitizer_double_ended_contiguous_container_find_bad_address(
196 st_beg
, beg
, cur
, st_end
);
199 // The last unaligned granule of the storage followed by unpoisoned
200 // bytes looks the same.
201 (!poison_buffer
&& RoundDown(st_end
) <= std::min(cur
, end
))) {
203 assert(!bad_address
);
209 assert(bad_address
==
211 GetFirstMismatch(masks
[i
][j
], masks
[i
][cur
- st_beg
]));
214 // Try to mismatch the begin of the container.
215 cur_first
= std::max(beg
- 2 * kGranularity
, st_beg
);
216 cur_last
= std::min(beg
+ 2 * kGranularity
, end
);
217 for (char *cur
= cur_first
; cur
<= cur_last
; ++cur
) {
218 bool is_valid
= __sanitizer_verify_double_ended_contiguous_container(
219 st_beg
, cur
, end
, st_end
);
220 const void *bad_address
=
221 __sanitizer_double_ended_contiguous_container_find_bad_address(
222 st_beg
, cur
, end
, st_end
);
225 // The last unaligned granule of the storage followed by unpoisoned
226 // bytes looks the same.
227 (!poison_buffer
&& RoundDown(st_end
) <= std::min(cur
, beg
) ||
228 // The first unaligned granule of non-empty container looks the
230 (std::max(beg
, cur
) < end
&&
231 RoundDown(beg
) == RoundDown(cur
)))) {
233 assert(!bad_address
);
238 assert(bad_address
==
240 GetFirstMismatch(masks
[i
][j
], masks
[cur
- st_beg
][j
]));
246 __asan_unpoison_memory_region(buffer
, buffer_size
);
250 __attribute__((noinline
)) void Throw() { throw 1; }
252 __attribute__((noinline
)) void ThrowAndCatch() {
261 __sanitizer_annotate_contiguous_container(x
, x
+ 32, x
+ 32, x
+ 14);
262 assert(!__asan_address_is_poisoned(x
+ 13));
263 assert(__asan_address_is_poisoned(x
+ 14));
265 assert(!__asan_address_is_poisoned(x
+ 13));
266 assert(!__asan_address_is_poisoned(x
+ 14));
267 __sanitizer_annotate_contiguous_container(x
, x
+ 32, x
+ 14, x
+ 32);
268 assert(!__asan_address_is_poisoned(x
+ 13));
269 assert(!__asan_address_is_poisoned(x
+ 14));
272 int main(int argc
, char **argv
) {
273 int n
= argc
== 1 ? 64 : atoi(argv
[1]);
274 for (int i
= 0; i
<= n
; i
++) {
275 for (int j
= 0; j
< kGranularity
* 2; j
++) {
276 for (int poison
= 0; poison
< 2; ++poison
) {
277 TestContainer(i
, j
, poison
);
278 TestDoubleEndedContainer(i
, j
, poison
);