blob: d78678069672b1c2368d76b661576639a4952b0e [file] [log] [blame]
// RUN: %clangxx_asan -fexceptions -O %s -o %t && %env_asan_opts=detect_stack_use_after_return=0 %run %t
//
// Test __sanitizer_annotate_contiguous_container.
#include <algorithm>
#include <assert.h>
#include <sanitizer/asan_interface.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static constexpr size_t kGranularity = 8;
template <class T> static constexpr T RoundDown(T x) {
return reinterpret_cast<T>(reinterpret_cast<uintptr_t>(x) &
~(kGranularity - 1));
}
void TestContainer(size_t capacity, size_t off_begin, bool poison_buffer) {
size_t buffer_size = capacity + off_begin + kGranularity * 2;
char *buffer = new char[buffer_size];
if (poison_buffer)
__asan_poison_memory_region(buffer, buffer_size);
char *beg = buffer + off_begin;
char *end = beg + capacity;
char *mid = poison_buffer ? beg : beg + capacity;
char *old_mid;
for (int i = 0; i < 1000; i++) {
size_t size = rand() % (capacity + 1);
assert(size <= capacity);
old_mid = mid;
mid = beg + size;
__sanitizer_annotate_contiguous_container(beg, end, old_mid, mid);
char *cur = buffer;
for (; cur < buffer + RoundDown(off_begin); ++cur)
assert(__asan_address_is_poisoned(cur) == poison_buffer);
// The prefix of the first incomplete granule can switch from poisoned to
// unpoisoned but not otherwise.
for (; cur < buffer + off_begin; ++cur)
assert(poison_buffer || !__asan_address_is_poisoned(cur));
for (; cur < mid; ++cur)
assert(!__asan_address_is_poisoned(cur));
for (; cur < RoundDown(end); ++cur)
assert(__asan_address_is_poisoned(cur));
// The suffix of the last incomplete granule must be poisoned the same as
// bytes after the end.
for (; cur != end + kGranularity; ++cur)
assert(__asan_address_is_poisoned(cur) == poison_buffer);
assert(__sanitizer_verify_contiguous_container(beg, mid, end));
assert(NULL ==
__sanitizer_contiguous_container_find_bad_address(beg, mid, end));
size_t distance = (end > RoundDown(end)) ? kGranularity + 1 : 1;
if (mid >= beg + distance) {
assert(
!__sanitizer_verify_contiguous_container(beg, mid - distance, end));
assert(mid - distance ==
__sanitizer_contiguous_container_find_bad_address(
beg, mid - distance, end));
}
if (mid + distance <= end) {
assert(
!__sanitizer_verify_contiguous_container(beg, mid + distance, end));
assert(mid == __sanitizer_contiguous_container_find_bad_address(
beg, mid + distance, end));
}
}
__asan_unpoison_memory_region(buffer, buffer_size);
delete[] buffer;
}
__attribute__((noinline)) void Throw() { throw 1; }
__attribute__((noinline)) void ThrowAndCatch() {
try {
Throw();
} catch (...) {
}
}
void TestThrow() {
char x[32];
__sanitizer_annotate_contiguous_container(x, x + 32, x + 32, x + 14);
assert(!__asan_address_is_poisoned(x + 13));
assert(__asan_address_is_poisoned(x + 14));
ThrowAndCatch();
assert(!__asan_address_is_poisoned(x + 13));
assert(!__asan_address_is_poisoned(x + 14));
__sanitizer_annotate_contiguous_container(x, x + 32, x + 14, x + 32);
assert(!__asan_address_is_poisoned(x + 13));
assert(!__asan_address_is_poisoned(x + 14));
}
int main(int argc, char **argv) {
int n = argc == 1 ? 64 : atoi(argv[1]);
for (int i = 0; i <= n; i++)
for (int j = 0; j < kGranularity * 2; j++)
for (int poison = 0; poison < 2; ++poison)
TestContainer(i, j, poison);
TestThrow();
}