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: 30 HiddenPointer(size_t size = 256) { 31 Set(malloc(size)); 32 } 33 ~HiddenPointer() { 34 Free(); 35 } 36 void* Get() { 37 return reinterpret_cast<void*>(~ptr_); 38 } 39 void Free() { 40 free(Get()); 41 Set(nullptr); 42 } 43 private: 44 void Set(void* ptr) { 45 ptr_ = ~reinterpret_cast<uintptr_t>(ptr); 46 } 47 volatile uintptr_t ptr_; 48 }; 49 50 static void Ref(void* ptr) { 51 write(0, ptr, 0); 52 } 53 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 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 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 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 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 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 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 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