Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 1 | //===-- sanitizer_allocator_test.cc ---------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
Dmitry Vyukov | a3eca81 | 2012-06-29 17:32:18 +0000 | [diff] [blame] | 10 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 11 | // Tests for sanitizer_allocator.h. |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 14 | #include "sanitizer_common/sanitizer_allocator.h" |
Alexey Samsonov | 1f3c2fe | 2013-05-29 09:15:39 +0000 | [diff] [blame] | 15 | #include "sanitizer_common/sanitizer_allocator_internal.h" |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 16 | #include "sanitizer_common/sanitizer_common.h" |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 17 | |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 18 | #include "sanitizer_test_utils.h" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 19 | #include "sanitizer_pthread_wrappers.h" |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 20 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 21 | #include "gtest/gtest.h" |
| 22 | |
| 23 | #include <stdlib.h> |
| 24 | #include <algorithm> |
| 25 | #include <vector> |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 26 | #include <set> |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 27 | |
Dmitry Vyukov | 68902f4 | 2012-12-14 10:17:22 +0000 | [diff] [blame] | 28 | // Too slow for debug build |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 29 | #if !SANITIZER_DEBUG |
Dmitry Vyukov | 68902f4 | 2012-12-14 10:17:22 +0000 | [diff] [blame] | 30 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 31 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 32 | static const uptr kAllocatorSpace = 0x700000000000ULL; |
| 33 | static const uptr kAllocatorSize = 0x010000000000ULL; // 1T. |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 34 | static const u64 kAddressSpaceSize = 1ULL << 47; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 35 | |
| 36 | typedef SizeClassAllocator64< |
| 37 | kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap> Allocator64; |
| 38 | |
| 39 | typedef SizeClassAllocator64< |
| 40 | kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 41 | #elif defined(__mips64) |
| 42 | static const u64 kAddressSpaceSize = 1ULL << 40; |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 43 | #else |
| 44 | static const u64 kAddressSpaceSize = 1ULL << 32; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 45 | #endif |
| 46 | |
Kostya Serebryany | 1b54cbf | 2013-05-20 07:29:21 +0000 | [diff] [blame] | 47 | static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24); |
| 48 | static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog; |
| 49 | |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 50 | typedef SizeClassAllocator32< |
Kostya Serebryany | 1b54cbf | 2013-05-20 07:29:21 +0000 | [diff] [blame] | 51 | 0, kAddressSpaceSize, |
| 52 | /*kMetadataSize*/16, |
| 53 | CompactSizeClassMap, |
| 54 | kRegionSizeLog, |
| 55 | FlatByteMap<kFlatByteMapSize> > |
| 56 | Allocator32Compact; |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 57 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 58 | template <class SizeClassMap> |
| 59 | void TestSizeClassMap() { |
| 60 | typedef SizeClassMap SCMap; |
Kostya Serebryany | bb5d057 | 2012-12-25 07:50:35 +0000 | [diff] [blame] | 61 | // SCMap::Print(); |
Kostya Serebryany | 038820f | 2012-12-24 13:41:07 +0000 | [diff] [blame] | 62 | SCMap::Validate(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | TEST(SanitizerCommon, DefaultSizeClassMap) { |
| 66 | TestSizeClassMap<DefaultSizeClassMap>(); |
| 67 | } |
| 68 | |
| 69 | TEST(SanitizerCommon, CompactSizeClassMap) { |
| 70 | TestSizeClassMap<CompactSizeClassMap>(); |
| 71 | } |
| 72 | |
Alexey Samsonov | 1f3c2fe | 2013-05-29 09:15:39 +0000 | [diff] [blame] | 73 | TEST(SanitizerCommon, InternalSizeClassMap) { |
| 74 | TestSizeClassMap<InternalSizeClassMap>(); |
| 75 | } |
| 76 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 77 | template <class Allocator> |
| 78 | void TestSizeClassAllocator() { |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 79 | Allocator *a = new Allocator; |
| 80 | a->Init(); |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 81 | SizeClassAllocatorLocalCache<Allocator> cache; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 82 | memset(&cache, 0, sizeof(cache)); |
| 83 | cache.Init(0); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 84 | |
| 85 | static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000, |
Kostya Serebryany | b1f21c6 | 2012-12-19 06:51:45 +0000 | [diff] [blame] | 86 | 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000}; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 87 | |
| 88 | std::vector<void *> allocated; |
| 89 | |
| 90 | uptr last_total_allocated = 0; |
Kostya Serebryany | b1f21c6 | 2012-12-19 06:51:45 +0000 | [diff] [blame] | 91 | for (int i = 0; i < 3; i++) { |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 92 | // Allocate a bunch of chunks. |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 93 | for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) { |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 94 | uptr size = sizes[s]; |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 95 | if (!a->CanAllocate(size, 1)) continue; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 96 | // printf("s = %ld\n", size); |
Evgeniy Stepanov | 7fe5526 | 2013-02-19 13:38:27 +0000 | [diff] [blame] | 97 | uptr n_iter = std::max((uptr)6, 8000000 / size); |
Kostya Serebryany | b1f21c6 | 2012-12-19 06:51:45 +0000 | [diff] [blame] | 98 | // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 99 | for (uptr i = 0; i < n_iter; i++) { |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 100 | uptr class_id0 = Allocator::SizeClassMapT::ClassID(size); |
| 101 | char *x = (char*)cache.Allocate(a, class_id0); |
Kostya Serebryany | d9b7404 | 2012-12-15 18:36:23 +0000 | [diff] [blame] | 102 | x[0] = 0; |
| 103 | x[size - 1] = 0; |
| 104 | x[size / 2] = 0; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 105 | allocated.push_back(x); |
Kostya Serebryany | 8a41bdc | 2012-12-06 13:13:58 +0000 | [diff] [blame] | 106 | CHECK_EQ(x, a->GetBlockBegin(x)); |
Kostya Serebryany | d9b7404 | 2012-12-15 18:36:23 +0000 | [diff] [blame] | 107 | CHECK_EQ(x, a->GetBlockBegin(x + size - 1)); |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 108 | CHECK(a->PointerIsMine(x)); |
Kostya Serebryany | da1f82b | 2012-12-18 14:56:38 +0000 | [diff] [blame] | 109 | CHECK(a->PointerIsMine(x + size - 1)); |
| 110 | CHECK(a->PointerIsMine(x + size / 2)); |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 111 | CHECK_GE(a->GetActuallyAllocatedSize(x), size); |
| 112 | uptr class_id = a->GetSizeClass(x); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 113 | CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size)); |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 114 | uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x)); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 115 | metadata[0] = reinterpret_cast<uptr>(x) + 1; |
| 116 | metadata[1] = 0xABCD; |
| 117 | } |
| 118 | } |
| 119 | // Deallocate all. |
| 120 | for (uptr i = 0; i < allocated.size(); i++) { |
| 121 | void *x = allocated[i]; |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 122 | uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x)); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 123 | CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1); |
| 124 | CHECK_EQ(metadata[1], 0xABCD); |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 125 | cache.Deallocate(a, a->GetSizeClass(x), x); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 126 | } |
| 127 | allocated.clear(); |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 128 | uptr total_allocated = a->TotalMemoryUsed(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 129 | if (last_total_allocated == 0) |
| 130 | last_total_allocated = total_allocated; |
| 131 | CHECK_EQ(last_total_allocated, total_allocated); |
| 132 | } |
| 133 | |
Kostya Serebryany | aa0f20d | 2013-03-11 09:43:12 +0000 | [diff] [blame] | 134 | // Check that GetBlockBegin never crashes. |
| 135 | for (uptr x = 0, step = kAddressSpaceSize / 100000; |
| 136 | x < kAddressSpaceSize - step; x += step) |
| 137 | if (a->PointerIsMine(reinterpret_cast<void *>(x))) |
| 138 | Ident(a->GetBlockBegin(reinterpret_cast<void *>(x))); |
| 139 | |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 140 | a->TestOnlyUnmap(); |
| 141 | delete a; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 142 | } |
| 143 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 144 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 145 | TEST(SanitizerCommon, SizeClassAllocator64) { |
| 146 | TestSizeClassAllocator<Allocator64>(); |
| 147 | } |
| 148 | |
| 149 | TEST(SanitizerCommon, SizeClassAllocator64Compact) { |
| 150 | TestSizeClassAllocator<Allocator64Compact>(); |
| 151 | } |
| 152 | #endif |
| 153 | |
Kostya Serebryany | 45595ba | 2012-12-06 12:49:28 +0000 | [diff] [blame] | 154 | TEST(SanitizerCommon, SizeClassAllocator32Compact) { |
| 155 | TestSizeClassAllocator<Allocator32Compact>(); |
| 156 | } |
| 157 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 158 | template <class Allocator> |
Kostya Serebryany | 784935d | 2012-12-06 13:00:11 +0000 | [diff] [blame] | 159 | void SizeClassAllocatorMetadataStress() { |
| 160 | Allocator *a = new Allocator; |
| 161 | a->Init(); |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 162 | SizeClassAllocatorLocalCache<Allocator> cache; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 163 | memset(&cache, 0, sizeof(cache)); |
| 164 | cache.Init(0); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 165 | |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 166 | const uptr kNumAllocs = 1 << 13; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 167 | void *allocated[kNumAllocs]; |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 168 | void *meta[kNumAllocs]; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 169 | for (uptr i = 0; i < kNumAllocs; i++) { |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 170 | void *x = cache.Allocate(a, 1 + i % 50); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 171 | allocated[i] = x; |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 172 | meta[i] = a->GetMetaData(x); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 173 | } |
| 174 | // Get Metadata kNumAllocs^2 times. |
| 175 | for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) { |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 176 | uptr idx = i % kNumAllocs; |
| 177 | void *m = a->GetMetaData(allocated[idx]); |
| 178 | EXPECT_EQ(m, meta[idx]); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 179 | } |
| 180 | for (uptr i = 0; i < kNumAllocs; i++) { |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 181 | cache.Deallocate(a, 1 + i % 50, allocated[i]); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 182 | } |
| 183 | |
Kostya Serebryany | 784935d | 2012-12-06 13:00:11 +0000 | [diff] [blame] | 184 | a->TestOnlyUnmap(); |
Kostya Serebryany | 784935d | 2012-12-06 13:00:11 +0000 | [diff] [blame] | 185 | delete a; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 186 | } |
| 187 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 188 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 189 | TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) { |
Kostya Serebryany | 784935d | 2012-12-06 13:00:11 +0000 | [diff] [blame] | 190 | SizeClassAllocatorMetadataStress<Allocator64>(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) { |
Kostya Serebryany | 784935d | 2012-12-06 13:00:11 +0000 | [diff] [blame] | 194 | SizeClassAllocatorMetadataStress<Allocator64Compact>(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 195 | } |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 196 | #endif // SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 784935d | 2012-12-06 13:00:11 +0000 | [diff] [blame] | 197 | TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) { |
| 198 | SizeClassAllocatorMetadataStress<Allocator32Compact>(); |
| 199 | } |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 200 | |
Kostya Serebryany | a1560bd | 2013-05-16 05:22:50 +0000 | [diff] [blame] | 201 | template <class Allocator> |
| 202 | void SizeClassAllocatorGetBlockBeginStress() { |
| 203 | Allocator *a = new Allocator; |
| 204 | a->Init(); |
| 205 | SizeClassAllocatorLocalCache<Allocator> cache; |
| 206 | memset(&cache, 0, sizeof(cache)); |
| 207 | cache.Init(0); |
| 208 | |
| 209 | uptr max_size_class = Allocator::kNumClasses - 1; |
| 210 | uptr size = Allocator::SizeClassMapT::Size(max_size_class); |
| 211 | u64 G8 = 1ULL << 33; |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 212 | // Make sure we correctly compute GetBlockBegin() w/o overflow. |
Kostya Serebryany | a1560bd | 2013-05-16 05:22:50 +0000 | [diff] [blame] | 213 | for (size_t i = 0; i <= G8 / size; i++) { |
| 214 | void *x = cache.Allocate(a, max_size_class); |
| 215 | void *beg = a->GetBlockBegin(x); |
Dmitry Vyukov | 374fd35 | 2013-05-17 11:54:37 +0000 | [diff] [blame] | 216 | // if ((i & (i - 1)) == 0) |
| 217 | // fprintf(stderr, "[%zd] %p %p\n", i, x, beg); |
Kostya Serebryany | a1560bd | 2013-05-16 05:22:50 +0000 | [diff] [blame] | 218 | EXPECT_EQ(x, beg); |
| 219 | } |
| 220 | |
| 221 | a->TestOnlyUnmap(); |
| 222 | delete a; |
| 223 | } |
| 224 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 225 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 226 | TEST(SanitizerCommon, SizeClassAllocator64GetBlockBegin) { |
Kostya Serebryany | a1560bd | 2013-05-16 05:22:50 +0000 | [diff] [blame] | 227 | SizeClassAllocatorGetBlockBeginStress<Allocator64>(); |
| 228 | } |
Kostya Serebryany | 871b7fd | 2013-05-16 07:11:16 +0000 | [diff] [blame] | 229 | TEST(SanitizerCommon, SizeClassAllocator64CompactGetBlockBegin) { |
| 230 | SizeClassAllocatorGetBlockBeginStress<Allocator64Compact>(); |
| 231 | } |
| 232 | TEST(SanitizerCommon, SizeClassAllocator32CompactGetBlockBegin) { |
| 233 | SizeClassAllocatorGetBlockBeginStress<Allocator32Compact>(); |
| 234 | } |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 235 | #endif // SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | a1560bd | 2013-05-16 05:22:50 +0000 | [diff] [blame] | 236 | |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 237 | struct TestMapUnmapCallback { |
| 238 | static int map_count, unmap_count; |
| 239 | void OnMap(uptr p, uptr size) const { map_count++; } |
| 240 | void OnUnmap(uptr p, uptr size) const { unmap_count++; } |
| 241 | }; |
| 242 | int TestMapUnmapCallback::map_count; |
| 243 | int TestMapUnmapCallback::unmap_count; |
| 244 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 245 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 246 | TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) { |
| 247 | TestMapUnmapCallback::map_count = 0; |
| 248 | TestMapUnmapCallback::unmap_count = 0; |
| 249 | typedef SizeClassAllocator64< |
| 250 | kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap, |
| 251 | TestMapUnmapCallback> Allocator64WithCallBack; |
| 252 | Allocator64WithCallBack *a = new Allocator64WithCallBack; |
| 253 | a->Init(); |
| 254 | EXPECT_EQ(TestMapUnmapCallback::map_count, 1); // Allocator state. |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 255 | SizeClassAllocatorLocalCache<Allocator64WithCallBack> cache; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 256 | memset(&cache, 0, sizeof(cache)); |
| 257 | cache.Init(0); |
| 258 | AllocatorStats stats; |
| 259 | stats.Init(); |
Kostya Serebryany | f2c417c | 2013-03-12 08:44:40 +0000 | [diff] [blame] | 260 | a->AllocateBatch(&stats, &cache, 32); |
Kostya Serebryany | 567ad07 | 2012-12-13 05:05:11 +0000 | [diff] [blame] | 261 | EXPECT_EQ(TestMapUnmapCallback::map_count, 3); // State + alloc + metadata. |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 262 | a->TestOnlyUnmap(); |
| 263 | EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); // The whole thing. |
| 264 | delete a; |
| 265 | } |
| 266 | #endif |
| 267 | |
| 268 | TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) { |
| 269 | TestMapUnmapCallback::map_count = 0; |
| 270 | TestMapUnmapCallback::unmap_count = 0; |
| 271 | typedef SizeClassAllocator32< |
Kostya Serebryany | 1b54cbf | 2013-05-20 07:29:21 +0000 | [diff] [blame] | 272 | 0, kAddressSpaceSize, |
| 273 | /*kMetadataSize*/16, |
| 274 | CompactSizeClassMap, |
| 275 | kRegionSizeLog, |
| 276 | FlatByteMap<kFlatByteMapSize>, |
| 277 | TestMapUnmapCallback> |
| 278 | Allocator32WithCallBack; |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 279 | Allocator32WithCallBack *a = new Allocator32WithCallBack; |
| 280 | a->Init(); |
Kostya Serebryany | 1b54cbf | 2013-05-20 07:29:21 +0000 | [diff] [blame] | 281 | EXPECT_EQ(TestMapUnmapCallback::map_count, 0); |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 282 | SizeClassAllocatorLocalCache<Allocator32WithCallBack> cache; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 283 | memset(&cache, 0, sizeof(cache)); |
| 284 | cache.Init(0); |
| 285 | AllocatorStats stats; |
| 286 | stats.Init(); |
Kostya Serebryany | f2c417c | 2013-03-12 08:44:40 +0000 | [diff] [blame] | 287 | a->AllocateBatch(&stats, &cache, 32); |
Kostya Serebryany | 1b54cbf | 2013-05-20 07:29:21 +0000 | [diff] [blame] | 288 | EXPECT_EQ(TestMapUnmapCallback::map_count, 1); |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 289 | a->TestOnlyUnmap(); |
Kostya Serebryany | 1b54cbf | 2013-05-20 07:29:21 +0000 | [diff] [blame] | 290 | EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 291 | delete a; |
Dmitry Vyukov | ca661f5 | 2012-12-14 10:12:14 +0000 | [diff] [blame] | 292 | // fprintf(stderr, "Map: %d Unmap: %d\n", |
| 293 | // TestMapUnmapCallback::map_count, |
| 294 | // TestMapUnmapCallback::unmap_count); |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 295 | } |
| 296 | |
| 297 | TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) { |
| 298 | TestMapUnmapCallback::map_count = 0; |
| 299 | TestMapUnmapCallback::unmap_count = 0; |
| 300 | LargeMmapAllocator<TestMapUnmapCallback> a; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 301 | a.Init(/* may_return_null */ false); |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 302 | AllocatorStats stats; |
| 303 | stats.Init(); |
| 304 | void *x = a.Allocate(&stats, 1 << 20, 1); |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 305 | EXPECT_EQ(TestMapUnmapCallback::map_count, 1); |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 306 | a.Deallocate(&stats, x); |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 307 | EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); |
| 308 | } |
| 309 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 310 | template<class Allocator> |
| 311 | void FailInAssertionOnOOM() { |
| 312 | Allocator a; |
| 313 | a.Init(); |
Dmitry Vyukov | a343ca0 | 2013-01-11 16:41:19 +0000 | [diff] [blame] | 314 | SizeClassAllocatorLocalCache<Allocator> cache; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 315 | memset(&cache, 0, sizeof(cache)); |
| 316 | cache.Init(0); |
| 317 | AllocatorStats stats; |
| 318 | stats.Init(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 319 | for (int i = 0; i < 1000000; i++) { |
Kostya Serebryany | f2c417c | 2013-03-12 08:44:40 +0000 | [diff] [blame] | 320 | a.AllocateBatch(&stats, &cache, 52); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 321 | } |
| 322 | |
| 323 | a.TestOnlyUnmap(); |
| 324 | } |
| 325 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 326 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 327 | TEST(SanitizerCommon, SizeClassAllocator64Overflow) { |
| 328 | EXPECT_DEATH(FailInAssertionOnOOM<Allocator64>(), "Out of memory"); |
| 329 | } |
| 330 | #endif |
| 331 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 332 | #if !defined(_WIN32) // FIXME: This currently fails on Windows. |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 333 | TEST(SanitizerCommon, LargeMmapAllocator) { |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 334 | LargeMmapAllocator<> a; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 335 | a.Init(/* may_return_null */ false); |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 336 | AllocatorStats stats; |
| 337 | stats.Init(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 338 | |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 339 | static const int kNumAllocs = 1000; |
Kostya Serebryany | da1f82b | 2012-12-18 14:56:38 +0000 | [diff] [blame] | 340 | char *allocated[kNumAllocs]; |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 341 | static const uptr size = 4000; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 342 | // Allocate some. |
| 343 | for (int i = 0; i < kNumAllocs; i++) { |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 344 | allocated[i] = (char *)a.Allocate(&stats, size, 1); |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 345 | CHECK(a.PointerIsMine(allocated[i])); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 346 | } |
| 347 | // Deallocate all. |
| 348 | CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs); |
| 349 | for (int i = 0; i < kNumAllocs; i++) { |
Kostya Serebryany | da1f82b | 2012-12-18 14:56:38 +0000 | [diff] [blame] | 350 | char *p = allocated[i]; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 351 | CHECK(a.PointerIsMine(p)); |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 352 | a.Deallocate(&stats, p); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 353 | } |
| 354 | // Check that non left. |
| 355 | CHECK_EQ(a.TotalMemoryUsed(), 0); |
| 356 | |
| 357 | // Allocate some more, also add metadata. |
| 358 | for (int i = 0; i < kNumAllocs; i++) { |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 359 | char *x = (char *)a.Allocate(&stats, size, 1); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 360 | CHECK_GE(a.GetActuallyAllocatedSize(x), size); |
| 361 | uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x)); |
| 362 | *meta = i; |
| 363 | allocated[i] = x; |
| 364 | } |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 365 | for (int i = 0; i < kNumAllocs * kNumAllocs; i++) { |
| 366 | char *p = allocated[i % kNumAllocs]; |
| 367 | CHECK(a.PointerIsMine(p)); |
| 368 | CHECK(a.PointerIsMine(p + 2000)); |
| 369 | } |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 370 | CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs); |
| 371 | // Deallocate all in reverse order. |
| 372 | for (int i = 0; i < kNumAllocs; i++) { |
| 373 | int idx = kNumAllocs - i - 1; |
Kostya Serebryany | da1f82b | 2012-12-18 14:56:38 +0000 | [diff] [blame] | 374 | char *p = allocated[idx]; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 375 | uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p)); |
| 376 | CHECK_EQ(*meta, idx); |
| 377 | CHECK(a.PointerIsMine(p)); |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 378 | a.Deallocate(&stats, p); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 379 | } |
| 380 | CHECK_EQ(a.TotalMemoryUsed(), 0); |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 381 | |
| 382 | // Test alignments. |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 383 | uptr max_alignment = SANITIZER_WORDSIZE == 64 ? (1 << 28) : (1 << 24); |
| 384 | for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) { |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 385 | const uptr kNumAlignedAllocs = 100; |
Kostya Serebryany | 68d3a1b | 2012-12-24 14:53:13 +0000 | [diff] [blame] | 386 | for (uptr i = 0; i < kNumAlignedAllocs; i++) { |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 387 | uptr size = ((i % 10) + 1) * 4096; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 388 | char *p = allocated[i] = (char *)a.Allocate(&stats, size, alignment); |
Kostya Serebryany | da1f82b | 2012-12-18 14:56:38 +0000 | [diff] [blame] | 389 | CHECK_EQ(p, a.GetBlockBegin(p)); |
| 390 | CHECK_EQ(p, a.GetBlockBegin(p + size - 1)); |
| 391 | CHECK_EQ(p, a.GetBlockBegin(p + size / 2)); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 392 | CHECK_EQ(0, (uptr)allocated[i] % alignment); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 393 | p[0] = p[size - 1] = 0; |
| 394 | } |
Kostya Serebryany | 68d3a1b | 2012-12-24 14:53:13 +0000 | [diff] [blame] | 395 | for (uptr i = 0; i < kNumAlignedAllocs; i++) { |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 396 | a.Deallocate(&stats, allocated[i]); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 397 | } |
| 398 | } |
Kostya Serebryany | a2c1d98 | 2013-04-08 08:43:22 +0000 | [diff] [blame] | 399 | |
| 400 | // Regression test for boundary condition in GetBlockBegin(). |
| 401 | uptr page_size = GetPageSizeCached(); |
| 402 | char *p = (char *)a.Allocate(&stats, page_size, 1); |
| 403 | CHECK_EQ(p, a.GetBlockBegin(p)); |
| 404 | CHECK_EQ(p, (char *)a.GetBlockBegin(p + page_size - 1)); |
| 405 | CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size)); |
| 406 | a.Deallocate(&stats, p); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 407 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 408 | #endif |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 409 | |
| 410 | template |
| 411 | <class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache> |
| 412 | void TestCombinedAllocator() { |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 413 | typedef |
| 414 | CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator> |
| 415 | Allocator; |
| 416 | Allocator *a = new Allocator; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 417 | a->Init(/* may_return_null */ true); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 418 | |
| 419 | AllocatorCache cache; |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 420 | memset(&cache, 0, sizeof(cache)); |
| 421 | a->InitCache(&cache); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 422 | |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 423 | EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0); |
| 424 | EXPECT_EQ(a->Allocate(&cache, -1, 1024), (void*)0); |
| 425 | EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0); |
| 426 | EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0); |
| 427 | EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 428 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 429 | // Set to false |
| 430 | a->SetMayReturnNull(false); |
Kostya Serebryany | 9150f39 | 2013-09-06 09:25:11 +0000 | [diff] [blame] | 431 | EXPECT_DEATH(a->Allocate(&cache, -1, 1), |
| 432 | "allocator is terminating the process"); |
Kostya Serebryany | 9150f39 | 2013-09-06 09:25:11 +0000 | [diff] [blame] | 433 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 434 | const uptr kNumAllocs = 100000; |
| 435 | const uptr kNumIter = 10; |
| 436 | for (uptr iter = 0; iter < kNumIter; iter++) { |
| 437 | std::vector<void*> allocated; |
| 438 | for (uptr i = 0; i < kNumAllocs; i++) { |
| 439 | uptr size = (i % (1 << 14)) + 1; |
| 440 | if ((i % 1024) == 0) |
| 441 | size = 1 << (10 + (i % 14)); |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 442 | void *x = a->Allocate(&cache, size, 1); |
| 443 | uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x)); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 444 | CHECK_EQ(*meta, 0); |
| 445 | *meta = size; |
| 446 | allocated.push_back(x); |
| 447 | } |
| 448 | |
| 449 | random_shuffle(allocated.begin(), allocated.end()); |
| 450 | |
| 451 | for (uptr i = 0; i < kNumAllocs; i++) { |
| 452 | void *x = allocated[i]; |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 453 | uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x)); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 454 | CHECK_NE(*meta, 0); |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 455 | CHECK(a->PointerIsMine(x)); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 456 | *meta = 0; |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 457 | a->Deallocate(&cache, x); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 458 | } |
| 459 | allocated.clear(); |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 460 | a->SwallowCache(&cache); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 461 | } |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 462 | a->DestroyCache(&cache); |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 463 | a->TestOnlyUnmap(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 464 | } |
| 465 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 466 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 467 | TEST(SanitizerCommon, CombinedAllocator64) { |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 468 | TestCombinedAllocator<Allocator64, |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 469 | LargeMmapAllocator<>, |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 470 | SizeClassAllocatorLocalCache<Allocator64> > (); |
| 471 | } |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 472 | |
| 473 | TEST(SanitizerCommon, CombinedAllocator64Compact) { |
| 474 | TestCombinedAllocator<Allocator64Compact, |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 475 | LargeMmapAllocator<>, |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 476 | SizeClassAllocatorLocalCache<Allocator64Compact> > (); |
| 477 | } |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 478 | #endif |
| 479 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 480 | #if !defined(_WIN32) // FIXME: This currently fails on Windows. |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 481 | TEST(SanitizerCommon, CombinedAllocator32Compact) { |
| 482 | TestCombinedAllocator<Allocator32Compact, |
Kostya Serebryany | 214621f | 2012-12-12 14:32:18 +0000 | [diff] [blame] | 483 | LargeMmapAllocator<>, |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 484 | SizeClassAllocatorLocalCache<Allocator32Compact> > (); |
| 485 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 486 | #endif |
Kostya Serebryany | 674d05c | 2012-12-06 14:27:32 +0000 | [diff] [blame] | 487 | |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 488 | template <class AllocatorCache> |
| 489 | void TestSizeClassAllocatorLocalCache() { |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 490 | AllocatorCache cache; |
Kostya Serebryany | e280ce5 | 2012-12-06 14:39:41 +0000 | [diff] [blame] | 491 | typedef typename AllocatorCache::Allocator Allocator; |
| 492 | Allocator *a = new Allocator(); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 493 | |
Kostya Serebryany | e280ce5 | 2012-12-06 14:39:41 +0000 | [diff] [blame] | 494 | a->Init(); |
Dmitry Vyukov | bdd844c | 2013-01-24 09:08:03 +0000 | [diff] [blame] | 495 | memset(&cache, 0, sizeof(cache)); |
| 496 | cache.Init(0); |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 497 | |
| 498 | const uptr kNumAllocs = 10000; |
| 499 | const int kNumIter = 100; |
| 500 | uptr saved_total = 0; |
Kostya Serebryany | 038820f | 2012-12-24 13:41:07 +0000 | [diff] [blame] | 501 | for (int class_id = 1; class_id <= 5; class_id++) { |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 502 | for (int it = 0; it < kNumIter; it++) { |
Kostya Serebryany | 038820f | 2012-12-24 13:41:07 +0000 | [diff] [blame] | 503 | void *allocated[kNumAllocs]; |
| 504 | for (uptr i = 0; i < kNumAllocs; i++) { |
| 505 | allocated[i] = cache.Allocate(a, class_id); |
| 506 | } |
| 507 | for (uptr i = 0; i < kNumAllocs; i++) { |
| 508 | cache.Deallocate(a, class_id, allocated[i]); |
| 509 | } |
| 510 | cache.Drain(a); |
| 511 | uptr total_allocated = a->TotalMemoryUsed(); |
Kostya Serebryany | b8c363d | 2012-12-24 14:35:14 +0000 | [diff] [blame] | 512 | if (it) |
Kostya Serebryany | 038820f | 2012-12-24 13:41:07 +0000 | [diff] [blame] | 513 | CHECK_EQ(saved_total, total_allocated); |
| 514 | saved_total = total_allocated; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 515 | } |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 516 | } |
| 517 | |
Kostya Serebryany | e280ce5 | 2012-12-06 14:39:41 +0000 | [diff] [blame] | 518 | a->TestOnlyUnmap(); |
| 519 | delete a; |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 520 | } |
| 521 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 522 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 523 | TEST(SanitizerCommon, SizeClassAllocator64LocalCache) { |
| 524 | TestSizeClassAllocatorLocalCache< |
| 525 | SizeClassAllocatorLocalCache<Allocator64> >(); |
| 526 | } |
Kostya Serebryany | e280ce5 | 2012-12-06 14:39:41 +0000 | [diff] [blame] | 527 | |
| 528 | TEST(SanitizerCommon, SizeClassAllocator64CompactLocalCache) { |
| 529 | TestSizeClassAllocatorLocalCache< |
| 530 | SizeClassAllocatorLocalCache<Allocator64Compact> >(); |
| 531 | } |
Kostya Serebryany | 72166ca | 2012-12-05 10:09:15 +0000 | [diff] [blame] | 532 | #endif |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 533 | |
Kostya Serebryany | e280ce5 | 2012-12-06 14:39:41 +0000 | [diff] [blame] | 534 | TEST(SanitizerCommon, SizeClassAllocator32CompactLocalCache) { |
| 535 | TestSizeClassAllocatorLocalCache< |
| 536 | SizeClassAllocatorLocalCache<Allocator32Compact> >(); |
| 537 | } |
| 538 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 539 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 9fc1f27 | 2012-12-14 14:20:29 +0000 | [diff] [blame] | 540 | typedef SizeClassAllocatorLocalCache<Allocator64> AllocatorCache; |
Evgeniy Stepanov | 0d02d75 | 2013-01-14 14:06:58 +0000 | [diff] [blame] | 541 | static AllocatorCache static_allocator_cache; |
Kostya Serebryany | 9fc1f27 | 2012-12-14 14:20:29 +0000 | [diff] [blame] | 542 | |
| 543 | void *AllocatorLeakTestWorker(void *arg) { |
| 544 | typedef AllocatorCache::Allocator Allocator; |
| 545 | Allocator *a = (Allocator*)(arg); |
| 546 | static_allocator_cache.Allocate(a, 10); |
| 547 | static_allocator_cache.Drain(a); |
| 548 | return 0; |
| 549 | } |
| 550 | |
| 551 | TEST(SanitizerCommon, AllocatorLeakTest) { |
Alexey Samsonov | 68acb90 | 2012-12-14 15:37:35 +0000 | [diff] [blame] | 552 | typedef AllocatorCache::Allocator Allocator; |
Kostya Serebryany | 9fc1f27 | 2012-12-14 14:20:29 +0000 | [diff] [blame] | 553 | Allocator a; |
| 554 | a.Init(); |
| 555 | uptr total_used_memory = 0; |
| 556 | for (int i = 0; i < 100; i++) { |
| 557 | pthread_t t; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 558 | PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a); |
| 559 | PTHREAD_JOIN(t, 0); |
Kostya Serebryany | 9fc1f27 | 2012-12-14 14:20:29 +0000 | [diff] [blame] | 560 | if (i == 0) |
| 561 | total_used_memory = a.TotalMemoryUsed(); |
| 562 | EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory); |
| 563 | } |
| 564 | |
| 565 | a.TestOnlyUnmap(); |
| 566 | } |
Reid Kleckner | 5d3dcb8 | 2013-03-06 14:54:08 +0000 | [diff] [blame] | 567 | |
| 568 | // Struct which is allocated to pass info to new threads. The new thread frees |
| 569 | // it. |
| 570 | struct NewThreadParams { |
| 571 | AllocatorCache *thread_cache; |
| 572 | AllocatorCache::Allocator *allocator; |
| 573 | uptr class_id; |
| 574 | }; |
| 575 | |
| 576 | // Called in a new thread. Just frees its argument. |
| 577 | static void *DeallocNewThreadWorker(void *arg) { |
| 578 | NewThreadParams *params = reinterpret_cast<NewThreadParams*>(arg); |
| 579 | params->thread_cache->Deallocate(params->allocator, params->class_id, params); |
| 580 | return NULL; |
| 581 | } |
| 582 | |
| 583 | // The allocator cache is supposed to be POD and zero initialized. We should be |
| 584 | // able to call Deallocate on a zeroed cache, and it will self-initialize. |
| 585 | TEST(Allocator, AllocatorCacheDeallocNewThread) { |
| 586 | AllocatorCache::Allocator allocator; |
| 587 | allocator.Init(); |
| 588 | AllocatorCache main_cache; |
| 589 | AllocatorCache child_cache; |
| 590 | memset(&main_cache, 0, sizeof(main_cache)); |
| 591 | memset(&child_cache, 0, sizeof(child_cache)); |
| 592 | |
| 593 | uptr class_id = DefaultSizeClassMap::ClassID(sizeof(NewThreadParams)); |
| 594 | NewThreadParams *params = reinterpret_cast<NewThreadParams*>( |
| 595 | main_cache.Allocate(&allocator, class_id)); |
| 596 | params->thread_cache = &child_cache; |
| 597 | params->allocator = &allocator; |
| 598 | params->class_id = class_id; |
| 599 | pthread_t t; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 600 | PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params); |
| 601 | PTHREAD_JOIN(t, 0); |
Reid Kleckner | 5d3dcb8 | 2013-03-06 14:54:08 +0000 | [diff] [blame] | 602 | } |
Kostya Serebryany | 9fc1f27 | 2012-12-14 14:20:29 +0000 | [diff] [blame] | 603 | #endif |
| 604 | |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 605 | TEST(Allocator, Basic) { |
| 606 | char *p = (char*)InternalAlloc(10); |
| 607 | EXPECT_NE(p, (char*)0); |
| 608 | char *p2 = (char*)InternalAlloc(20); |
| 609 | EXPECT_NE(p2, (char*)0); |
| 610 | EXPECT_NE(p2, p); |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 611 | InternalFree(p); |
| 612 | InternalFree(p2); |
| 613 | } |
| 614 | |
| 615 | TEST(Allocator, Stress) { |
| 616 | const int kCount = 1000; |
| 617 | char *ptrs[kCount]; |
| 618 | unsigned rnd = 42; |
| 619 | for (int i = 0; i < kCount; i++) { |
Evgeniy Stepanov | 48ddbef | 2013-01-14 15:12:26 +0000 | [diff] [blame] | 620 | uptr sz = my_rand_r(&rnd) % 1000; |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 621 | char *p = (char*)InternalAlloc(sz); |
| 622 | EXPECT_NE(p, (char*)0); |
Dmitry Vyukov | 225f531 | 2012-06-25 15:09:24 +0000 | [diff] [blame] | 623 | ptrs[i] = p; |
| 624 | } |
| 625 | for (int i = 0; i < kCount; i++) { |
| 626 | InternalFree(ptrs[i]); |
| 627 | } |
| 628 | } |
| 629 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 630 | TEST(Allocator, LargeAlloc) { |
| 631 | void *p = InternalAlloc(10 << 20); |
| 632 | InternalFree(p); |
Alexey Samsonov | 1f3c2fe | 2013-05-29 09:15:39 +0000 | [diff] [blame] | 633 | } |
| 634 | |
Alexey Samsonov | 6611abe | 2012-08-21 08:13:37 +0000 | [diff] [blame] | 635 | TEST(Allocator, ScopedBuffer) { |
| 636 | const int kSize = 512; |
| 637 | { |
| 638 | InternalScopedBuffer<int> int_buf(kSize); |
| 639 | EXPECT_EQ(sizeof(int) * kSize, int_buf.size()); // NOLINT |
| 640 | } |
| 641 | InternalScopedBuffer<char> char_buf(kSize); |
| 642 | EXPECT_EQ(sizeof(char) * kSize, char_buf.size()); // NOLINT |
Kostya Serebryany | 0bb6e5d | 2012-12-07 10:13:10 +0000 | [diff] [blame] | 643 | internal_memset(char_buf.data(), 'c', kSize); |
Alexey Samsonov | 6611abe | 2012-08-21 08:13:37 +0000 | [diff] [blame] | 644 | for (int i = 0; i < kSize; i++) { |
| 645 | EXPECT_EQ('c', char_buf[i]); |
| 646 | } |
| 647 | } |
Dmitry Vyukov | 68902f4 | 2012-12-14 10:17:22 +0000 | [diff] [blame] | 648 | |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 649 | void IterationTestCallback(uptr chunk, void *arg) { |
| 650 | reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk); |
Sergey Matveev | c87f737 | 2013-06-24 09:12:11 +0000 | [diff] [blame] | 651 | } |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 652 | |
| 653 | template <class Allocator> |
| 654 | void TestSizeClassAllocatorIteration() { |
| 655 | Allocator *a = new Allocator; |
| 656 | a->Init(); |
| 657 | SizeClassAllocatorLocalCache<Allocator> cache; |
| 658 | memset(&cache, 0, sizeof(cache)); |
| 659 | cache.Init(0); |
| 660 | |
| 661 | static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000, |
| 662 | 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000}; |
| 663 | |
| 664 | std::vector<void *> allocated; |
| 665 | |
| 666 | // Allocate a bunch of chunks. |
| 667 | for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) { |
| 668 | uptr size = sizes[s]; |
| 669 | if (!a->CanAllocate(size, 1)) continue; |
| 670 | // printf("s = %ld\n", size); |
| 671 | uptr n_iter = std::max((uptr)6, 80000 / size); |
| 672 | // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter); |
| 673 | for (uptr j = 0; j < n_iter; j++) { |
| 674 | uptr class_id0 = Allocator::SizeClassMapT::ClassID(size); |
| 675 | void *x = cache.Allocate(a, class_id0); |
| 676 | allocated.push_back(x); |
| 677 | } |
| 678 | } |
| 679 | |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 680 | std::set<uptr> reported_chunks; |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 681 | a->ForceLock(); |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 682 | a->ForEachChunk(IterationTestCallback, &reported_chunks); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 683 | a->ForceUnlock(); |
| 684 | |
| 685 | for (uptr i = 0; i < allocated.size(); i++) { |
| 686 | // Don't use EXPECT_NE. Reporting the first mismatch is enough. |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 687 | ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])), |
| 688 | reported_chunks.end()); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 689 | } |
| 690 | |
| 691 | a->TestOnlyUnmap(); |
| 692 | delete a; |
| 693 | } |
| 694 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 695 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 696 | TEST(SanitizerCommon, SizeClassAllocator64Iteration) { |
| 697 | TestSizeClassAllocatorIteration<Allocator64>(); |
| 698 | } |
| 699 | #endif |
| 700 | |
| 701 | TEST(SanitizerCommon, SizeClassAllocator32Iteration) { |
| 702 | TestSizeClassAllocatorIteration<Allocator32Compact>(); |
| 703 | } |
| 704 | |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 705 | TEST(SanitizerCommon, LargeMmapAllocatorIteration) { |
| 706 | LargeMmapAllocator<> a; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 707 | a.Init(/* may_return_null */ false); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 708 | AllocatorStats stats; |
| 709 | stats.Init(); |
| 710 | |
Kostya Serebryany | 6c876e4 | 2013-03-15 12:27:52 +0000 | [diff] [blame] | 711 | static const uptr kNumAllocs = 1000; |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 712 | char *allocated[kNumAllocs]; |
| 713 | static const uptr size = 40; |
| 714 | // Allocate some. |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 715 | for (uptr i = 0; i < kNumAllocs; i++) |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 716 | allocated[i] = (char *)a.Allocate(&stats, size, 1); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 717 | |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 718 | std::set<uptr> reported_chunks; |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 719 | a.ForceLock(); |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 720 | a.ForEachChunk(IterationTestCallback, &reported_chunks); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 721 | a.ForceUnlock(); |
| 722 | |
| 723 | for (uptr i = 0; i < kNumAllocs; i++) { |
| 724 | // Don't use EXPECT_NE. Reporting the first mismatch is enough. |
Sergey Matveev | ac78d00 | 2013-06-24 08:34:50 +0000 | [diff] [blame] | 725 | ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])), |
| 726 | reported_chunks.end()); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 727 | } |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 728 | for (uptr i = 0; i < kNumAllocs; i++) |
| 729 | a.Deallocate(&stats, allocated[i]); |
Kostya Serebryany | 300f953 | 2013-03-15 11:39:41 +0000 | [diff] [blame] | 730 | } |
| 731 | |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 732 | TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) { |
| 733 | LargeMmapAllocator<> a; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 734 | a.Init(/* may_return_null */ false); |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 735 | AllocatorStats stats; |
| 736 | stats.Init(); |
| 737 | |
| 738 | static const uptr kNumAllocs = 1024; |
| 739 | static const uptr kNumExpectedFalseLookups = 10000000; |
| 740 | char *allocated[kNumAllocs]; |
| 741 | static const uptr size = 4096; |
| 742 | // Allocate some. |
| 743 | for (uptr i = 0; i < kNumAllocs; i++) { |
| 744 | allocated[i] = (char *)a.Allocate(&stats, size, 1); |
| 745 | } |
| 746 | |
Kostya Serebryany | 8fa4edc | 2013-10-17 11:18:11 +0000 | [diff] [blame] | 747 | a.ForceLock(); |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 748 | for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) { |
| 749 | // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i); |
| 750 | char *p1 = allocated[i % kNumAllocs]; |
Sergey Matveev | 4fcc565 | 2013-05-31 11:33:21 +0000 | [diff] [blame] | 751 | EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1)); |
| 752 | EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2)); |
| 753 | EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1)); |
| 754 | EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100)); |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 755 | } |
| 756 | |
| 757 | for (uptr i = 0; i < kNumExpectedFalseLookups; i++) { |
| 758 | void *p = reinterpret_cast<void *>(i % 1024); |
Sergey Matveev | 4fcc565 | 2013-05-31 11:33:21 +0000 | [diff] [blame] | 759 | EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p)); |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 760 | p = reinterpret_cast<void *>(~0L - (i % 1024)); |
Sergey Matveev | 4fcc565 | 2013-05-31 11:33:21 +0000 | [diff] [blame] | 761 | EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p)); |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 762 | } |
Kostya Serebryany | 8fa4edc | 2013-10-17 11:18:11 +0000 | [diff] [blame] | 763 | a.ForceUnlock(); |
Kostya Serebryany | f8c3f3d | 2013-05-30 08:43:30 +0000 | [diff] [blame] | 764 | |
| 765 | for (uptr i = 0; i < kNumAllocs; i++) |
| 766 | a.Deallocate(&stats, allocated[i]); |
| 767 | } |
| 768 | |
| 769 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 770 | #if SANITIZER_CAN_USE_ALLOCATOR64 |
Sergey Matveev | f14ef72 | 2013-05-16 12:58:34 +0000 | [diff] [blame] | 771 | // Regression test for out-of-memory condition in PopulateFreeList(). |
| 772 | TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) { |
| 773 | // In a world where regions are small and chunks are huge... |
| 774 | typedef SizeClassMap<63, 128, 16> SpecialSizeClassMap; |
| 775 | typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0, |
| 776 | SpecialSizeClassMap> SpecialAllocator64; |
| 777 | const uptr kRegionSize = |
| 778 | kAllocatorSize / SpecialSizeClassMap::kNumClassesRounded; |
| 779 | SpecialAllocator64 *a = new SpecialAllocator64; |
| 780 | a->Init(); |
| 781 | SizeClassAllocatorLocalCache<SpecialAllocator64> cache; |
| 782 | memset(&cache, 0, sizeof(cache)); |
| 783 | cache.Init(0); |
| 784 | |
| 785 | // ...one man is on a mission to overflow a region with a series of |
| 786 | // successive allocations. |
| 787 | const uptr kClassID = 107; |
| 788 | const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID); |
| 789 | ASSERT_LT(2 * kAllocationSize, kRegionSize); |
| 790 | ASSERT_GT(3 * kAllocationSize, kRegionSize); |
| 791 | cache.Allocate(a, kClassID); |
| 792 | EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID), |
| 793 | "The process has exhausted"); |
| 794 | a->TestOnlyUnmap(); |
| 795 | delete a; |
| 796 | } |
| 797 | #endif |
| 798 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 799 | TEST(SanitizerCommon, TwoLevelByteMap) { |
| 800 | const u64 kSize1 = 1 << 6, kSize2 = 1 << 12; |
| 801 | const u64 n = kSize1 * kSize2; |
| 802 | TwoLevelByteMap<kSize1, kSize2> m; |
| 803 | m.TestOnlyInit(); |
| 804 | for (u64 i = 0; i < n; i += 7) { |
| 805 | m.set(i, (i % 100) + 1); |
| 806 | } |
| 807 | for (u64 j = 0; j < n; j++) { |
| 808 | if (j % 7) |
| 809 | EXPECT_EQ(m[j], 0); |
| 810 | else |
| 811 | EXPECT_EQ(m[j], (j % 100) + 1); |
| 812 | } |
| 813 | |
| 814 | m.TestOnlyUnmap(); |
| 815 | } |
| 816 | |
| 817 | |
| 818 | typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap; |
| 819 | |
| 820 | struct TestByteMapParam { |
| 821 | TestByteMap *m; |
| 822 | size_t shard; |
| 823 | size_t num_shards; |
| 824 | }; |
| 825 | |
| 826 | void *TwoLevelByteMapUserThread(void *param) { |
| 827 | TestByteMapParam *p = (TestByteMapParam*)param; |
| 828 | for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) { |
| 829 | size_t val = (i % 100) + 1; |
| 830 | p->m->set(i, val); |
| 831 | EXPECT_EQ((*p->m)[i], val); |
| 832 | } |
| 833 | return 0; |
| 834 | } |
| 835 | |
| 836 | TEST(SanitizerCommon, ThreadedTwoLevelByteMap) { |
| 837 | TestByteMap m; |
| 838 | m.TestOnlyInit(); |
| 839 | TestMapUnmapCallback::map_count = 0; |
| 840 | TestMapUnmapCallback::unmap_count = 0; |
| 841 | static const int kNumThreads = 4; |
| 842 | pthread_t t[kNumThreads]; |
| 843 | TestByteMapParam p[kNumThreads]; |
| 844 | for (int i = 0; i < kNumThreads; i++) { |
| 845 | p[i].m = &m; |
| 846 | p[i].shard = i; |
| 847 | p[i].num_shards = kNumThreads; |
| 848 | PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]); |
| 849 | } |
| 850 | for (int i = 0; i < kNumThreads; i++) { |
| 851 | PTHREAD_JOIN(t[i], 0); |
| 852 | } |
| 853 | EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1()); |
| 854 | EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL); |
| 855 | m.TestOnlyUnmap(); |
| 856 | EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1()); |
| 857 | EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1()); |
| 858 | } |
| 859 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 860 | #endif // #if !SANITIZER_DEBUG |