1 //===-- sanitizer_quarantine_test.cpp -------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
11 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_common.h"
13 #include "sanitizer_common/sanitizer_quarantine.h"
14 #include "gtest/gtest.h"
18 namespace __sanitizer
{
20 struct QuarantineCallback
{
21 void Recycle(void *m
) {}
22 void *Allocate(uptr size
) {
25 void Deallocate(void *p
) {
30 typedef QuarantineCache
<QuarantineCallback
> Cache
;
32 static void* kFakePtr
= reinterpret_cast<void*>(0xFA83FA83);
33 static const size_t kBlockSize
= 8;
35 static QuarantineCallback cb
;
37 static void DeallocateCache(Cache
*cache
) {
38 while (QuarantineBatch
*batch
= cache
->DequeueBatch())
42 TEST(SanitizerCommon
, QuarantineBatchMerge
) {
43 // Verify the trivial case.
45 into
.init(kFakePtr
, 4UL);
47 from
.init(kFakePtr
, 8UL);
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);
57 ASSERT_EQ(from
.count
, 0UL);
58 ASSERT_EQ(from
.size
, sizeof(QuarantineBatch
));
59 ASSERT_EQ(from
.quarantined_size(), 0UL);
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
));
68 ASSERT_TRUE(into
.count
== QuarantineBatch::kSize
);
70 // No more space, not even for one element.
71 from
.init(kFakePtr
, 8UL);
73 ASSERT_FALSE(into
.can_merge(&from
));
76 TEST(SanitizerCommon
, QuarantineCacheMergeBatchesEmpty
) {
79 cache
.MergeBatches(&to_deallocate
);
81 ASSERT_EQ(to_deallocate
.Size(), 0UL);
82 ASSERT_EQ(to_deallocate
.DequeueBatch(), nullptr);
85 TEST(SanitizerCommon
, QuarantineCacheMergeBatchesOneBatch
) {
87 cache
.Enqueue(cb
, kFakePtr
, kBlockSize
);
88 ASSERT_EQ(kBlockSize
+ sizeof(QuarantineBatch
), cache
.Size());
91 cache
.MergeBatches(&to_deallocate
);
93 // Nothing to merge, nothing to deallocate.
94 ASSERT_EQ(kBlockSize
+ sizeof(QuarantineBatch
), cache
.Size());
96 ASSERT_EQ(to_deallocate
.Size(), 0UL);
97 ASSERT_EQ(to_deallocate
.DequeueBatch(), nullptr);
99 DeallocateCache(&cache
);
102 TEST(SanitizerCommon
, QuarantineCacheMergeBatchesSmallBatches
) {
103 // Make a cache with two batches small enough to merge.
105 from
.Enqueue(cb
, kFakePtr
, kBlockSize
);
107 cache
.Enqueue(cb
, kFakePtr
, kBlockSize
);
109 cache
.Transfer(&from
);
110 ASSERT_EQ(kBlockSize
* 2 + sizeof(QuarantineBatch
) * 2, cache
.Size());
113 cache
.MergeBatches(&to_deallocate
);
115 // Batches merged, one batch to deallocate.
116 ASSERT_EQ(kBlockSize
* 2 + sizeof(QuarantineBatch
), cache
.Size());
117 ASSERT_EQ(to_deallocate
.Size(), sizeof(QuarantineBatch
));
119 DeallocateCache(&cache
);
120 DeallocateCache(&to_deallocate
);
123 TEST(SanitizerCommon
, QuarantineCacheMergeBatchesTooBigToMerge
) {
124 const uptr kNumBlocks
= QuarantineBatch::kSize
- 1;
126 // Make a cache with two batches small enough to merge.
129 for (uptr i
= 0; i
< kNumBlocks
; ++i
) {
130 from
.Enqueue(cb
, kFakePtr
, kBlockSize
);
131 cache
.Enqueue(cb
, kFakePtr
, kBlockSize
);
133 cache
.Transfer(&from
);
134 ASSERT_EQ(kBlockSize
* kNumBlocks
* 2 +
135 sizeof(QuarantineBatch
) * 2, cache
.Size());
138 cache
.MergeBatches(&to_deallocate
);
140 // Batches cannot be merged.
141 ASSERT_EQ(kBlockSize
* kNumBlocks
* 2 +
142 sizeof(QuarantineBatch
) * 2, cache
.Size());
143 ASSERT_EQ(to_deallocate
.Size(), 0UL);
145 DeallocateCache(&cache
);
148 TEST(SanitizerCommon
, QuarantineCacheMergeBatchesALotOfBatches
) {
149 const uptr kNumBatchesAfterMerge
= 3;
150 const uptr kNumBlocks
= QuarantineBatch::kSize
* kNumBatchesAfterMerge
;
151 const uptr kNumBatchesBeforeMerge
= kNumBlocks
;
153 // Make a cache with many small batches.
155 for (uptr i
= 0; i
< kNumBlocks
; ++i
) {
157 from
.Enqueue(cb
, kFakePtr
, kBlockSize
);
158 cache
.Transfer(&from
);
161 ASSERT_EQ(kBlockSize
* kNumBlocks
+
162 sizeof(QuarantineBatch
) * kNumBatchesBeforeMerge
, cache
.Size());
165 cache
.MergeBatches(&to_deallocate
);
167 // All blocks should fit into 3 batches.
168 ASSERT_EQ(kBlockSize
* kNumBlocks
+
169 sizeof(QuarantineBatch
) * kNumBatchesAfterMerge
, cache
.Size());
171 ASSERT_EQ(to_deallocate
.Size(),
172 sizeof(QuarantineBatch
) *
173 (kNumBatchesBeforeMerge
- kNumBatchesAfterMerge
));
175 DeallocateCache(&cache
);
176 DeallocateCache(&to_deallocate
);
179 } // namespace __sanitizer