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