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 <fcntl.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/prctl.h>
21
22 #include <gtest/gtest.h>
23
24 #include <memunreachable/memunreachable.h>
25
26 void* ptr;
27
28 class HiddenPointer {
29 public:
HiddenPointer(size_t size=256)30 HiddenPointer(size_t size = 256) {
31 Set(malloc(size));
32 }
~HiddenPointer()33 ~HiddenPointer() {
34 Free();
35 }
Get()36 void* Get() {
37 return reinterpret_cast<void*>(~ptr_);
38 }
Free()39 void Free() {
40 free(Get());
41 Set(nullptr);
42 }
43 private:
Set(void * ptr)44 void Set(void* ptr) {
45 ptr_ = ~reinterpret_cast<uintptr_t>(ptr);
46 }
47 volatile uintptr_t ptr_;
48 };
49
Ref(void * ptr)50 static void Ref(void* ptr) {
51 write(0, ptr, 0);
52 }
53
TEST(MemunreachableTest,clean)54 TEST(MemunreachableTest, clean) {
55 UnreachableMemoryInfo info;
56
57 ASSERT_TRUE(LogUnreachableMemory(true, 100));
58
59 ASSERT_TRUE(GetUnreachableMemory(info));
60 ASSERT_EQ(0U, info.leaks.size());
61 }
62
TEST(MemunreachableTest,stack)63 TEST(MemunreachableTest, stack) {
64 HiddenPointer hidden_ptr;
65
66 {
67 void* ptr = hidden_ptr.Get();
68 Ref(ptr);
69
70 UnreachableMemoryInfo info;
71
72 ASSERT_TRUE(GetUnreachableMemory(info));
73 ASSERT_EQ(0U, info.leaks.size());
74
75 Ref(ptr);
76 }
77
78 {
79 UnreachableMemoryInfo info;
80
81 ASSERT_TRUE(GetUnreachableMemory(info));
82 ASSERT_EQ(1U, info.leaks.size());
83 }
84
85 hidden_ptr.Free();
86
87 {
88 UnreachableMemoryInfo info;
89
90 ASSERT_TRUE(GetUnreachableMemory(info));
91 ASSERT_EQ(0U, info.leaks.size());
92 }
93 }
94
TEST(MemunreachableTest,global)95 TEST(MemunreachableTest, global) {
96 HiddenPointer hidden_ptr;
97
98 ptr = hidden_ptr.Get();
99
100 {
101 UnreachableMemoryInfo info;
102
103 ASSERT_TRUE(GetUnreachableMemory(info));
104 ASSERT_EQ(0U, info.leaks.size());
105 }
106
107 ptr = NULL;
108
109 {
110 UnreachableMemoryInfo info;
111
112 ASSERT_TRUE(GetUnreachableMemory(info));
113 ASSERT_EQ(1U, info.leaks.size());
114 }
115
116 hidden_ptr.Free();
117
118 {
119 UnreachableMemoryInfo info;
120
121 ASSERT_TRUE(GetUnreachableMemory(info));
122 ASSERT_EQ(0U, info.leaks.size());
123 }
124 }
125
TEST(MemunreachableTest,tls)126 TEST(MemunreachableTest, tls) {
127 HiddenPointer hidden_ptr;
128 pthread_key_t key;
129 pthread_key_create(&key, NULL);
130
131 pthread_setspecific(key, hidden_ptr.Get());
132
133 {
134 UnreachableMemoryInfo info;
135
136 ASSERT_TRUE(GetUnreachableMemory(info));
137 ASSERT_EQ(0U, info.leaks.size());
138 }
139
140 pthread_setspecific(key, nullptr);
141
142 {
143 UnreachableMemoryInfo info;
144
145 ASSERT_TRUE(GetUnreachableMemory(info));
146 ASSERT_EQ(1U, info.leaks.size());
147 }
148
149 hidden_ptr.Free();
150
151 {
152 UnreachableMemoryInfo info;
153
154 ASSERT_TRUE(GetUnreachableMemory(info));
155 ASSERT_EQ(0U, info.leaks.size());
156 }
157
158 pthread_key_delete(key);
159 }
160
TEST(MemunreachableTest,twice)161 TEST(MemunreachableTest, twice) {
162 HiddenPointer hidden_ptr;
163
164 {
165 UnreachableMemoryInfo info;
166
167 ASSERT_TRUE(GetUnreachableMemory(info));
168 ASSERT_EQ(1U, info.leaks.size());
169 }
170
171 {
172 UnreachableMemoryInfo info;
173
174 ASSERT_TRUE(GetUnreachableMemory(info));
175 ASSERT_EQ(1U, info.leaks.size());
176 }
177
178 hidden_ptr.Free();
179
180 {
181 UnreachableMemoryInfo info;
182
183 ASSERT_TRUE(GetUnreachableMemory(info));
184 ASSERT_EQ(0U, info.leaks.size());
185 }
186 }
187
TEST(MemunreachableTest,log)188 TEST(MemunreachableTest, log) {
189 HiddenPointer hidden_ptr;
190
191 ASSERT_TRUE(LogUnreachableMemory(true, 100));
192
193 hidden_ptr.Free();
194
195 {
196 UnreachableMemoryInfo info;
197
198 ASSERT_TRUE(GetUnreachableMemory(info));
199 ASSERT_EQ(0U, info.leaks.size());
200 }
201 }
202
TEST(MemunreachableTest,notdumpable)203 TEST(MemunreachableTest, notdumpable) {
204 ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 0));
205
206 HiddenPointer hidden_ptr;
207
208 ASSERT_TRUE(LogUnreachableMemory(true, 100));
209
210 ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 1));
211 }
212
TEST(MemunreachableTest,leak_lots)213 TEST(MemunreachableTest, leak_lots) {
214 std::vector<HiddenPointer> hidden_ptrs;
215 hidden_ptrs.resize(1024);
216
217 ASSERT_TRUE(LogUnreachableMemory(true, 100));
218 }
219