Home | History | Annotate | Line # | Download | only in tests
      1 //===-- sanitizer_quarantine_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 //
     10 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 #include "sanitizer_common/sanitizer_common.h"
     14 #include "sanitizer_common/sanitizer_quarantine.h"
     15 #include "gtest/gtest.h"
     16 
     17 #include <stdlib.h>
     18 
     19 namespace __sanitizer {
     20 
     21 struct QuarantineCallback {
     22   void Recycle(void *m) {}
     23   void *Allocate(uptr size) {
     24     return malloc(size);
     25   }
     26   void Deallocate(void *p) {
     27     free(p);
     28   }
     29 };
     30 
     31 typedef QuarantineCache<QuarantineCallback> Cache;
     32 
     33 static void* kFakePtr = reinterpret_cast<void*>(0xFA83FA83);
     34 static const size_t kBlockSize = 8;
     35 
     36 static QuarantineCallback cb;
     37 
     38 static void DeallocateCache(Cache *cache) {
     39   while (QuarantineBatch *batch = cache->DequeueBatch())
     40     cb.Deallocate(batch);
     41 }
     42 
     43 TEST(SanitizerCommon, QuarantineBatchMerge) {
     44   // Verify the trivial case.
     45   QuarantineBatch into;
     46   into.init(kFakePtr, 4UL);
     47   QuarantineBatch from;
     48   from.init(kFakePtr, 8UL);
     49 
     50   into.merge(&from);
     51 
     52   ASSERT_EQ(into.count, 2UL);
     53   ASSERT_EQ(into.batch[0], kFakePtr);
     54   ASSERT_EQ(into.batch[1], kFakePtr);
     55   ASSERT_EQ(into.size, 12UL + sizeof(QuarantineBatch));
     56   ASSERT_EQ(into.quarantined_size(), 12UL);
     57 
     58   ASSERT_EQ(from.count, 0UL);
     59   ASSERT_EQ(from.size, sizeof(QuarantineBatch));
     60   ASSERT_EQ(from.quarantined_size(), 0UL);
     61 
     62   // Merge the batch to the limit.
     63   for (uptr i = 2; i < QuarantineBatch::kSize; ++i)
     64     from.push_back(kFakePtr, 8UL);
     65   ASSERT_TRUE(into.count + from.count == QuarantineBatch::kSize);
     66   ASSERT_TRUE(into.can_merge(&from));
     67 
     68   into.merge(&from);
     69   ASSERT_TRUE(into.count == QuarantineBatch::kSize);
     70 
     71   // No more space, not even for one element.
     72   from.init(kFakePtr, 8UL);
     73 
     74   ASSERT_FALSE(into.can_merge(&from));
     75 }
     76 
     77 TEST(SanitizerCommon, QuarantineCacheMergeBatchesEmpty) {
     78   Cache cache;
     79   Cache to_deallocate;
     80   cache.MergeBatches(&to_deallocate);
     81 
     82   ASSERT_EQ(to_deallocate.Size(), 0UL);
     83   ASSERT_EQ(to_deallocate.DequeueBatch(), nullptr);
     84 }
     85 
     86 TEST(SanitizerCommon, QuarantineCacheMergeBatchesOneBatch) {
     87   Cache cache;
     88   cache.Enqueue(cb, kFakePtr, kBlockSize);
     89   ASSERT_EQ(kBlockSize + sizeof(QuarantineBatch), cache.Size());
     90 
     91   Cache to_deallocate;
     92   cache.MergeBatches(&to_deallocate);
     93 
     94   // Nothing to merge, nothing to deallocate.
     95   ASSERT_EQ(kBlockSize + sizeof(QuarantineBatch), cache.Size());
     96 
     97   ASSERT_EQ(to_deallocate.Size(), 0UL);
     98   ASSERT_EQ(to_deallocate.DequeueBatch(), nullptr);
     99 
    100   DeallocateCache(&cache);
    101 }
    102 
    103 TEST(SanitizerCommon, QuarantineCacheMergeBatchesSmallBatches) {
    104   // Make a cache with two batches small enough to merge.
    105   Cache from;
    106   from.Enqueue(cb, kFakePtr, kBlockSize);
    107   Cache cache;
    108   cache.Enqueue(cb, kFakePtr, kBlockSize);
    109 
    110   cache.Transfer(&from);
    111   ASSERT_EQ(kBlockSize * 2 + sizeof(QuarantineBatch) * 2, cache.Size());
    112 
    113   Cache to_deallocate;
    114   cache.MergeBatches(&to_deallocate);
    115 
    116   // Batches merged, one batch to deallocate.
    117   ASSERT_EQ(kBlockSize * 2 + sizeof(QuarantineBatch), cache.Size());
    118   ASSERT_EQ(to_deallocate.Size(), sizeof(QuarantineBatch));
    119 
    120   DeallocateCache(&cache);
    121   DeallocateCache(&to_deallocate);
    122 }
    123 
    124 TEST(SanitizerCommon, QuarantineCacheMergeBatchesTooBigToMerge) {
    125   const uptr kNumBlocks = QuarantineBatch::kSize - 1;
    126 
    127   // Make a cache with two batches small enough to merge.
    128   Cache from;
    129   Cache cache;
    130   for (uptr i = 0; i < kNumBlocks; ++i) {
    131     from.Enqueue(cb, kFakePtr, kBlockSize);
    132     cache.Enqueue(cb, kFakePtr, kBlockSize);
    133   }
    134   cache.Transfer(&from);
    135   ASSERT_EQ(kBlockSize * kNumBlocks * 2 +
    136             sizeof(QuarantineBatch) * 2, cache.Size());
    137 
    138   Cache to_deallocate;
    139   cache.MergeBatches(&to_deallocate);
    140 
    141   // Batches cannot be merged.
    142   ASSERT_EQ(kBlockSize * kNumBlocks * 2 +
    143             sizeof(QuarantineBatch) * 2, cache.Size());
    144   ASSERT_EQ(to_deallocate.Size(), 0UL);
    145 
    146   DeallocateCache(&cache);
    147 }
    148 
    149 TEST(SanitizerCommon, QuarantineCacheMergeBatchesALotOfBatches) {
    150   const uptr kNumBatchesAfterMerge = 3;
    151   const uptr kNumBlocks = QuarantineBatch::kSize * kNumBatchesAfterMerge;
    152   const uptr kNumBatchesBeforeMerge = kNumBlocks;
    153 
    154   // Make a cache with many small batches.
    155   Cache cache;
    156   for (uptr i = 0; i < kNumBlocks; ++i) {
    157     Cache from;
    158     from.Enqueue(cb, kFakePtr, kBlockSize);
    159     cache.Transfer(&from);
    160   }
    161 
    162   ASSERT_EQ(kBlockSize * kNumBlocks +
    163             sizeof(QuarantineBatch) * kNumBatchesBeforeMerge, cache.Size());
    164 
    165   Cache to_deallocate;
    166   cache.MergeBatches(&to_deallocate);
    167 
    168   // All blocks should fit into 3 batches.
    169   ASSERT_EQ(kBlockSize * kNumBlocks +
    170             sizeof(QuarantineBatch) * kNumBatchesAfterMerge, cache.Size());
    171 
    172   ASSERT_EQ(to_deallocate.Size(),
    173             sizeof(QuarantineBatch) *
    174                 (kNumBatchesBeforeMerge - kNumBatchesAfterMerge));
    175 
    176   DeallocateCache(&cache);
    177   DeallocateCache(&to_deallocate);
    178 }
    179 
    180 }  // namespace __sanitizer
    181