1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/agent/asan/heaps/large_block_heap.h"
16 :
17 : #include "syzygy/agent/asan/unittest_util.h"
18 : #include "syzygy/agent/asan/memory_notifiers/null_memory_notifier.h"
19 :
20 : namespace agent {
21 : namespace asan {
22 : namespace heaps {
23 :
24 : namespace {
25 :
26 : // Provides an ordering for BlockInfo objects.
27 : struct BlockInfoLessThan {
28 E : bool operator()(const BlockInfo& bi1, const BlockInfo& bi2) const {
29 E : return bi1.header < bi2.header;
30 E : }
31 : };
32 :
33 : typedef std::set<BlockInfo, BlockInfoLessThan> BlockInfoSet;
34 :
35 E : testing::DummyHeap dummy_heap;
36 E : agent::asan::memory_notifiers::NullMemoryNotifier dummy_notifier;
37 :
38 : // A LargeBlockHeap that uses a null memory notifier.
39 : class TestLargeBlockHeap : public LargeBlockHeap {
40 : public:
41 : using LargeBlockHeap::FreeAllAllocations;
42 :
43 E : TestLargeBlockHeap() : LargeBlockHeap(&dummy_notifier, &dummy_heap) {
44 E : }
45 : };
46 :
47 : } // namespace
48 :
49 E : TEST(LargeBlockHeapTest, GetHeapTypeIsValid) {
50 E : TestLargeBlockHeap h;
51 E : EXPECT_EQ(kLargeBlockHeap, h.GetHeapType());
52 E : }
53 :
54 E : TEST(LargeBlockHeapTest, FeaturesAreValid) {
55 E : TestLargeBlockHeap h;
56 : EXPECT_EQ(HeapInterface::kHeapSupportsIsAllocated |
57 : HeapInterface::kHeapSupportsGetAllocationSize |
58 : HeapInterface::kHeapReportsReservations,
59 E : h.GetHeapFeatures());
60 E : }
61 :
62 E : TEST(LargeBlockHeapTest, EndToEnd) {
63 E : TestLargeBlockHeap h;
64 E : EXPECT_EQ(0u, h.size());
65 :
66 E : BlockLayout layout = {};
67 E : BlockInfo block = {};
68 :
69 : // Allocate and free a zero-sized allocation. This should succeed by
70 : // definition.
71 E : void* alloc = h.AllocateBlock(0, 0, 0, &layout);
72 E : EXPECT_EQ(1u, h.size());
73 E : BlockInitialize(layout, alloc, false, &block);
74 E : EXPECT_TRUE(h.FreeBlock(block));
75 E : EXPECT_EQ(0u, h.size());
76 :
77 : // Make a bunch of different sized allocations.
78 E : BlockInfoSet blocks;
79 E : for (size_t i = 1, j = 1; i < 1024 * 1024; i <<= 1, ++j) {
80 E : void* alloc = h.AllocateBlock(i, 0, 0, &layout);
81 E : EXPECT_EQ(j, h.size());
82 E : EXPECT_EQ(0u, layout.block_size % GetPageSize());
83 E : EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(alloc) % GetPageSize());
84 E : EXPECT_LE(GetPageSize(), layout.header_size + layout.header_padding_size);
85 E : EXPECT_EQ(i, layout.body_size);
86 E : EXPECT_LE(GetPageSize(), layout.trailer_padding_size + layout.trailer_size);
87 E : BlockInitialize(layout, alloc, false, &block);
88 E : blocks.insert(block);
89 E : }
90 :
91 : // Now free them.
92 E : BlockInfoSet::const_iterator it = blocks.begin();
93 E : for (; it != blocks.end(); ++it)
94 E : EXPECT_TRUE(h.FreeBlock(*it));
95 E : EXPECT_EQ(0u, h.size());
96 E : }
97 :
98 E : TEST(LargeBlockHeapTest, ZeroSizedAllocationsHaveDistinctAddresses) {
99 E : TestLargeBlockHeap h;
100 :
101 E : void* a1 = h.Allocate(0);
102 E : EXPECT_TRUE(a1 != NULL);
103 E : void* a2 = h.Allocate(0);
104 E : EXPECT_TRUE(a2 != NULL);
105 E : EXPECT_NE(a1, a2);
106 E : EXPECT_TRUE(h.Free(a1));
107 E : EXPECT_TRUE(h.Free(a2));
108 :
109 E : BlockLayout layout = {};
110 :
111 E : BlockInfo b1 = {};
112 E : a1 = h.AllocateBlock(0, 0, 0, &layout);
113 E : EXPECT_TRUE(a1 != NULL);
114 E : BlockInitialize(layout, a1, false, &b1);
115 :
116 E : BlockInfo b2 = {};
117 E : a2 = h.AllocateBlock(0, 0, 0, &layout);
118 E : EXPECT_TRUE(a2 != NULL);
119 E : BlockInitialize(layout, a2, false, &b2);
120 :
121 E : EXPECT_NE(a1, a2);
122 E : EXPECT_NE(b1.header, b2.header);
123 :
124 E : EXPECT_TRUE(h.FreeBlock(b1));
125 E : EXPECT_TRUE(h.FreeBlock(b2));
126 E : }
127 :
128 E : TEST(LargeBlockHeapTest, IsAllocated) {
129 E : TestLargeBlockHeap h;
130 :
131 E : EXPECT_FALSE(h.IsAllocated(NULL));
132 :
133 E : void* a = h.Allocate(100);
134 E : EXPECT_TRUE(h.IsAllocated(a));
135 E : EXPECT_FALSE(h.IsAllocated(reinterpret_cast<uint8*>(a) - 1));
136 E : EXPECT_FALSE(h.IsAllocated(reinterpret_cast<uint8*>(a) + 1));
137 :
138 E : EXPECT_TRUE(h.Free(a));
139 E : EXPECT_FALSE(h.IsAllocated(a));
140 E : }
141 :
142 E : TEST(LargeBlockHeapTest, GetAllocationSize) {
143 E : TestLargeBlockHeap h;
144 :
145 E : void* alloc = h.Allocate(67);
146 E : ASSERT_TRUE(alloc != NULL);
147 E : EXPECT_EQ(67u, h.GetAllocationSize(alloc));
148 E : EXPECT_TRUE(h.Free(alloc));
149 E : }
150 :
151 E : TEST(LargeBlockHeapTest, Lock) {
152 E : TestLargeBlockHeap h;
153 :
154 E : h.Lock();
155 E : EXPECT_TRUE(h.TryLock());
156 E : h.Unlock();
157 E : h.Unlock();
158 E : }
159 :
160 E : TEST(LargeBlockHeapTest, FreeAllAllocations) {
161 E : const size_t kAllocCount = 10;
162 E : TestLargeBlockHeap h;
163 E : for (size_t i = 0; i < kAllocCount; ++i)
164 E : h.Allocate(42);
165 E : EXPECT_EQ(kAllocCount, h.size());
166 E : h.FreeAllAllocations();
167 E : EXPECT_EQ(0U, h.size());
168 E : }
169 :
170 E : TEST(LargeBlockHeapTest, DestructionWithOutstandingAllocationsSucceeds) {
171 E : const size_t kAllocCount = 10;
172 E : TestLargeBlockHeap h;
173 : // Create some allocations and intentionally leak them. They should be
174 : // automatically released in the LargeBlockHeap destructor. This will only
175 : // fail due to a CHECK in the LargeBlockHeap that ensure that there's no more
176 : // alive allocations after calling FreeAllAllocations.
177 E : for (size_t i = 0; i < kAllocCount; ++i)
178 E : h.Allocate(42);
179 E : EXPECT_EQ(kAllocCount, h.size());
180 E : }
181 :
182 : } // namespace heaps
183 : } // namespace asan
184 : } // namespace agent
|