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