1 /* 2 * Copyright (C) 2018 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 <stdint.h> 18 #include <stdlib.h> 19 #include <time.h> 20 21 #include <gtest/gtest.h> 22 23 #if defined(__BIONIC__) 24 25 #include <vector> 26 27 #include <procinfo/process_map.h> 28 29 #include "utils.h" 30 31 extern "C" void malloc_disable(); 32 extern "C" void malloc_enable(); 33 extern "C" int malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base, 34 size_t size, void* arg), void* arg); 35 36 struct AllocDataType { 37 void* ptr; 38 size_t size; 39 size_t size_reported; 40 size_t count; 41 }; 42 43 struct TestDataType { 44 size_t total_allocated_bytes; 45 std::vector<AllocDataType> allocs; 46 }; 47 48 static void AllocPtr(TestDataType* test_data, size_t size) { 49 test_data->allocs.resize(test_data->allocs.size() + 1); 50 AllocDataType* alloc = &test_data->allocs.back(); 51 void* ptr = malloc(size); 52 ASSERT_TRUE(ptr != nullptr); 53 alloc->ptr = ptr; 54 alloc->size = malloc_usable_size(ptr); 55 alloc->size_reported = 0; 56 alloc->count = 0; 57 } 58 59 static void FreePtrs(TestDataType* test_data) { 60 for (size_t i = 0; i < test_data->allocs.size(); i++) { 61 free(test_data->allocs[i].ptr); 62 } 63 } 64 65 static void SavePointers(uintptr_t base, size_t size, void* data) { 66 TestDataType* test_data = reinterpret_cast<TestDataType*>(data); 67 68 test_data->total_allocated_bytes += size; 69 70 uintptr_t end; 71 if (__builtin_add_overflow(base, size, &end)) { 72 // Skip this entry. 73 return; 74 } 75 76 for (size_t i = 0; i < test_data->allocs.size(); i++) { 77 uintptr_t ptr = reinterpret_cast<uintptr_t>(test_data->allocs[i].ptr); 78 if (ptr >= base && ptr < end) { 79 test_data->allocs[i].count++; 80 81 uintptr_t max_size = end - ptr; 82 if (max_size > test_data->allocs[i].size) { 83 test_data->allocs[i].size_reported = test_data->allocs[i].size; 84 } else { 85 test_data->allocs[i].size_reported = max_size; 86 } 87 } 88 } 89 } 90 91 static void VerifyPtrs(TestDataType* test_data) { 92 test_data->total_allocated_bytes = 0; 93 94 // Find all of the maps that are [anon:libc_malloc]. 95 ASSERT_TRUE(android::procinfo::ReadMapFile( 96 "/proc/self/maps", 97 [&](uint64_t start, uint64_t end, uint16_t, uint64_t, ino_t, const char* name) { 98 if (std::string(name) == "[anon:libc_malloc]") { 99 malloc_disable(); 100 malloc_iterate(start, end - start, SavePointers, test_data); 101 malloc_enable(); 102 } 103 })); 104 105 for (size_t i = 0; i < test_data->allocs.size(); i++) { 106 EXPECT_EQ(1UL, test_data->allocs[i].count) << "Failed on size " << test_data->allocs[i].size; 107 if (test_data->allocs[i].count == 1) { 108 EXPECT_EQ(test_data->allocs[i].size, test_data->allocs[i].size_reported); 109 } 110 } 111 } 112 113 static void AllocateSizes(TestDataType* test_data, const std::vector<size_t>& sizes) { 114 static constexpr size_t kInitialAllocations = 40; 115 static constexpr size_t kNumAllocs = 50; 116 for (size_t size : sizes) { 117 // Verify that if the tcache is enabled, that tcache pointers 118 // are found by allocating and freeing 20 pointers (should be larger 119 // than the total number of cache entries). 120 for (size_t i = 0; i < kInitialAllocations; i++) { 121 void* ptr = malloc(size); 122 ASSERT_TRUE(ptr != nullptr); 123 memset(ptr, 0, size); 124 free(ptr); 125 } 126 for (size_t i = 0; i < kNumAllocs; i++) { 127 AllocPtr(test_data, size); 128 } 129 } 130 } 131 #endif 132 133 // Verify that small allocs can be found properly. 134 TEST(malloc_iterate, small_allocs) { 135 #if defined(__BIONIC__) 136 SKIP_WITH_HWASAN; 137 TestDataType test_data; 138 139 // Try to cycle through all of the different small bins. 140 // This is specific to the implementation of jemalloc and should be 141 // adjusted if a different native memory allocator is used. 142 std::vector<size_t> sizes{8, 16, 32, 48, 64, 80, 96, 112, 128, 160, 143 192, 224, 256, 320, 384, 448, 512, 640, 768, 896, 144 1024, 1280, 1536, 1792, 2048, 2560, 3072, 3584, 4096, 5120, 145 6144, 7168, 8192, 10240, 12288, 14336, 16384, 32768, 65536}; 146 AllocateSizes(&test_data, sizes); 147 148 SCOPED_TRACE(""); 149 VerifyPtrs(&test_data); 150 151 FreePtrs(&test_data); 152 #else 153 GTEST_SKIP() << "bionic-only test"; 154 #endif 155 } 156 157 // Verify that large allocs can be found properly. 158 TEST(malloc_iterate, large_allocs) { 159 #if defined(__BIONIC__) 160 SKIP_WITH_HWASAN; 161 TestDataType test_data; 162 163 // Try some larger sizes. 164 std::vector<size_t> sizes{131072, 262144, 524288, 1048576, 2097152}; 165 AllocateSizes(&test_data, sizes); 166 167 SCOPED_TRACE(""); 168 VerifyPtrs(&test_data); 169 170 FreePtrs(&test_data); 171 #else 172 GTEST_SKIP() << "bionic-only test"; 173 #endif 174 } 175 176 // Verify that there are no crashes attempting to get pointers from 177 // non-allocated pointers. 178 TEST(malloc_iterate, invalid_pointers) { 179 #if defined(__BIONIC__) 180 SKIP_WITH_HWASAN; 181 TestDataType test_data = {}; 182 183 // Find all of the maps that are not [anon:libc_malloc]. 184 ASSERT_TRUE(android::procinfo::ReadMapFile( 185 "/proc/self/maps", 186 [&](uint64_t start, uint64_t end, uint16_t, uint64_t, ino_t, const char* name) { 187 if (std::string(name) != "[anon:libc_malloc]") { 188 malloc_disable(); 189 malloc_iterate(start, end - start, SavePointers, &test_data); 190 malloc_enable(); 191 } 192 })); 193 194 ASSERT_EQ(0UL, test_data.total_allocated_bytes); 195 #else 196 GTEST_SKIP() << "bionic-only test"; 197 #endif 198 } 199 200 TEST(malloc_iterate, malloc_disable_prevents_allocs) { 201 #if defined(__BIONIC__) 202 SKIP_WITH_HWASAN; 203 pid_t pid; 204 if ((pid = fork()) == 0) { 205 malloc_disable(); 206 void* ptr = malloc(1024); 207 if (ptr == nullptr) { 208 exit(1); 209 } 210 memset(ptr, 0, 1024); 211 exit(0); 212 } 213 ASSERT_NE(-1, pid); 214 215 // Expect that the malloc will hang forever, and that if the process 216 // does not return for two seconds, it is hung. 217 sleep(2); 218 pid_t wait_pid = TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); 219 if (wait_pid <= 0) { 220 kill(pid, SIGKILL); 221 } 222 ASSERT_NE(-1, wait_pid) << "Unknown failure in waitpid."; 223 ASSERT_EQ(0, wait_pid) << "malloc_disable did not prevent allocation calls."; 224 #else 225 GTEST_SKIP() << "bionic-only test"; 226 #endif 227 } 228