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