1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <sys/mman.h>
18 #include <unistd.h>
19
20 #include "HeapWalker.h"
21
22 #include <ScopedDisableMalloc.h>
23 #include <gtest/gtest.h>
24 #include "Allocator.h"
25
26 namespace android {
27
28 class HeapWalkerTest : public ::testing::Test {
29 public:
HeapWalkerTest()30 HeapWalkerTest() : disable_malloc_(), heap_() {}
31
TearDown()32 void TearDown() {
33 ASSERT_TRUE(heap_.empty());
34 if (!HasFailure()) {
35 ASSERT_FALSE(disable_malloc_.timed_out());
36 }
37 }
38
39 protected:
40 ScopedDisableMallocTimeout disable_malloc_;
41 Heap heap_;
42 };
43
TEST_F(HeapWalkerTest,allocation)44 TEST_F(HeapWalkerTest, allocation) {
45 HeapWalker heap_walker(heap_);
46 ASSERT_TRUE(heap_walker.Allocation(3, 4));
47 ASSERT_TRUE(heap_walker.Allocation(2, 3));
48 ASSERT_TRUE(heap_walker.Allocation(4, 5));
49 ASSERT_TRUE(heap_walker.Allocation(6, 7));
50 ASSERT_TRUE(heap_walker.Allocation(0, 1));
51 }
52
TEST_F(HeapWalkerTest,overlap)53 TEST_F(HeapWalkerTest, overlap) {
54 HeapWalker heap_walker(heap_);
55 ASSERT_TRUE(heap_walker.Allocation(2, 3));
56 ASSERT_TRUE(heap_walker.Allocation(3, 4));
57 ASSERT_FALSE(heap_walker.Allocation(2, 3));
58 ASSERT_FALSE(heap_walker.Allocation(1, 3));
59 ASSERT_FALSE(heap_walker.Allocation(1, 4));
60 ASSERT_FALSE(heap_walker.Allocation(1, 5));
61 ASSERT_FALSE(heap_walker.Allocation(3, 4));
62 ASSERT_FALSE(heap_walker.Allocation(3, 5));
63 ASSERT_TRUE(heap_walker.Allocation(4, 5));
64 ASSERT_TRUE(heap_walker.Allocation(1, 2));
65 }
66
TEST_F(HeapWalkerTest,zero)67 TEST_F(HeapWalkerTest, zero) {
68 HeapWalker heap_walker(heap_);
69 ASSERT_TRUE(heap_walker.Allocation(2, 2));
70 ASSERT_FALSE(heap_walker.Allocation(2, 2));
71 ASSERT_TRUE(heap_walker.Allocation(3, 3));
72 ASSERT_TRUE(heap_walker.Allocation(1, 1));
73 ASSERT_FALSE(heap_walker.Allocation(2, 3));
74 }
75
TEST_F(HeapWalkerTest,mapping)76 TEST_F(HeapWalkerTest, mapping) {
77 HeapWalker heap_walker(heap_);
78 heap_walker.Mapping(2, 3);
79 heap_walker.Mapping(4, 5);
80 ASSERT_TRUE(heap_walker.Allocation(2, 3));
81 ASSERT_TRUE(heap_walker.Allocation(4, 5));
82 // space between mappings is not checked, but could be in the future
83 ASSERT_TRUE(heap_walker.Allocation(3, 4));
84
85 // re-enable malloc, ASSERT_DEATH may allocate
86 disable_malloc_.Enable();
87 ASSERT_DEATH({ heap_walker.Allocation(1, 2); }, "0x1-0x2.*outside.*0x2-0x5");
88 ASSERT_DEATH({ heap_walker.Allocation(1, 3); }, "0x1-0x3.*outside.*0x2-0x5");
89 ASSERT_DEATH({ heap_walker.Allocation(4, 6); }, "0x4-0x6.*outside.*0x2-0x5");
90 ASSERT_DEATH({ heap_walker.Allocation(5, 6); }, "0x5-0x6.*outside.*0x2-0x5");
91 ASSERT_DEATH({ heap_walker.Allocation(1, 6); }, "0x1-0x6.*outside.*0x2-0x5");
92 }
93
94 #define buffer_begin(buffer) reinterpret_cast<uintptr_t>(buffer)
95 #define buffer_end(buffer) (reinterpret_cast<uintptr_t>(buffer) + sizeof(buffer))
96
TEST_F(HeapWalkerTest,leak)97 TEST_F(HeapWalkerTest, leak) {
98 void* buffer1[16]{};
99 char buffer2[16]{};
100 buffer1[0] = &buffer2[0] - sizeof(void*);
101 buffer1[1] = &buffer2[15] + sizeof(void*);
102
103 HeapWalker heap_walker(heap_);
104 heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
105
106 ASSERT_EQ(true, heap_walker.DetectLeaks());
107
108 allocator::vector<Range> leaked(heap_);
109 size_t num_leaks = 0;
110 size_t leaked_bytes = 0;
111 ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
112
113 EXPECT_EQ(1U, num_leaks);
114 EXPECT_EQ(16U, leaked_bytes);
115 ASSERT_EQ(1U, leaked.size());
116 EXPECT_EQ(buffer_begin(buffer2), leaked[0].begin);
117 EXPECT_EQ(buffer_end(buffer2), leaked[0].end);
118 }
119
TEST_F(HeapWalkerTest,live)120 TEST_F(HeapWalkerTest, live) {
121 const int from_buffer_entries = 4;
122 const int to_buffer_bytes = 16;
123
124 for (int i = 0; i < from_buffer_entries; i++) {
125 for (int j = 0; j < to_buffer_bytes; j++) {
126 void* buffer1[from_buffer_entries]{};
127 char buffer2[to_buffer_bytes]{};
128 buffer1[i] = &buffer2[j];
129
130 HeapWalker heap_walker(heap_);
131 heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
132 heap_walker.Root(buffer_begin(buffer1), buffer_end(buffer1));
133
134 ASSERT_EQ(true, heap_walker.DetectLeaks());
135
136 allocator::vector<Range> leaked(heap_);
137 size_t num_leaks = SIZE_MAX;
138 size_t leaked_bytes = SIZE_MAX;
139 ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
140
141 EXPECT_EQ(0U, num_leaks);
142 EXPECT_EQ(0U, leaked_bytes);
143 EXPECT_EQ(0U, leaked.size());
144 }
145 }
146 }
147
TEST_F(HeapWalkerTest,unaligned)148 TEST_F(HeapWalkerTest, unaligned) {
149 const int from_buffer_entries = 4;
150 const int to_buffer_bytes = 16;
151 void* buffer1[from_buffer_entries]{};
152 char buffer2[to_buffer_bytes]{};
153
154 buffer1[1] = &buffer2;
155
156 for (unsigned int i = 0; i < sizeof(uintptr_t); i++) {
157 for (unsigned int j = 0; j < sizeof(uintptr_t); j++) {
158 HeapWalker heap_walker(heap_);
159 heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
160 heap_walker.Root(buffer_begin(buffer1) + i, buffer_end(buffer1) - j);
161
162 ASSERT_EQ(true, heap_walker.DetectLeaks());
163
164 allocator::vector<Range> leaked(heap_);
165 size_t num_leaks = SIZE_MAX;
166 size_t leaked_bytes = SIZE_MAX;
167 ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
168
169 EXPECT_EQ(0U, num_leaks);
170 EXPECT_EQ(0U, leaked_bytes);
171 EXPECT_EQ(0U, leaked.size());
172 }
173 }
174 }
175
TEST_F(HeapWalkerTest,cycle)176 TEST_F(HeapWalkerTest, cycle) {
177 void* buffer1;
178 void* buffer2;
179
180 buffer1 = &buffer2;
181 buffer2 = &buffer1;
182
183 HeapWalker heap_walker(heap_);
184 heap_walker.Allocation(buffer_begin(buffer1), buffer_end(buffer1));
185 heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
186
187 ASSERT_EQ(true, heap_walker.DetectLeaks());
188
189 allocator::vector<Range> leaked(heap_);
190 size_t num_leaks = 0;
191 size_t leaked_bytes = 0;
192 ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
193
194 EXPECT_EQ(2U, num_leaks);
195 EXPECT_EQ(2 * sizeof(uintptr_t), leaked_bytes);
196 ASSERT_EQ(2U, leaked.size());
197 }
198
TEST_F(HeapWalkerTest,segv)199 TEST_F(HeapWalkerTest, segv) {
200 const size_t page_size = sysconf(_SC_PAGE_SIZE);
201 void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
202 ASSERT_NE(buffer1, nullptr);
203 void* buffer2;
204
205 buffer2 = &buffer1;
206
207 HeapWalker heap_walker(heap_);
208 heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1) + page_size);
209 heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
210
211 ASSERT_EQ(true, heap_walker.DetectLeaks());
212
213 allocator::vector<Range> leaked(heap_);
214 size_t num_leaks = 0;
215 size_t leaked_bytes = 0;
216 ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
217
218 EXPECT_EQ(0U, num_leaks);
219 EXPECT_EQ(0U, leaked_bytes);
220 ASSERT_EQ(0U, leaked.size());
221 }
222
223 } // namespace android
224