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 "gtest/gtest.h"
18 : #include "syzygy/agent/asan/unittest_util.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.block < bi2.block;
30 E : }
31 : };
32 :
33 : typedef std::set<BlockInfo, BlockInfoLessThan> BlockInfoSet;
34 :
35 E : testing::DummyHeap dummy_heap;
36 :
37 : // A LargeBlockHeap that uses a null memory notifier.
38 : class TestLargeBlockHeap : public LargeBlockHeap {
39 : public:
40 E : TestLargeBlockHeap() : LargeBlockHeap(&dummy_heap) {
41 E : }
42 : };
43 :
44 : } // namespace
45 :
46 E : TEST(LargeBlockHeapTest, GetHeapTypeIsValid) {
47 E : TestLargeBlockHeap h;
48 E : EXPECT_EQ(kLargeBlockHeap, h.GetHeapType());
49 E : }
50 :
51 E : TEST(LargeBlockHeapTest, FeaturesAreValid) {
52 E : TestLargeBlockHeap h;
53 : EXPECT_EQ(HeapInterface::kHeapSupportsIsAllocated |
54 : HeapInterface::kHeapSupportsGetAllocationSize,
55 E : h.GetHeapFeatures());
56 E : }
57 :
58 E : TEST(LargeBlockHeapTest, EndToEnd) {
59 E : TestLargeBlockHeap h;
60 E : EXPECT_EQ(0u, h.size());
61 :
62 E : BlockLayout layout = {};
63 E : BlockInfo block = {};
64 :
65 : // Allocate and free a zero-sized allocation. This should succeed by
66 : // definition.
67 E : void* alloc = h.AllocateBlock(0, 0, 0, &layout);
68 E : EXPECT_EQ(1u, h.size());
69 E : BlockInitialize(layout, alloc, false, &block);
70 E : EXPECT_TRUE(h.FreeBlock(block));
71 E : EXPECT_EQ(0u, h.size());
72 :
73 : // Make a bunch of different sized allocations.
74 E : BlockInfoSet blocks;
75 E : for (size_t i = 1, j = 1; i < 1024 * 1024; i <<= 1, ++j) {
76 E : void* alloc = h.AllocateBlock(i, 0, 0, &layout);
77 E : EXPECT_EQ(j, h.size());
78 E : EXPECT_EQ(0u, layout.block_size % GetPageSize());
79 E : EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(alloc) % GetPageSize());
80 E : EXPECT_LE(GetPageSize(), layout.header_size + layout.header_padding_size);
81 E : EXPECT_EQ(i, layout.body_size);
82 E : EXPECT_LE(GetPageSize(), layout.trailer_padding_size + layout.trailer_size);
83 E : BlockInitialize(layout, alloc, false, &block);
84 E : blocks.insert(block);
85 E : }
86 :
87 : // Now free them.
88 E : BlockInfoSet::const_iterator it = blocks.begin();
89 E : for (; it != blocks.end(); ++it)
90 E : EXPECT_TRUE(h.FreeBlock(*it));
91 E : EXPECT_EQ(0u, h.size());
92 E : }
93 :
94 E : TEST(LargeBlockHeapTest, ZeroSizedAllocationsHaveDistinctAddresses) {
95 E : TestLargeBlockHeap h;
96 :
97 E : void* a1 = h.Allocate(0);
98 E : EXPECT_TRUE(a1 != NULL);
99 E : void* a2 = h.Allocate(0);
100 E : EXPECT_TRUE(a2 != NULL);
101 E : EXPECT_NE(a1, a2);
102 E : EXPECT_TRUE(h.Free(a1));
103 E : EXPECT_TRUE(h.Free(a2));
104 :
105 E : BlockLayout layout = {};
106 :
107 E : BlockInfo b1 = {};
108 E : a1 = h.AllocateBlock(0, 0, 0, &layout);
109 E : EXPECT_TRUE(a1 != NULL);
110 E : BlockInitialize(layout, a1, false, &b1);
111 :
112 E : BlockInfo b2 = {};
113 E : a2 = h.AllocateBlock(0, 0, 0, &layout);
114 E : EXPECT_TRUE(a2 != NULL);
115 E : BlockInitialize(layout, a2, false, &b2);
116 :
117 E : EXPECT_NE(a1, a2);
118 E : EXPECT_NE(b1.block, b2.block);
119 :
120 E : EXPECT_TRUE(h.FreeBlock(b1));
121 E : EXPECT_TRUE(h.FreeBlock(b2));
122 E : }
123 :
124 E : TEST(LargeBlockHeapTest, IsAllocated) {
125 E : TestLargeBlockHeap h;
126 :
127 E : EXPECT_FALSE(h.IsAllocated(NULL));
128 :
129 E : void* a = h.Allocate(100);
130 E : EXPECT_TRUE(h.IsAllocated(a));
131 E : EXPECT_FALSE(h.IsAllocated(reinterpret_cast<uint8*>(a) - 1));
132 E : EXPECT_FALSE(h.IsAllocated(reinterpret_cast<uint8*>(a) + 1));
133 :
134 E : EXPECT_TRUE(h.Free(a));
135 E : EXPECT_FALSE(h.IsAllocated(a));
136 E : }
137 :
138 E : TEST(LargeBlockHeapTest, GetAllocationSize) {
139 E : TestLargeBlockHeap h;
140 :
141 E : void* alloc = h.Allocate(67);
142 E : ASSERT_TRUE(alloc != NULL);
143 E : EXPECT_EQ(67u, h.GetAllocationSize(alloc));
144 E : EXPECT_TRUE(h.Free(alloc));
145 E : }
146 :
147 E : TEST(LargeBlockHeapTest, Lock) {
148 E : TestLargeBlockHeap h;
149 :
150 E : h.Lock();
151 E : EXPECT_TRUE(h.TryLock());
152 E : h.Unlock();
153 E : h.Unlock();
154 E : }
155 :
156 : } // namespace heaps
157 : } // namespace asan
158 : } // namespace agent
|