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 <gtest/gtest.h>
23#include <ScopedDisableMalloc.h>
24#include "Allocator.h"
25
26class HeapWalkerTest : public ::testing::Test {
27 public:
28  HeapWalkerTest() : disable_malloc_(), heap_() {}
29
30  void TearDown() {
31    ASSERT_TRUE(heap_.empty());
32    if (!HasFailure()) {
33      ASSERT_FALSE(disable_malloc_.timed_out());
34    }
35  }
36
37 protected:
38  ScopedDisableMallocTimeout disable_malloc_;
39  Heap heap_;
40};
41
42TEST_F(HeapWalkerTest, allocation) {
43  HeapWalker heap_walker(heap_);
44  ASSERT_TRUE(heap_walker.Allocation(3, 4));
45  ASSERT_TRUE(heap_walker.Allocation(2, 3));
46  ASSERT_TRUE(heap_walker.Allocation(4, 5));
47  ASSERT_TRUE(heap_walker.Allocation(6, 7));
48  ASSERT_TRUE(heap_walker.Allocation(0, 1));
49}
50
51TEST_F(HeapWalkerTest, overlap) {
52  HeapWalker heap_walker(heap_);
53  ASSERT_TRUE(heap_walker.Allocation(2, 3));
54  ASSERT_TRUE(heap_walker.Allocation(3, 4));
55  ASSERT_FALSE(heap_walker.Allocation(2, 3));
56  ASSERT_FALSE(heap_walker.Allocation(1, 3));
57  ASSERT_FALSE(heap_walker.Allocation(1, 4));
58  ASSERT_FALSE(heap_walker.Allocation(1, 5));
59  ASSERT_FALSE(heap_walker.Allocation(3, 4));
60  ASSERT_FALSE(heap_walker.Allocation(3, 5));
61  ASSERT_TRUE(heap_walker.Allocation(4, 5));
62  ASSERT_TRUE(heap_walker.Allocation(1, 2));
63}
64
65TEST_F(HeapWalkerTest, zero) {
66  HeapWalker heap_walker(heap_);
67  ASSERT_TRUE(heap_walker.Allocation(2, 2));
68  ASSERT_FALSE(heap_walker.Allocation(2, 2));
69  ASSERT_TRUE(heap_walker.Allocation(3, 3));
70  ASSERT_TRUE(heap_walker.Allocation(1, 1));
71  ASSERT_FALSE(heap_walker.Allocation(2, 3));
72}
73
74#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(buffer)
75#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(buffer) + sizeof(buffer))
76
77TEST_F(HeapWalkerTest, leak) {
78  void* buffer1[16]{};
79  char buffer2[16]{};
80  buffer1[0] = &buffer2[0] - sizeof(void*);
81  buffer1[1] = &buffer2[15] + sizeof(void*);
82
83  HeapWalker heap_walker(heap_);
84  heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
85
86  ASSERT_EQ(true, heap_walker.DetectLeaks());
87
88  allocator::vector<Range> leaked(heap_);
89  size_t num_leaks = 0;
90  size_t leaked_bytes = 0;
91  ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
92
93  EXPECT_EQ(1U, num_leaks);
94  EXPECT_EQ(16U, leaked_bytes);
95  ASSERT_EQ(1U, leaked.size());
96  EXPECT_EQ(buffer_begin(buffer2), leaked[0].begin);
97  EXPECT_EQ(buffer_end(buffer2), leaked[0].end);
98}
99
100TEST_F(HeapWalkerTest, live) {
101  const int from_buffer_entries = 4;
102  const int to_buffer_bytes = 16;
103
104  for (int i = 0; i < from_buffer_entries; i++) {
105    for (int j = 0; j < to_buffer_bytes; j++) {
106      void* buffer1[from_buffer_entries]{};
107      char buffer2[to_buffer_bytes]{};
108      buffer1[i] = &buffer2[j];
109
110      HeapWalker heap_walker(heap_);
111      heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
112      heap_walker.Root(buffer_begin(buffer1), buffer_end(buffer1));
113
114      ASSERT_EQ(true, heap_walker.DetectLeaks());
115
116      allocator::vector<Range> leaked(heap_);
117      size_t num_leaks = SIZE_MAX;
118      size_t leaked_bytes = SIZE_MAX;
119      ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
120
121      EXPECT_EQ(0U, num_leaks);
122      EXPECT_EQ(0U, leaked_bytes);
123      EXPECT_EQ(0U, leaked.size());
124    }
125  }
126}
127
128TEST_F(HeapWalkerTest, unaligned) {
129  const int from_buffer_entries = 4;
130  const int to_buffer_bytes = 16;
131  void* buffer1[from_buffer_entries]{};
132  char buffer2[to_buffer_bytes]{};
133
134  buffer1[1] = &buffer2;
135
136  for (unsigned int i = 0; i < sizeof(uintptr_t); i++) {
137    for (unsigned int j = 0; j < sizeof(uintptr_t); j++) {
138      HeapWalker heap_walker(heap_);
139      heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
140      heap_walker.Root(buffer_begin(buffer1) + i, buffer_end(buffer1) - j);
141
142      ASSERT_EQ(true, heap_walker.DetectLeaks());
143
144      allocator::vector<Range> leaked(heap_);
145      size_t num_leaks = SIZE_MAX;
146      size_t leaked_bytes = SIZE_MAX;
147      ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
148
149      EXPECT_EQ(0U, num_leaks);
150      EXPECT_EQ(0U, leaked_bytes);
151      EXPECT_EQ(0U, leaked.size());
152    }
153  }
154}
155
156TEST_F(HeapWalkerTest, cycle) {
157  void* buffer1;
158  void* buffer2;
159
160  buffer1 = &buffer2;
161  buffer2 = &buffer1;
162
163  HeapWalker heap_walker(heap_);
164  heap_walker.Allocation(buffer_begin(buffer1), buffer_end(buffer1));
165  heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2));
166
167  ASSERT_EQ(true, heap_walker.DetectLeaks());
168
169  allocator::vector<Range> leaked(heap_);
170  size_t num_leaks = 0;
171  size_t leaked_bytes = 0;
172  ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
173
174  EXPECT_EQ(2U, num_leaks);
175  EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
176  ASSERT_EQ(2U, leaked.size());
177}
178
179TEST_F(HeapWalkerTest, segv) {
180  const size_t page_size = sysconf(_SC_PAGE_SIZE);
181  void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
182  ASSERT_NE(buffer1, nullptr);
183  void* buffer2;
184
185  buffer2 = &buffer1;
186
187  HeapWalker heap_walker(heap_);
188  heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1)+page_size);
189  heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
190
191  ASSERT_EQ(true, heap_walker.DetectLeaks());
192
193  allocator::vector<Range> leaked(heap_);
194  size_t num_leaks = 0;
195  size_t leaked_bytes = 0;
196  ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
197
198  EXPECT_EQ(0U, num_leaks);
199  EXPECT_EQ(0U, leaked_bytes);
200  ASSERT_EQ(0U, leaked.size());
201}
202