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