blob: ba636439f9077af1de9817249ad9d43f7d3c9dea [file] [log] [blame]
//===-- sanitizer_allocator64_test.cc -------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for sanitizer_allocator64.h.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_allocator64.h"
#include "gtest/gtest.h"
#include <algorithm>
#include <vector>
TEST(SanitizerCommon, DefaultSizeClassMap) {
typedef DefaultSizeClassMap SCMap;
#if 0
for (uptr i = 0; i < SCMap::kNumClasses; i++) {
// printf("% 3ld: % 5ld (%4lx); ", i, SCMap::Size(i), SCMap::Size(i));
printf("c%ld => %ld ", i, SCMap::Size(i));
if ((i % 8) == 7)
printf("\n");
}
printf("\n");
#endif
for (uptr c = 0; c < SCMap::kNumClasses; c++) {
uptr s = SCMap::Size(c);
CHECK_EQ(SCMap::ClassID(s), c);
if (c != SCMap::kNumClasses - 1)
CHECK_EQ(SCMap::ClassID(s + 1), c + 1);
CHECK_EQ(SCMap::ClassID(s - 1), c);
if (c)
CHECK_GT(SCMap::Size(c), SCMap::Size(c-1));
}
CHECK_EQ(SCMap::ClassID(SCMap::kMaxSize + 1), 0);
for (uptr s = 1; s <= SCMap::kMaxSize; s++) {
uptr c = SCMap::ClassID(s);
CHECK_LT(c, SCMap::kNumClasses);
CHECK_GE(SCMap::Size(c), s);
if (c > 0)
CHECK_LT(SCMap::Size(c-1), s);
}
}
static const uptr kAllocatorSpace = 0x600000000000ULL;
static const uptr kAllocatorSize = 0x10000000000; // 1T.
TEST(SanitizerCommon, SizeClassAllocator64) {
typedef DefaultSizeClassMap SCMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
16, SCMap> Allocator;
Allocator a;
a.Init();
static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
50000, 60000, 100000, 300000, 500000, 1000000, 2000000};
std::vector<void *> allocated;
uptr last_total_allocated = 0;
for (int i = 0; i < 5; i++) {
// Allocate a bunch of chunks.
for (uptr s = 0; s < sizeof(sizes) /sizeof(sizes[0]); s++) {
uptr size = sizes[s];
// printf("s = %ld\n", size);
uptr n_iter = std::max((uptr)2, 1000000 / size);
for (uptr i = 0; i < n_iter; i++) {
void *x = a.Allocate(size, 1);
allocated.push_back(x);
CHECK(a.PointerIsMine(x));
uptr class_id = a.GetSizeClass(x);
CHECK_EQ(class_id, SCMap::ClassID(size));
uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
metadata[0] = reinterpret_cast<uptr>(x) + 1;
metadata[1] = 0xABCD;
}
}
// Deallocate all.
for (uptr i = 0; i < allocated.size(); i++) {
void *x = allocated[i];
uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
CHECK_EQ(metadata[1], 0xABCD);
a.Deallocate(x);
}
allocated.clear();
uptr total_allocated = a.TotalMemoryUsed();
if (last_total_allocated == 0)
last_total_allocated = total_allocated;
CHECK_EQ(last_total_allocated, total_allocated);
}
a.TestOnlyUnmap();
}
TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
typedef DefaultSizeClassMap SCMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
16, SCMap> Allocator;
Allocator a;
a.Init();
static volatile void *sink;
const uptr kNumAllocs = 10000;
void *allocated[kNumAllocs];
for (uptr i = 0; i < kNumAllocs; i++) {
uptr size = (i % 4096) + 1;
void *x = a.Allocate(size, 1);
allocated[i] = x;
}
// Get Metadata kNumAllocs^2 times.
for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
sink = a.GetMetaData(allocated[i % kNumAllocs]);
}
for (uptr i = 0; i < kNumAllocs; i++) {
a.Deallocate(allocated[i]);
}
a.TestOnlyUnmap();
}
void FailInAssertionOnOOM() {
typedef DefaultSizeClassMap SCMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
16, SCMap> Allocator;
Allocator a;
a.Init();
const uptr size = 1 << 20;
for (int i = 0; i < 1000000; i++) {
a.Allocate(size, 1);
}
a.TestOnlyUnmap();
}
TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
EXPECT_DEATH(FailInAssertionOnOOM(),
"allocated_user.*allocated_meta.*kRegionSize");
}
TEST(SanitizerCommon, LargeMmapAllocator) {
LargeMmapAllocator a;
a.Init();
static const int kNumAllocs = 100;
void *allocated[kNumAllocs];
static const uptr size = 1000;
// Allocate some.
for (int i = 0; i < kNumAllocs; i++) {
allocated[i] = a.Allocate(size, 1);
}
// Deallocate all.
CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
for (int i = 0; i < kNumAllocs; i++) {
void *p = allocated[i];
CHECK(a.PointerIsMine(p));
a.Deallocate(p);
}
// Check that non left.
CHECK_EQ(a.TotalMemoryUsed(), 0);
// Allocate some more, also add metadata.
for (int i = 0; i < kNumAllocs; i++) {
void *x = a.Allocate(size, 1);
uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
*meta = i;
allocated[i] = x;
}
CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
// Deallocate all in reverse order.
for (int i = 0; i < kNumAllocs; i++) {
int idx = kNumAllocs - i - 1;
void *p = allocated[idx];
uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
CHECK_EQ(*meta, idx);
CHECK(a.PointerIsMine(p));
a.Deallocate(p);
}
CHECK_EQ(a.TotalMemoryUsed(), 0);
}
TEST(SanitizerCommon, CombinedAllocator) {
typedef DefaultSizeClassMap SCMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
16, SCMap> PrimaryAllocator;
typedef LargeMmapAllocator SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, SecondaryAllocator> Allocator;
Allocator a;
a.Init();
const uptr kNumAllocs = 100000;
const uptr kNumIter = 10;
for (uptr iter = 0; iter < kNumIter; iter++) {
std::vector<void*> allocated;
for (uptr i = 0; i < kNumAllocs; i++) {
uptr size = (i % (1 << 14)) + 1;
if ((i % 1024) == 0)
size = 1 << (10 + (i % 14));
void *x = a.Allocate(size, 1);
uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
CHECK_EQ(*meta, 0);
*meta = size;
allocated.push_back(x);
}
random_shuffle(allocated.begin(), allocated.end());
for (uptr i = 0; i < kNumAllocs; i++) {
void *x = allocated[i];
uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
CHECK_NE(*meta, 0);
CHECK(a.PointerIsMine(x));
*meta = 0;
a.Deallocate(x);
}
allocated.clear();
}
a.TestOnlyUnmap();
}