xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp (revision dcef530878e870cd72479e7ecda6b059ebe00175)
1 //===-- sanitizer_allocator_test.cpp --------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10 // Tests for sanitizer_allocator.h.
11 //
12 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_allocator.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 #include <algorithm>
19 #include <random>
20 #include <set>
21 #include <vector>
22 
23 #include "gtest/gtest.h"
24 #include "sanitizer_common/sanitizer_allocator_internal.h"
25 #include "sanitizer_common/sanitizer_common.h"
26 #include "sanitizer_pthread_wrappers.h"
27 #include "sanitizer_test_utils.h"
28 
29 using namespace __sanitizer;
30 
31 #if SANITIZER_SOLARIS && defined(__sparcv9)
32 // FIXME: These tests probably fail because Solaris/sparcv9 uses the full
33 // 64-bit address space.  Needs more investigation
34 #define SKIP_ON_SOLARIS_SPARCV9(x) DISABLED_##x
35 #else
36 #define SKIP_ON_SOLARIS_SPARCV9(x) x
37 #endif
38 
39 // On 64-bit systems with small virtual address spaces (e.g. 39-bit) we can't
40 // use size class maps with a large number of classes, as that will make the
41 // SizeClassAllocator64 region size too small (< 2^32).
42 #if SANITIZER_ANDROID && defined(__aarch64__)
43 #define ALLOCATOR64_SMALL_SIZE 1
44 #elif SANITIZER_RISCV64
45 #define ALLOCATOR64_SMALL_SIZE 1
46 #else
47 #define ALLOCATOR64_SMALL_SIZE 0
48 #endif
49 
50 // Too slow for debug build
51 #if !SANITIZER_DEBUG
52 
53 #if SANITIZER_CAN_USE_ALLOCATOR64
54 #if SANITIZER_WINDOWS
55 // On Windows 64-bit there is no easy way to find a large enough fixed address
56 // space that is always available. Thus, a dynamically allocated address space
57 // is used instead (i.e. ~(uptr)0).
58 static const uptr kAllocatorSpace = ~(uptr)0;
59 static const uptr kAllocatorSize  =  0x8000000000ULL;  // 500G
60 static const u64 kAddressSpaceSize = 1ULL << 47;
61 typedef DefaultSizeClassMap SizeClassMap;
62 #elif SANITIZER_ANDROID && defined(__aarch64__)
63 static const uptr kAllocatorSpace = 0x3000000000ULL;
64 static const uptr kAllocatorSize  = 0x2000000000ULL;
65 static const u64 kAddressSpaceSize = 1ULL << 39;
66 typedef VeryCompactSizeClassMap SizeClassMap;
67 #elif SANITIZER_RISCV64
68 const uptr kAllocatorSpace = ~(uptr)0;
69 const uptr kAllocatorSize = 0x2000000000ULL;  // 128G.
70 static const u64 kAddressSpaceSize = 1ULL << 38;
71 typedef VeryDenseSizeClassMap SizeClassMap;
72 #else
73 static const uptr kAllocatorSpace = 0x700000000000ULL;
74 static const uptr kAllocatorSize  = 0x010000000000ULL;  // 1T.
75 static const u64 kAddressSpaceSize = 1ULL << 47;
76 typedef DefaultSizeClassMap SizeClassMap;
77 #endif
78 
79 template <typename AddressSpaceViewTy>
80 struct AP64 {  // Allocator Params. Short name for shorter demangled names..
81   static const uptr kSpaceBeg = kAllocatorSpace;
82   static const uptr kSpaceSize = kAllocatorSize;
83   static const uptr kMetadataSize = 16;
84   typedef ::SizeClassMap SizeClassMap;
85   typedef NoOpMapUnmapCallback MapUnmapCallback;
86   static const uptr kFlags = 0;
87   using AddressSpaceView = AddressSpaceViewTy;
88 };
89 
90 template <typename AddressSpaceViewTy>
91 struct AP64Dyn {
92   static const uptr kSpaceBeg = ~(uptr)0;
93   static const uptr kSpaceSize = kAllocatorSize;
94   static const uptr kMetadataSize = 16;
95   typedef ::SizeClassMap SizeClassMap;
96   typedef NoOpMapUnmapCallback MapUnmapCallback;
97   static const uptr kFlags = 0;
98   using AddressSpaceView = AddressSpaceViewTy;
99 };
100 
101 template <typename AddressSpaceViewTy>
102 struct AP64Compact {
103   static const uptr kSpaceBeg = ~(uptr)0;
104   static const uptr kSpaceSize = kAllocatorSize;
105   static const uptr kMetadataSize = 16;
106   typedef CompactSizeClassMap SizeClassMap;
107   typedef NoOpMapUnmapCallback MapUnmapCallback;
108   static const uptr kFlags = 0;
109   using AddressSpaceView = AddressSpaceViewTy;
110 };
111 
112 template <typename AddressSpaceViewTy>
113 struct AP64VeryCompact {
114   static const uptr kSpaceBeg = ~(uptr)0;
115   static const uptr kSpaceSize = 1ULL << 37;
116   static const uptr kMetadataSize = 16;
117   typedef VeryCompactSizeClassMap SizeClassMap;
118   typedef NoOpMapUnmapCallback MapUnmapCallback;
119   static const uptr kFlags = 0;
120   using AddressSpaceView = AddressSpaceViewTy;
121 };
122 
123 template <typename AddressSpaceViewTy>
124 struct AP64Dense {
125   static const uptr kSpaceBeg = kAllocatorSpace;
126   static const uptr kSpaceSize = kAllocatorSize;
127   static const uptr kMetadataSize = 16;
128   typedef DenseSizeClassMap SizeClassMap;
129   typedef NoOpMapUnmapCallback MapUnmapCallback;
130   static const uptr kFlags = 0;
131   using AddressSpaceView = AddressSpaceViewTy;
132 };
133 
134 template <typename AddressSpaceView>
135 using Allocator64ASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
136 using Allocator64 = Allocator64ASVT<LocalAddressSpaceView>;
137 
138 template <typename AddressSpaceView>
139 using Allocator64DynamicASVT = SizeClassAllocator64<AP64Dyn<AddressSpaceView>>;
140 using Allocator64Dynamic = Allocator64DynamicASVT<LocalAddressSpaceView>;
141 
142 template <typename AddressSpaceView>
143 using Allocator64CompactASVT =
144     SizeClassAllocator64<AP64Compact<AddressSpaceView>>;
145 using Allocator64Compact = Allocator64CompactASVT<LocalAddressSpaceView>;
146 
147 template <typename AddressSpaceView>
148 using Allocator64VeryCompactASVT =
149     SizeClassAllocator64<AP64VeryCompact<AddressSpaceView>>;
150 using Allocator64VeryCompact =
151     Allocator64VeryCompactASVT<LocalAddressSpaceView>;
152 
153 template <typename AddressSpaceView>
154 using Allocator64DenseASVT = SizeClassAllocator64<AP64Dense<AddressSpaceView>>;
155 using Allocator64Dense = Allocator64DenseASVT<LocalAddressSpaceView>;
156 
157 #elif defined(__mips64)
158 static const u64 kAddressSpaceSize = 1ULL << 40;
159 #elif defined(__aarch64__)
160 static const u64 kAddressSpaceSize = 1ULL << 39;
161 #elif defined(__s390x__)
162 static const u64 kAddressSpaceSize = 1ULL << 53;
163 #elif defined(__s390__)
164 static const u64 kAddressSpaceSize = 1ULL << 31;
165 #else
166 static const u64 kAddressSpaceSize = 1ULL << 32;
167 #endif
168 
169 static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24);
170 
171 template <typename AddressSpaceViewTy>
172 struct AP32Compact {
173   static const uptr kSpaceBeg = 0;
174   static const u64 kSpaceSize = kAddressSpaceSize;
175   static const uptr kMetadataSize = 16;
176   typedef CompactSizeClassMap SizeClassMap;
177   static const uptr kRegionSizeLog = ::kRegionSizeLog;
178   using AddressSpaceView = AddressSpaceViewTy;
179   typedef NoOpMapUnmapCallback MapUnmapCallback;
180   static const uptr kFlags = 0;
181 };
182 template <typename AddressSpaceView>
183 using Allocator32CompactASVT =
184     SizeClassAllocator32<AP32Compact<AddressSpaceView>>;
185 using Allocator32Compact = Allocator32CompactASVT<LocalAddressSpaceView>;
186 
187 template <class SizeClassMap>
188 void TestSizeClassMap() {
189   typedef SizeClassMap SCMap;
190   SCMap::Print();
191   SCMap::Validate();
192 }
193 
194 TEST(SanitizerCommon, DefaultSizeClassMap) {
195   TestSizeClassMap<DefaultSizeClassMap>();
196 }
197 
198 TEST(SanitizerCommon, CompactSizeClassMap) {
199   TestSizeClassMap<CompactSizeClassMap>();
200 }
201 
202 TEST(SanitizerCommon, VeryCompactSizeClassMap) {
203   TestSizeClassMap<VeryCompactSizeClassMap>();
204 }
205 
206 TEST(SanitizerCommon, InternalSizeClassMap) {
207   TestSizeClassMap<InternalSizeClassMap>();
208 }
209 
210 TEST(SanitizerCommon, DenseSizeClassMap) {
211   TestSizeClassMap<VeryCompactSizeClassMap>();
212 }
213 
214 template <class Allocator>
215 void TestSizeClassAllocator(uptr premapped_heap = 0) {
216   Allocator *a = new Allocator;
217   a->Init(kReleaseToOSIntervalNever, premapped_heap);
218   typename Allocator::AllocatorCache cache;
219   memset(&cache, 0, sizeof(cache));
220   cache.Init(0);
221 
222   static const uptr sizes[] = {
223     1, 16,  30, 40, 100, 1000, 10000,
224     50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000
225   };
226 
227   std::vector<void *> allocated;
228 
229   uptr last_total_allocated = 0;
230   for (int i = 0; i < 3; i++) {
231     // Allocate a bunch of chunks.
232     for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
233       uptr size = sizes[s];
234       if (!a->CanAllocate(size, 1)) continue;
235       // printf("s = %ld\n", size);
236       uptr n_iter = std::max((uptr)6, 4000000 / size);
237       // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter);
238       for (uptr i = 0; i < n_iter; i++) {
239         uptr class_id0 = Allocator::SizeClassMapT::ClassID(size);
240         char *x = (char*)cache.Allocate(a, class_id0);
241         x[0] = 0;
242         x[size - 1] = 0;
243         x[size / 2] = 0;
244         allocated.push_back(x);
245         CHECK_EQ(x, a->GetBlockBegin(x));
246         CHECK_EQ(x, a->GetBlockBegin(x + size - 1));
247         CHECK(a->PointerIsMine(x));
248         CHECK(a->PointerIsMine(x + size - 1));
249         CHECK(a->PointerIsMine(x + size / 2));
250         CHECK_GE(a->GetActuallyAllocatedSize(x), size);
251         uptr class_id = a->GetSizeClass(x);
252         CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size));
253         uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
254         metadata[0] = reinterpret_cast<uptr>(x) + 1;
255         metadata[1] = 0xABCD;
256       }
257     }
258     // Deallocate all.
259     for (uptr i = 0; i < allocated.size(); i++) {
260       void *x = allocated[i];
261       uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
262       CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
263       CHECK_EQ(metadata[1], 0xABCD);
264       cache.Deallocate(a, a->GetSizeClass(x), x);
265     }
266     allocated.clear();
267     uptr total_allocated = a->TotalMemoryUsed();
268     if (last_total_allocated == 0)
269       last_total_allocated = total_allocated;
270     CHECK_EQ(last_total_allocated, total_allocated);
271   }
272 
273   // Check that GetBlockBegin never crashes.
274   for (uptr x = 0, step = kAddressSpaceSize / 100000;
275        x < kAddressSpaceSize - step; x += step)
276     if (a->PointerIsMine(reinterpret_cast<void *>(x)))
277       Ident(a->GetBlockBegin(reinterpret_cast<void *>(x)));
278 
279   a->TestOnlyUnmap();
280   delete a;
281 }
282 
283 #if SANITIZER_CAN_USE_ALLOCATOR64
284 
285 // Allocates kAllocatorSize aligned bytes on construction and frees it on
286 // destruction.
287 class ScopedPremappedHeap {
288  public:
289   ScopedPremappedHeap() {
290     BasePtr = MmapNoReserveOrDie(2 * kAllocatorSize, "preallocated heap");
291     AlignedAddr = RoundUpTo(reinterpret_cast<uptr>(BasePtr), kAllocatorSize);
292   }
293 
294   ~ScopedPremappedHeap() { UnmapOrDie(BasePtr, kAllocatorSize); }
295 
296   uptr Addr() { return AlignedAddr; }
297 
298  private:
299   void *BasePtr;
300   uptr AlignedAddr;
301 };
302 
303 // These tests can fail on Windows if memory is somewhat full and lit happens
304 // to run them all at the same time. FIXME: Make them not flaky and reenable.
305 #if !SANITIZER_WINDOWS
306 TEST(SanitizerCommon, SizeClassAllocator64) {
307   TestSizeClassAllocator<Allocator64>();
308 }
309 
310 TEST(SanitizerCommon, SizeClassAllocator64Dynamic) {
311   TestSizeClassAllocator<Allocator64Dynamic>();
312 }
313 
314 #if !ALLOCATOR64_SMALL_SIZE
315 // Android only has 39-bit address space, so mapping 2 * kAllocatorSize
316 // sometimes fails.
317 TEST(SanitizerCommon, SizeClassAllocator64DynamicPremapped) {
318   ScopedPremappedHeap h;
319   TestSizeClassAllocator<Allocator64Dynamic>(h.Addr());
320 }
321 
322 TEST(SanitizerCommon, SizeClassAllocator64Compact) {
323   TestSizeClassAllocator<Allocator64Compact>();
324 }
325 
326 TEST(SanitizerCommon, SizeClassAllocator64Dense) {
327   TestSizeClassAllocator<Allocator64Dense>();
328 }
329 #endif
330 
331 TEST(SanitizerCommon, SizeClassAllocator64VeryCompact) {
332   TestSizeClassAllocator<Allocator64VeryCompact>();
333 }
334 #endif
335 #endif
336 
337 TEST(SanitizerCommon, SizeClassAllocator32Compact) {
338   TestSizeClassAllocator<Allocator32Compact>();
339 }
340 
341 template <typename AddressSpaceViewTy>
342 struct AP32SeparateBatches {
343   static const uptr kSpaceBeg = 0;
344   static const u64 kSpaceSize = kAddressSpaceSize;
345   static const uptr kMetadataSize = 16;
346   typedef DefaultSizeClassMap SizeClassMap;
347   static const uptr kRegionSizeLog = ::kRegionSizeLog;
348   using AddressSpaceView = AddressSpaceViewTy;
349   typedef NoOpMapUnmapCallback MapUnmapCallback;
350   static const uptr kFlags =
351       SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch;
352 };
353 template <typename AddressSpaceView>
354 using Allocator32SeparateBatchesASVT =
355     SizeClassAllocator32<AP32SeparateBatches<AddressSpaceView>>;
356 using Allocator32SeparateBatches =
357     Allocator32SeparateBatchesASVT<LocalAddressSpaceView>;
358 
359 TEST(SanitizerCommon, SizeClassAllocator32SeparateBatches) {
360   TestSizeClassAllocator<Allocator32SeparateBatches>();
361 }
362 
363 template <class Allocator>
364 void SizeClassAllocatorMetadataStress(uptr premapped_heap = 0) {
365   Allocator *a = new Allocator;
366   a->Init(kReleaseToOSIntervalNever, premapped_heap);
367   typename Allocator::AllocatorCache cache;
368   memset(&cache, 0, sizeof(cache));
369   cache.Init(0);
370 
371   const uptr kNumAllocs = 1 << 13;
372   void *allocated[kNumAllocs];
373   void *meta[kNumAllocs];
374   for (uptr i = 0; i < kNumAllocs; i++) {
375     void *x = cache.Allocate(a, 1 + i % (Allocator::kNumClasses - 1));
376     allocated[i] = x;
377     meta[i] = a->GetMetaData(x);
378   }
379   // Get Metadata kNumAllocs^2 times.
380   for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
381     uptr idx = i % kNumAllocs;
382     void *m = a->GetMetaData(allocated[idx]);
383     EXPECT_EQ(m, meta[idx]);
384   }
385   for (uptr i = 0; i < kNumAllocs; i++) {
386     cache.Deallocate(a, 1 + i % (Allocator::kNumClasses - 1), allocated[i]);
387   }
388 
389   a->TestOnlyUnmap();
390   delete a;
391 }
392 
393 #if SANITIZER_CAN_USE_ALLOCATOR64
394 // These tests can fail on Windows if memory is somewhat full and lit happens
395 // to run them all at the same time. FIXME: Make them not flaky and reenable.
396 #if !SANITIZER_WINDOWS
397 TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
398   SizeClassAllocatorMetadataStress<Allocator64>();
399 }
400 
401 TEST(SanitizerCommon, SizeClassAllocator64DynamicMetadataStress) {
402   SizeClassAllocatorMetadataStress<Allocator64Dynamic>();
403 }
404 
405 #if !ALLOCATOR64_SMALL_SIZE
406 TEST(SanitizerCommon, SizeClassAllocator64DynamicPremappedMetadataStress) {
407   ScopedPremappedHeap h;
408   SizeClassAllocatorMetadataStress<Allocator64Dynamic>(h.Addr());
409 }
410 
411 TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) {
412   SizeClassAllocatorMetadataStress<Allocator64Compact>();
413 }
414 #endif
415 
416 #endif
417 #endif  // SANITIZER_CAN_USE_ALLOCATOR64
418 TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) {
419   SizeClassAllocatorMetadataStress<Allocator32Compact>();
420 }
421 
422 template <class Allocator>
423 void SizeClassAllocatorGetBlockBeginStress(u64 TotalSize,
424                                            uptr premapped_heap = 0) {
425   Allocator *a = new Allocator;
426   a->Init(kReleaseToOSIntervalNever, premapped_heap);
427   typename Allocator::AllocatorCache cache;
428   memset(&cache, 0, sizeof(cache));
429   cache.Init(0);
430 
431   uptr max_size_class = Allocator::SizeClassMapT::kLargestClassID;
432   uptr size = Allocator::SizeClassMapT::Size(max_size_class);
433   // Make sure we correctly compute GetBlockBegin() w/o overflow.
434   for (size_t i = 0; i <= TotalSize / size; i++) {
435     void *x = cache.Allocate(a, max_size_class);
436     void *beg = a->GetBlockBegin(x);
437     // if ((i & (i - 1)) == 0)
438     //   fprintf(stderr, "[%zd] %p %p\n", i, x, beg);
439     EXPECT_EQ(x, beg);
440   }
441 
442   a->TestOnlyUnmap();
443   delete a;
444 }
445 
446 #if SANITIZER_CAN_USE_ALLOCATOR64
447 // These tests can fail on Windows if memory is somewhat full and lit happens
448 // to run them all at the same time. FIXME: Make them not flaky and reenable.
449 #if !SANITIZER_WINDOWS
450 TEST(SanitizerCommon, SizeClassAllocator64GetBlockBegin) {
451   SizeClassAllocatorGetBlockBeginStress<Allocator64>(
452       1ULL << (SANITIZER_ANDROID ? 31 : 33));
453 }
454 TEST(SanitizerCommon, SizeClassAllocator64DynamicGetBlockBegin) {
455   SizeClassAllocatorGetBlockBeginStress<Allocator64Dynamic>(
456       1ULL << (SANITIZER_ANDROID ? 31 : 33));
457 }
458 #if !ALLOCATOR64_SMALL_SIZE
459 TEST(SanitizerCommon, SizeClassAllocator64DynamicPremappedGetBlockBegin) {
460   ScopedPremappedHeap h;
461   SizeClassAllocatorGetBlockBeginStress<Allocator64Dynamic>(
462       1ULL << (SANITIZER_ANDROID ? 31 : 33), h.Addr());
463 }
464 TEST(SanitizerCommon, SizeClassAllocator64CompactGetBlockBegin) {
465   SizeClassAllocatorGetBlockBeginStress<Allocator64Compact>(1ULL << 33);
466 }
467 #endif
468 TEST(SanitizerCommon, SizeClassAllocator64VeryCompactGetBlockBegin) {
469   // Does not have > 4Gb for each class.
470   SizeClassAllocatorGetBlockBeginStress<Allocator64VeryCompact>(1ULL << 31);
471 }
472 TEST(SanitizerCommon, SizeClassAllocator32CompactGetBlockBegin) {
473   SizeClassAllocatorGetBlockBeginStress<Allocator32Compact>(1ULL << 33);
474 }
475 #endif
476 #endif  // SANITIZER_CAN_USE_ALLOCATOR64
477 
478 struct TestMapUnmapCallback {
479   static int map_count, map_secondary_count, unmap_count;
480   void OnMap(uptr p, uptr size) const { map_count++; }
481   void OnMapSecondary(uptr p, uptr size, uptr user_begin,
482                       uptr user_size) const {
483     map_secondary_count++;
484   }
485   void OnUnmap(uptr p, uptr size) const { unmap_count++; }
486 
487   static void Reset() { map_count = map_secondary_count = unmap_count = 0; }
488 };
489 int TestMapUnmapCallback::map_count;
490 int TestMapUnmapCallback::map_secondary_count;
491 int TestMapUnmapCallback::unmap_count;
492 
493 #if SANITIZER_CAN_USE_ALLOCATOR64
494 // These tests can fail on Windows if memory is somewhat full and lit happens
495 // to run them all at the same time. FIXME: Make them not flaky and reenable.
496 #if !SANITIZER_WINDOWS
497 
498 template <typename AddressSpaceViewTy = LocalAddressSpaceView>
499 struct AP64WithCallback {
500   static const uptr kSpaceBeg = kAllocatorSpace;
501   static const uptr kSpaceSize = kAllocatorSize;
502   static const uptr kMetadataSize = 16;
503   typedef ::SizeClassMap SizeClassMap;
504   typedef TestMapUnmapCallback MapUnmapCallback;
505   static const uptr kFlags = 0;
506   using AddressSpaceView = AddressSpaceViewTy;
507 };
508 
509 TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) {
510   TestMapUnmapCallback::Reset();
511   typedef SizeClassAllocator64<AP64WithCallback<>> Allocator64WithCallBack;
512   Allocator64WithCallBack *a = new Allocator64WithCallBack;
513   a->Init(kReleaseToOSIntervalNever);
514   EXPECT_EQ(TestMapUnmapCallback::map_count, 1);  // Allocator state.
515   EXPECT_EQ(TestMapUnmapCallback::map_secondary_count, 0);
516   typename Allocator64WithCallBack::AllocatorCache cache;
517   memset(&cache, 0, sizeof(cache));
518   cache.Init(0);
519   AllocatorStats stats;
520   stats.Init();
521   const size_t kNumChunks = 128;
522   uint32_t chunks[kNumChunks];
523   a->GetFromAllocator(&stats, 30, chunks, kNumChunks);
524   // State + alloc + metadata + freearray.
525   EXPECT_EQ(TestMapUnmapCallback::map_count, 4);
526   EXPECT_EQ(TestMapUnmapCallback::map_secondary_count, 0);
527   a->TestOnlyUnmap();
528   EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);  // The whole thing.
529   delete a;
530 }
531 #endif
532 #endif
533 
534 template <typename AddressSpaceViewTy = LocalAddressSpaceView>
535 struct AP32WithCallback {
536   static const uptr kSpaceBeg = 0;
537   static const u64 kSpaceSize = kAddressSpaceSize;
538   static const uptr kMetadataSize = 16;
539   typedef CompactSizeClassMap SizeClassMap;
540   static const uptr kRegionSizeLog = ::kRegionSizeLog;
541   using AddressSpaceView = AddressSpaceViewTy;
542   typedef TestMapUnmapCallback MapUnmapCallback;
543   static const uptr kFlags = 0;
544 };
545 
546 TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {
547   TestMapUnmapCallback::Reset();
548   typedef SizeClassAllocator32<AP32WithCallback<>> Allocator32WithCallBack;
549   Allocator32WithCallBack *a = new Allocator32WithCallBack;
550   a->Init(kReleaseToOSIntervalNever);
551   EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
552   EXPECT_EQ(TestMapUnmapCallback::map_secondary_count, 0);
553   Allocator32WithCallBack::AllocatorCache cache;
554   memset(&cache, 0, sizeof(cache));
555   cache.Init(0);
556   AllocatorStats stats;
557   stats.Init();
558   a->AllocateBatch(&stats, &cache, 32);
559   EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
560   EXPECT_EQ(TestMapUnmapCallback::map_secondary_count, 0);
561   a->TestOnlyUnmap();
562   EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
563   delete a;
564 }
565 
566 TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) {
567   TestMapUnmapCallback::Reset();
568   LargeMmapAllocator<TestMapUnmapCallback> a;
569   a.Init();
570   AllocatorStats stats;
571   stats.Init();
572   void *x = a.Allocate(&stats, 1 << 20, 1);
573   EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
574   EXPECT_EQ(TestMapUnmapCallback::map_secondary_count, 1);
575   a.Deallocate(&stats, x);
576   EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
577 }
578 
579 // Don't test OOM conditions on Win64 because it causes other tests on the same
580 // machine to OOM.
581 #if SANITIZER_CAN_USE_ALLOCATOR64 && !SANITIZER_WINDOWS64
582 TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
583   Allocator64 a;
584   a.Init(kReleaseToOSIntervalNever);
585   Allocator64::AllocatorCache cache;
586   memset(&cache, 0, sizeof(cache));
587   cache.Init(0);
588   AllocatorStats stats;
589   stats.Init();
590 
591   const size_t kNumChunks = 128;
592   uint32_t chunks[kNumChunks];
593   bool allocation_failed = false;
594   for (int i = 0; i < 1000000; i++) {
595     uptr class_id = a.kNumClasses - 1;
596     if (!a.GetFromAllocator(&stats, class_id, chunks, kNumChunks)) {
597       allocation_failed = true;
598       break;
599     }
600   }
601   EXPECT_EQ(allocation_failed, true);
602 
603   a.TestOnlyUnmap();
604 }
605 #endif
606 
607 TEST(SanitizerCommon, LargeMmapAllocator) {
608   LargeMmapAllocator<NoOpMapUnmapCallback> a;
609   a.Init();
610   AllocatorStats stats;
611   stats.Init();
612 
613   static const int kNumAllocs = 1000;
614   char *allocated[kNumAllocs];
615   static const uptr size = 4000;
616   // Allocate some.
617   for (int i = 0; i < kNumAllocs; i++) {
618     allocated[i] = (char *)a.Allocate(&stats, size, 1);
619     CHECK(a.PointerIsMine(allocated[i]));
620   }
621   // Deallocate all.
622   CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
623   for (int i = 0; i < kNumAllocs; i++) {
624     char *p = allocated[i];
625     CHECK(a.PointerIsMine(p));
626     a.Deallocate(&stats, p);
627   }
628   // Check that non left.
629   CHECK_EQ(a.TotalMemoryUsed(), 0);
630 
631   // Allocate some more, also add metadata.
632   for (int i = 0; i < kNumAllocs; i++) {
633     char *x = (char *)a.Allocate(&stats, size, 1);
634     CHECK_GE(a.GetActuallyAllocatedSize(x), size);
635     uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
636     *meta = i;
637     allocated[i] = x;
638   }
639   for (int i = 0; i < kNumAllocs * kNumAllocs; i++) {
640     char *p = allocated[i % kNumAllocs];
641     CHECK(a.PointerIsMine(p));
642     CHECK(a.PointerIsMine(p + 2000));
643   }
644   CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
645   // Deallocate all in reverse order.
646   for (int i = 0; i < kNumAllocs; i++) {
647     int idx = kNumAllocs - i - 1;
648     char *p = allocated[idx];
649     uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
650     CHECK_EQ(*meta, idx);
651     CHECK(a.PointerIsMine(p));
652     a.Deallocate(&stats, p);
653   }
654   CHECK_EQ(a.TotalMemoryUsed(), 0);
655 
656   // Test alignments. Test with 512MB alignment on x64 non-Windows machines.
657   // Windows doesn't overcommit, and many machines do not have 51.2GB of swap.
658   uptr max_alignment =
659       (SANITIZER_WORDSIZE == 64 && !SANITIZER_WINDOWS) ? (1 << 28) : (1 << 24);
660   for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) {
661     const uptr kNumAlignedAllocs = 100;
662     for (uptr i = 0; i < kNumAlignedAllocs; i++) {
663       uptr size = ((i % 10) + 1) * 4096;
664       char *p = allocated[i] = (char *)a.Allocate(&stats, size, alignment);
665       CHECK_EQ(p, a.GetBlockBegin(p));
666       CHECK_EQ(p, a.GetBlockBegin(p + size - 1));
667       CHECK_EQ(p, a.GetBlockBegin(p + size / 2));
668       CHECK_EQ(0, (uptr)allocated[i] % alignment);
669       p[0] = p[size - 1] = 0;
670     }
671     for (uptr i = 0; i < kNumAlignedAllocs; i++) {
672       a.Deallocate(&stats, allocated[i]);
673     }
674   }
675 
676   // Regression test for boundary condition in GetBlockBegin().
677   uptr page_size = GetPageSizeCached();
678   char *p = (char *)a.Allocate(&stats, page_size, 1);
679   CHECK_EQ(p, a.GetBlockBegin(p));
680   CHECK_EQ(p, (char *)a.GetBlockBegin(p + page_size - 1));
681   CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
682   a.Deallocate(&stats, p);
683 }
684 
685 template <class PrimaryAllocator>
686 void TestCombinedAllocator(uptr premapped_heap = 0) {
687   typedef CombinedAllocator<PrimaryAllocator> Allocator;
688   Allocator *a = new Allocator;
689   a->Init(kReleaseToOSIntervalNever, premapped_heap);
690   std::mt19937 r;
691 
692   typename Allocator::AllocatorCache cache;
693   memset(&cache, 0, sizeof(cache));
694   a->InitCache(&cache);
695 
696   EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0);
697   EXPECT_EQ(a->Allocate(&cache, -1, 1024), (void*)0);
698   EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);
699   EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);
700   EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0);
701   EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0);
702 
703   const uptr kNumAllocs = 100000;
704   const uptr kNumIter = 10;
705   for (uptr iter = 0; iter < kNumIter; iter++) {
706     std::vector<void*> allocated;
707     for (uptr i = 0; i < kNumAllocs; i++) {
708       uptr size = (i % (1 << 14)) + 1;
709       if ((i % 1024) == 0)
710         size = 1 << (10 + (i % 14));
711       void *x = a->Allocate(&cache, size, 1);
712       uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
713       CHECK_EQ(*meta, 0);
714       *meta = size;
715       allocated.push_back(x);
716     }
717 
718     std::shuffle(allocated.begin(), allocated.end(), r);
719 
720     // Test ForEachChunk(...)
721     {
722       std::set<void *> reported_chunks;
723       auto cb = [](uptr chunk, void *arg) {
724         auto reported_chunks_ptr = reinterpret_cast<std::set<void *> *>(arg);
725         auto pair =
726             reported_chunks_ptr->insert(reinterpret_cast<void *>(chunk));
727         // Check chunk is never reported more than once.
728         ASSERT_TRUE(pair.second);
729       };
730       a->ForEachChunk(cb, reinterpret_cast<void *>(&reported_chunks));
731       for (const auto &allocated_ptr : allocated) {
732         ASSERT_NE(reported_chunks.find(allocated_ptr), reported_chunks.end());
733       }
734     }
735 
736     for (uptr i = 0; i < kNumAllocs; i++) {
737       void *x = allocated[i];
738       uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
739       CHECK_NE(*meta, 0);
740       CHECK(a->PointerIsMine(x));
741       *meta = 0;
742       a->Deallocate(&cache, x);
743     }
744     allocated.clear();
745     a->SwallowCache(&cache);
746   }
747   a->DestroyCache(&cache);
748   a->TestOnlyUnmap();
749 }
750 
751 #if SANITIZER_CAN_USE_ALLOCATOR64
752 TEST(SanitizerCommon, CombinedAllocator64) {
753   TestCombinedAllocator<Allocator64>();
754 }
755 
756 TEST(SanitizerCommon, CombinedAllocator64Dynamic) {
757   TestCombinedAllocator<Allocator64Dynamic>();
758 }
759 
760 #if !ALLOCATOR64_SMALL_SIZE
761 #if !SANITIZER_WINDOWS
762 // Windows fails to map 1TB, so disable this test.
763 TEST(SanitizerCommon, CombinedAllocator64DynamicPremapped) {
764   ScopedPremappedHeap h;
765   TestCombinedAllocator<Allocator64Dynamic>(h.Addr());
766 }
767 #endif
768 
769 TEST(SanitizerCommon, CombinedAllocator64Compact) {
770   TestCombinedAllocator<Allocator64Compact>();
771 }
772 #endif
773 
774 TEST(SanitizerCommon, CombinedAllocator64VeryCompact) {
775   TestCombinedAllocator<Allocator64VeryCompact>();
776 }
777 #endif
778 
779 TEST(SanitizerCommon, SKIP_ON_SOLARIS_SPARCV9(CombinedAllocator32Compact)) {
780   TestCombinedAllocator<Allocator32Compact>();
781 }
782 
783 template <class Allocator>
784 void TestSizeClassAllocatorLocalCache(uptr premapped_heap = 0) {
785   using AllocatorCache = typename Allocator::AllocatorCache;
786   AllocatorCache cache;
787   Allocator *a = new Allocator();
788 
789   a->Init(kReleaseToOSIntervalNever, premapped_heap);
790   memset(&cache, 0, sizeof(cache));
791   cache.Init(0);
792 
793   const uptr kNumAllocs = 10000;
794   const int kNumIter = 100;
795   uptr saved_total = 0;
796   for (int class_id = 1; class_id <= 5; class_id++) {
797     for (int it = 0; it < kNumIter; it++) {
798       void *allocated[kNumAllocs];
799       for (uptr i = 0; i < kNumAllocs; i++) {
800         allocated[i] = cache.Allocate(a, class_id);
801       }
802       for (uptr i = 0; i < kNumAllocs; i++) {
803         cache.Deallocate(a, class_id, allocated[i]);
804       }
805       cache.Drain(a);
806       uptr total_allocated = a->TotalMemoryUsed();
807       if (it)
808         CHECK_EQ(saved_total, total_allocated);
809       saved_total = total_allocated;
810     }
811   }
812 
813   a->TestOnlyUnmap();
814   delete a;
815 }
816 
817 #if SANITIZER_CAN_USE_ALLOCATOR64
818 // These tests can fail on Windows if memory is somewhat full and lit happens
819 // to run them all at the same time. FIXME: Make them not flaky and reenable.
820 #if !SANITIZER_WINDOWS
821 TEST(SanitizerCommon, SizeClassAllocator64LocalCache) {
822   TestSizeClassAllocatorLocalCache<Allocator64>();
823 }
824 
825 TEST(SanitizerCommon, SizeClassAllocator64DynamicLocalCache) {
826   TestSizeClassAllocatorLocalCache<Allocator64Dynamic>();
827 }
828 
829 #if !ALLOCATOR64_SMALL_SIZE
830 TEST(SanitizerCommon, SizeClassAllocator64DynamicPremappedLocalCache) {
831   ScopedPremappedHeap h;
832   TestSizeClassAllocatorLocalCache<Allocator64Dynamic>(h.Addr());
833 }
834 
835 TEST(SanitizerCommon, SizeClassAllocator64CompactLocalCache) {
836   TestSizeClassAllocatorLocalCache<Allocator64Compact>();
837 }
838 #endif
839 TEST(SanitizerCommon, SizeClassAllocator64VeryCompactLocalCache) {
840   TestSizeClassAllocatorLocalCache<Allocator64VeryCompact>();
841 }
842 #endif
843 #endif
844 
845 TEST(SanitizerCommon, SizeClassAllocator32CompactLocalCache) {
846   TestSizeClassAllocatorLocalCache<Allocator32Compact>();
847 }
848 
849 #if SANITIZER_CAN_USE_ALLOCATOR64
850 typedef Allocator64::AllocatorCache AllocatorCache;
851 static AllocatorCache static_allocator_cache;
852 
853 void *AllocatorLeakTestWorker(void *arg) {
854   typedef AllocatorCache::Allocator Allocator;
855   Allocator *a = (Allocator*)(arg);
856   static_allocator_cache.Allocate(a, 10);
857   static_allocator_cache.Drain(a);
858   return 0;
859 }
860 
861 TEST(SanitizerCommon, AllocatorLeakTest) {
862   typedef AllocatorCache::Allocator Allocator;
863   Allocator a;
864   a.Init(kReleaseToOSIntervalNever);
865   uptr total_used_memory = 0;
866   for (int i = 0; i < 100; i++) {
867     pthread_t t;
868     PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a);
869     PTHREAD_JOIN(t, 0);
870     if (i == 0)
871       total_used_memory = a.TotalMemoryUsed();
872     EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory);
873   }
874 
875   a.TestOnlyUnmap();
876 }
877 
878 // Struct which is allocated to pass info to new threads.  The new thread frees
879 // it.
880 struct NewThreadParams {
881   AllocatorCache *thread_cache;
882   AllocatorCache::Allocator *allocator;
883   uptr class_id;
884 };
885 
886 // Called in a new thread.  Just frees its argument.
887 static void *DeallocNewThreadWorker(void *arg) {
888   NewThreadParams *params = reinterpret_cast<NewThreadParams*>(arg);
889   params->thread_cache->Deallocate(params->allocator, params->class_id, params);
890   return NULL;
891 }
892 
893 // The allocator cache is supposed to be POD and zero initialized.  We should be
894 // able to call Deallocate on a zeroed cache, and it will self-initialize.
895 TEST(Allocator, AllocatorCacheDeallocNewThread) {
896   AllocatorCache::Allocator allocator;
897   allocator.Init(kReleaseToOSIntervalNever);
898   AllocatorCache main_cache;
899   AllocatorCache child_cache;
900   memset(&main_cache, 0, sizeof(main_cache));
901   memset(&child_cache, 0, sizeof(child_cache));
902 
903   uptr class_id = DefaultSizeClassMap::ClassID(sizeof(NewThreadParams));
904   NewThreadParams *params = reinterpret_cast<NewThreadParams*>(
905       main_cache.Allocate(&allocator, class_id));
906   params->thread_cache = &child_cache;
907   params->allocator = &allocator;
908   params->class_id = class_id;
909   pthread_t t;
910   PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params);
911   PTHREAD_JOIN(t, 0);
912 
913   allocator.TestOnlyUnmap();
914 }
915 #endif
916 
917 TEST(Allocator, Basic) {
918   char *p = (char*)InternalAlloc(10);
919   EXPECT_NE(p, (char*)0);
920   char *p2 = (char*)InternalAlloc(20);
921   EXPECT_NE(p2, (char*)0);
922   EXPECT_NE(p2, p);
923   InternalFree(p);
924   InternalFree(p2);
925 }
926 
927 TEST(Allocator, Stress) {
928   const int kCount = 1000;
929   char *ptrs[kCount];
930   unsigned rnd = 42;
931   for (int i = 0; i < kCount; i++) {
932     uptr sz = my_rand_r(&rnd) % 1000;
933     char *p = (char*)InternalAlloc(sz);
934     EXPECT_NE(p, (char*)0);
935     ptrs[i] = p;
936   }
937   for (int i = 0; i < kCount; i++) {
938     InternalFree(ptrs[i]);
939   }
940 }
941 
942 TEST(Allocator, LargeAlloc) {
943   void *p = InternalAlloc(10 << 20);
944   InternalFree(p);
945 }
946 
947 TEST(Allocator, ScopedBuffer) {
948   const int kSize = 512;
949   {
950     InternalMmapVector<int> int_buf(kSize);
951     EXPECT_EQ((uptr)kSize, int_buf.size());
952   }
953   InternalMmapVector<char> char_buf(kSize);
954   EXPECT_EQ((uptr)kSize, char_buf.size());
955   internal_memset(char_buf.data(), 'c', kSize);
956   for (int i = 0; i < kSize; i++) {
957     EXPECT_EQ('c', char_buf[i]);
958   }
959 }
960 
961 void IterationTestCallback(uptr chunk, void *arg) {
962   reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk);
963 }
964 
965 template <class Allocator>
966 void TestSizeClassAllocatorIteration(uptr premapped_heap = 0) {
967   Allocator *a = new Allocator;
968   a->Init(kReleaseToOSIntervalNever, premapped_heap);
969   typename Allocator::AllocatorCache cache;
970   memset(&cache, 0, sizeof(cache));
971   cache.Init(0);
972 
973   static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
974     50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000};
975 
976   std::vector<void *> allocated;
977 
978   // Allocate a bunch of chunks.
979   for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
980     uptr size = sizes[s];
981     if (!a->CanAllocate(size, 1)) continue;
982     // printf("s = %ld\n", size);
983     uptr n_iter = std::max((uptr)6, 80000 / size);
984     // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter);
985     for (uptr j = 0; j < n_iter; j++) {
986       uptr class_id0 = Allocator::SizeClassMapT::ClassID(size);
987       void *x = cache.Allocate(a, class_id0);
988       allocated.push_back(x);
989     }
990   }
991 
992   std::set<uptr> reported_chunks;
993   a->ForceLock();
994   a->ForEachChunk(IterationTestCallback, &reported_chunks);
995   a->ForceUnlock();
996 
997   for (uptr i = 0; i < allocated.size(); i++) {
998     // Don't use EXPECT_NE. Reporting the first mismatch is enough.
999     ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
1000               reported_chunks.end());
1001   }
1002 
1003   a->TestOnlyUnmap();
1004   delete a;
1005 }
1006 
1007 #if SANITIZER_CAN_USE_ALLOCATOR64
1008 // These tests can fail on Windows if memory is somewhat full and lit happens
1009 // to run them all at the same time. FIXME: Make them not flaky and reenable.
1010 #if !SANITIZER_WINDOWS
1011 TEST(SanitizerCommon, SizeClassAllocator64Iteration) {
1012   TestSizeClassAllocatorIteration<Allocator64>();
1013 }
1014 TEST(SanitizerCommon, SizeClassAllocator64DynamicIteration) {
1015   TestSizeClassAllocatorIteration<Allocator64Dynamic>();
1016 }
1017 #if !ALLOCATOR64_SMALL_SIZE
1018 TEST(SanitizerCommon, SizeClassAllocator64DynamicPremappedIteration) {
1019   ScopedPremappedHeap h;
1020   TestSizeClassAllocatorIteration<Allocator64Dynamic>(h.Addr());
1021 }
1022 #endif
1023 #endif
1024 #endif
1025 
1026 TEST(SanitizerCommon, SKIP_ON_SOLARIS_SPARCV9(SizeClassAllocator32Iteration)) {
1027   TestSizeClassAllocatorIteration<Allocator32Compact>();
1028 }
1029 
1030 TEST(SanitizerCommon, LargeMmapAllocatorIteration) {
1031   LargeMmapAllocator<NoOpMapUnmapCallback> a;
1032   a.Init();
1033   AllocatorStats stats;
1034   stats.Init();
1035 
1036   static const uptr kNumAllocs = 1000;
1037   char *allocated[kNumAllocs];
1038   static const uptr size = 40;
1039   // Allocate some.
1040   for (uptr i = 0; i < kNumAllocs; i++)
1041     allocated[i] = (char *)a.Allocate(&stats, size, 1);
1042 
1043   std::set<uptr> reported_chunks;
1044   a.ForceLock();
1045   a.ForEachChunk(IterationTestCallback, &reported_chunks);
1046   a.ForceUnlock();
1047 
1048   for (uptr i = 0; i < kNumAllocs; i++) {
1049     // Don't use EXPECT_NE. Reporting the first mismatch is enough.
1050     ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
1051               reported_chunks.end());
1052   }
1053   for (uptr i = 0; i < kNumAllocs; i++)
1054     a.Deallocate(&stats, allocated[i]);
1055 }
1056 
1057 TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) {
1058   LargeMmapAllocator<NoOpMapUnmapCallback> a;
1059   a.Init();
1060   AllocatorStats stats;
1061   stats.Init();
1062 
1063   static const uptr kNumAllocs = 1024;
1064   static const uptr kNumExpectedFalseLookups = 10000000;
1065   char *allocated[kNumAllocs];
1066   static const uptr size = 4096;
1067   // Allocate some.
1068   for (uptr i = 0; i < kNumAllocs; i++) {
1069     allocated[i] = (char *)a.Allocate(&stats, size, 1);
1070   }
1071 
1072   a.ForceLock();
1073   for (uptr i = 0; i < kNumAllocs  * kNumAllocs; i++) {
1074     // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i);
1075     char *p1 = allocated[i % kNumAllocs];
1076     EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1));
1077     EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2));
1078     EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1));
1079     EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100));
1080   }
1081 
1082   for (uptr i = 0; i < kNumExpectedFalseLookups; i++) {
1083     void *p = reinterpret_cast<void *>(i % 1024);
1084     EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
1085     p = reinterpret_cast<void *>(~0L - (i % 1024));
1086     EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
1087   }
1088   a.ForceUnlock();
1089 
1090   for (uptr i = 0; i < kNumAllocs; i++)
1091     a.Deallocate(&stats, allocated[i]);
1092 }
1093 
1094 
1095 // Don't test OOM conditions on Win64 because it causes other tests on the same
1096 // machine to OOM.
1097 #if SANITIZER_CAN_USE_ALLOCATOR64 && !SANITIZER_WINDOWS64 && !ALLOCATOR64_SMALL_SIZE
1098 typedef __sanitizer::SizeClassMap<2, 22, 22, 34, 128, 16> SpecialSizeClassMap;
1099 template <typename AddressSpaceViewTy = LocalAddressSpaceView>
1100 struct AP64_SpecialSizeClassMap {
1101   static const uptr kSpaceBeg = kAllocatorSpace;
1102   static const uptr kSpaceSize = kAllocatorSize;
1103   static const uptr kMetadataSize = 0;
1104   typedef SpecialSizeClassMap SizeClassMap;
1105   typedef NoOpMapUnmapCallback MapUnmapCallback;
1106   static const uptr kFlags = 0;
1107   using AddressSpaceView = AddressSpaceViewTy;
1108 };
1109 
1110 // Regression test for out-of-memory condition in PopulateFreeList().
1111 TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
1112   // In a world where regions are small and chunks are huge...
1113   typedef SizeClassAllocator64<AP64_SpecialSizeClassMap<>> SpecialAllocator64;
1114   const uptr kRegionSize =
1115       kAllocatorSize / SpecialSizeClassMap::kNumClassesRounded;
1116   SpecialAllocator64 *a = new SpecialAllocator64;
1117   a->Init(kReleaseToOSIntervalNever);
1118   SpecialAllocator64::AllocatorCache cache;
1119   memset(&cache, 0, sizeof(cache));
1120   cache.Init(0);
1121 
1122   // ...one man is on a mission to overflow a region with a series of
1123   // successive allocations.
1124 
1125   const uptr kClassID = 24;
1126   const uptr kAllocationSize = SpecialSizeClassMap::Size(kClassID);
1127   ASSERT_LT(2 * kAllocationSize, kRegionSize);
1128   ASSERT_GT(3 * kAllocationSize, kRegionSize);
1129   EXPECT_NE(cache.Allocate(a, kClassID), nullptr);
1130   EXPECT_NE(cache.Allocate(a, kClassID), nullptr);
1131   EXPECT_EQ(cache.Allocate(a, kClassID), nullptr);
1132 
1133   const uptr Class2 = 21;
1134   const uptr Size2 = SpecialSizeClassMap::Size(Class2);
1135   ASSERT_EQ(Size2 * 8, kRegionSize);
1136   char *p[7];
1137   for (int i = 0; i < 7; i++) {
1138     p[i] = (char*)cache.Allocate(a, Class2);
1139     EXPECT_NE(p[i], nullptr);
1140     fprintf(stderr, "p[%d] %p s = %lx\n", i, (void*)p[i], Size2);
1141     p[i][Size2 - 1] = 42;
1142     if (i) ASSERT_LT(p[i - 1], p[i]);
1143   }
1144   EXPECT_EQ(cache.Allocate(a, Class2), nullptr);
1145   cache.Deallocate(a, Class2, p[0]);
1146   cache.Drain(a);
1147   ASSERT_EQ(p[6][Size2 - 1], 42);
1148   a->TestOnlyUnmap();
1149   delete a;
1150 }
1151 
1152 #endif
1153 
1154 #if SANITIZER_CAN_USE_ALLOCATOR64
1155 
1156 class NoMemoryMapper {
1157  public:
1158   uptr last_request_buffer_size = 0;
1159 
1160   u64 *MapPackedCounterArrayBuffer(uptr buffer_size) {
1161     last_request_buffer_size = buffer_size * sizeof(u64);
1162     return nullptr;
1163   }
1164 };
1165 
1166 class RedZoneMemoryMapper {
1167  public:
1168   RedZoneMemoryMapper() {
1169     const auto page_size = GetPageSize();
1170     buffer = MmapOrDie(3ULL * page_size, "");
1171     MprotectNoAccess(reinterpret_cast<uptr>(buffer), page_size);
1172     MprotectNoAccess(reinterpret_cast<uptr>(buffer) + page_size * 2, page_size);
1173   }
1174   ~RedZoneMemoryMapper() { UnmapOrDie(buffer, 3 * GetPageSize()); }
1175 
1176   u64 *MapPackedCounterArrayBuffer(uptr buffer_size) {
1177     buffer_size *= sizeof(u64);
1178     const auto page_size = GetPageSize();
1179     CHECK_EQ(buffer_size, page_size);
1180     u64 *p =
1181         reinterpret_cast<u64 *>(reinterpret_cast<uptr>(buffer) + page_size);
1182     memset(p, 0, page_size);
1183     return p;
1184   }
1185 
1186  private:
1187   void *buffer;
1188 };
1189 
1190 TEST(SanitizerCommon, SizeClassAllocator64PackedCounterArray) {
1191   NoMemoryMapper no_memory_mapper;
1192   for (int i = 0; i < 64; i++) {
1193     // Various valid counter's max values packed into one word.
1194     Allocator64::PackedCounterArray counters_2n(1, 1ULL << i,
1195                                                 &no_memory_mapper);
1196     EXPECT_EQ(8ULL, no_memory_mapper.last_request_buffer_size);
1197 
1198     // Check the "all bit set" values too.
1199     Allocator64::PackedCounterArray counters_2n1_1(1, ~0ULL >> i,
1200                                                    &no_memory_mapper);
1201     EXPECT_EQ(8ULL, no_memory_mapper.last_request_buffer_size);
1202 
1203     // Verify the packing ratio, the counter is expected to be packed into the
1204     // closest power of 2 bits.
1205     Allocator64::PackedCounterArray counters(64, 1ULL << i, &no_memory_mapper);
1206     EXPECT_EQ(8ULL * RoundUpToPowerOfTwo(i + 1),
1207               no_memory_mapper.last_request_buffer_size);
1208   }
1209 
1210   RedZoneMemoryMapper memory_mapper;
1211   // Go through 1, 2, 4, 8, .. 64 bits per counter.
1212   for (int i = 0; i < 7; i++) {
1213     // Make sure counters request one memory page for the buffer.
1214     const u64 kNumCounters = (GetPageSize() / 8) * (64 >> i);
1215     Allocator64::PackedCounterArray counters(
1216         kNumCounters, 1ULL << ((1 << i) - 1), &memory_mapper);
1217     counters.Inc(0);
1218     for (u64 c = 1; c < kNumCounters - 1; c++) {
1219       ASSERT_EQ(0ULL, counters.Get(c));
1220       counters.Inc(c);
1221       ASSERT_EQ(1ULL, counters.Get(c - 1));
1222     }
1223     ASSERT_EQ(0ULL, counters.Get(kNumCounters - 1));
1224     counters.Inc(kNumCounters - 1);
1225 
1226     if (i > 0) {
1227       counters.IncRange(0, kNumCounters - 1);
1228       for (u64 c = 0; c < kNumCounters; c++)
1229         ASSERT_EQ(2ULL, counters.Get(c));
1230     }
1231   }
1232 }
1233 
1234 class RangeRecorder {
1235  public:
1236   std::string reported_pages;
1237 
1238   RangeRecorder()
1239       : page_size_scaled_log(
1240             Log2(GetPageSizeCached() >> Allocator64::kCompactPtrScale)),
1241         last_page_reported(0) {}
1242 
1243   void ReleasePageRangeToOS(u32 class_id, u32 from, u32 to) {
1244     from >>= page_size_scaled_log;
1245     to >>= page_size_scaled_log;
1246     ASSERT_LT(from, to);
1247     if (!reported_pages.empty())
1248       ASSERT_LT(last_page_reported, from);
1249     reported_pages.append(from - last_page_reported, '.');
1250     reported_pages.append(to - from, 'x');
1251     last_page_reported = to;
1252   }
1253 
1254  private:
1255   const uptr page_size_scaled_log;
1256   u32 last_page_reported;
1257 };
1258 
1259 TEST(SanitizerCommon, SizeClassAllocator64FreePagesRangeTracker) {
1260   typedef Allocator64::FreePagesRangeTracker<RangeRecorder> RangeTracker;
1261 
1262   // 'x' denotes a page to be released, '.' denotes a page to be kept around.
1263   const char* test_cases[] = {
1264       "",
1265       ".",
1266       "x",
1267       "........",
1268       "xxxxxxxxxxx",
1269       "..............xxxxx",
1270       "xxxxxxxxxxxxxxxxxx.....",
1271       "......xxxxxxxx........",
1272       "xxx..........xxxxxxxxxxxxxxx",
1273       "......xxxx....xxxx........",
1274       "xxx..........xxxxxxxx....xxxxxxx",
1275       "x.x.x.x.x.x.x.x.x.x.x.x.",
1276       ".x.x.x.x.x.x.x.x.x.x.x.x",
1277       ".x.x.x.x.x.x.x.x.x.x.x.x.",
1278       "x.x.x.x.x.x.x.x.x.x.x.x.x",
1279   };
1280 
1281   for (auto test_case : test_cases) {
1282     RangeRecorder range_recorder;
1283     RangeTracker tracker(&range_recorder, 1);
1284     for (int i = 0; test_case[i] != 0; i++)
1285       tracker.NextPage(test_case[i] == 'x');
1286     tracker.Done();
1287     // Strip trailing '.'-pages before comparing the results as they are not
1288     // going to be reported to range_recorder anyway.
1289     const char* last_x = strrchr(test_case, 'x');
1290     std::string expected(
1291         test_case,
1292         last_x == nullptr ? 0 : (last_x - test_case + 1));
1293     EXPECT_STREQ(expected.c_str(), range_recorder.reported_pages.c_str());
1294   }
1295 }
1296 
1297 class ReleasedPagesTrackingMemoryMapper {
1298  public:
1299   std::set<u32> reported_pages;
1300   std::vector<u64> buffer;
1301 
1302   u64 *MapPackedCounterArrayBuffer(uptr buffer_size) {
1303     reported_pages.clear();
1304     buffer.assign(buffer_size, 0);
1305     return buffer.data();
1306   }
1307   void ReleasePageRangeToOS(u32 class_id, u32 from, u32 to) {
1308     uptr page_size_scaled =
1309         GetPageSizeCached() >> Allocator64::kCompactPtrScale;
1310     for (u32 i = from; i < to; i += page_size_scaled)
1311       reported_pages.insert(i);
1312   }
1313 };
1314 
1315 template <class Allocator>
1316 void TestReleaseFreeMemoryToOS() {
1317   ReleasedPagesTrackingMemoryMapper memory_mapper;
1318   const uptr kAllocatedPagesCount = 1024;
1319   const uptr page_size = GetPageSizeCached();
1320   const uptr page_size_scaled = page_size >> Allocator::kCompactPtrScale;
1321   std::mt19937 r;
1322   uint32_t rnd_state = 42;
1323 
1324   for (uptr class_id = 1; class_id <= Allocator::SizeClassMapT::kLargestClassID;
1325       class_id++) {
1326     const uptr chunk_size = Allocator::SizeClassMapT::Size(class_id);
1327     const uptr chunk_size_scaled = chunk_size >> Allocator::kCompactPtrScale;
1328     const uptr max_chunks =
1329         kAllocatedPagesCount * GetPageSizeCached() / chunk_size;
1330 
1331     // Generate the random free list.
1332     std::vector<u32> free_array;
1333     bool in_free_range = false;
1334     uptr current_range_end = 0;
1335     for (uptr i = 0; i < max_chunks; i++) {
1336       if (i == current_range_end) {
1337         in_free_range = (my_rand_r(&rnd_state) & 1U) == 1;
1338         current_range_end += my_rand_r(&rnd_state) % 100 + 1;
1339       }
1340       if (in_free_range)
1341         free_array.push_back(i * chunk_size_scaled);
1342     }
1343     if (free_array.empty())
1344       continue;
1345     // Shuffle free_list to verify that ReleaseFreeMemoryToOS does not depend on
1346     // the list ordering.
1347     std::shuffle(free_array.begin(), free_array.end(), r);
1348 
1349     Allocator::ReleaseFreeMemoryToOS(&free_array[0], free_array.size(),
1350                                      chunk_size, kAllocatedPagesCount,
1351                                      &memory_mapper, class_id);
1352 
1353     // Verify that there are no released pages touched by used chunks and all
1354     // ranges of free chunks big enough to contain the entire memory pages had
1355     // these pages released.
1356     uptr verified_released_pages = 0;
1357     std::set<u32> free_chunks(free_array.begin(), free_array.end());
1358 
1359     u32 current_chunk = 0;
1360     in_free_range = false;
1361     u32 current_free_range_start = 0;
1362     for (uptr i = 0; i <= max_chunks; i++) {
1363       bool is_free_chunk = free_chunks.find(current_chunk) != free_chunks.end();
1364 
1365       if (is_free_chunk) {
1366         if (!in_free_range) {
1367           in_free_range = true;
1368           current_free_range_start = current_chunk;
1369         }
1370       } else {
1371         // Verify that this used chunk does not touch any released page.
1372         for (uptr i_page = current_chunk / page_size_scaled;
1373              i_page <= (current_chunk + chunk_size_scaled - 1) /
1374                        page_size_scaled;
1375              i_page++) {
1376           bool page_released =
1377               memory_mapper.reported_pages.find(i_page * page_size_scaled) !=
1378               memory_mapper.reported_pages.end();
1379           ASSERT_EQ(false, page_released);
1380         }
1381 
1382         if (in_free_range) {
1383           in_free_range = false;
1384           // Verify that all entire memory pages covered by this range of free
1385           // chunks were released.
1386           u32 page = RoundUpTo(current_free_range_start, page_size_scaled);
1387           while (page + page_size_scaled <= current_chunk) {
1388             bool page_released =
1389                 memory_mapper.reported_pages.find(page) !=
1390                 memory_mapper.reported_pages.end();
1391             ASSERT_EQ(true, page_released);
1392             verified_released_pages++;
1393             page += page_size_scaled;
1394           }
1395         }
1396       }
1397 
1398       current_chunk += chunk_size_scaled;
1399     }
1400 
1401     ASSERT_EQ(memory_mapper.reported_pages.size(), verified_released_pages);
1402   }
1403 }
1404 
1405 TEST(SanitizerCommon, SizeClassAllocator64ReleaseFreeMemoryToOS) {
1406   TestReleaseFreeMemoryToOS<Allocator64>();
1407 }
1408 
1409 #if !ALLOCATOR64_SMALL_SIZE
1410 TEST(SanitizerCommon, SizeClassAllocator64CompactReleaseFreeMemoryToOS) {
1411   TestReleaseFreeMemoryToOS<Allocator64Compact>();
1412 }
1413 
1414 TEST(SanitizerCommon, SizeClassAllocator64VeryCompactReleaseFreeMemoryToOS) {
1415   TestReleaseFreeMemoryToOS<Allocator64VeryCompact>();
1416 }
1417 #endif  // !ALLOCATOR64_SMALL_SIZE
1418 
1419 #endif  // SANITIZER_CAN_USE_ALLOCATOR64
1420 
1421 TEST(SanitizerCommon, LowLevelAllocatorShouldRoundUpSizeOnAlloc) {
1422   // When allocating a memory block slightly bigger than a memory page and
1423   // LowLevelAllocator calls MmapOrDie for the internal buffer, it should round
1424   // the size up to the page size, so that subsequent calls to the allocator
1425   // can use the remaining space in the last allocated page.
1426   static LowLevelAllocator allocator;
1427   char *ptr1 = (char *)allocator.Allocate(GetPageSizeCached() + 16);
1428   char *ptr2 = (char *)allocator.Allocate(16);
1429   EXPECT_EQ(ptr2, ptr1 + GetPageSizeCached() + 16);
1430 }
1431 
1432 #endif  // #if !SANITIZER_DEBUG
1433