blob: 297f637c6aef5d495c13afe091c43710e3df3ed9 [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
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -070017#include <gtest/gtest.h>
18
19#if defined(__BIONIC__)
20
Christopher Ferris8ea85af2019-08-16 11:07:50 -070021#include <inttypes.h>
22#include <stdint.h>
23#include <stdlib.h>
24#include <time.h>
25#include <unistd.h>
26
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -070027#include <vector>
28
Florian Mayer750dcd32022-04-15 15:54:47 -070029#include <android-base/test_utils.h>
Christopher Ferris8ea85af2019-08-16 11:07:50 -070030#include <async_safe/log.h>
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -070031#include <procinfo/process_map.h>
32
Evgenii Stepanovacd6f4f2018-11-06 16:48:27 -080033#include "utils.h"
34
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -070035extern "C" void malloc_disable();
36extern "C" void malloc_enable();
37extern "C" int malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base,
38 size_t size, void* arg), void* arg);
39
40struct AllocDataType {
41 void* ptr;
42 size_t size;
43 size_t size_reported;
44 size_t count;
45};
46
47struct TestDataType {
48 size_t total_allocated_bytes;
49 std::vector<AllocDataType> allocs;
50};
51
52static void AllocPtr(TestDataType* test_data, size_t size) {
53 test_data->allocs.resize(test_data->allocs.size() + 1);
54 AllocDataType* alloc = &test_data->allocs.back();
55 void* ptr = malloc(size);
56 ASSERT_TRUE(ptr != nullptr);
57 alloc->ptr = ptr;
58 alloc->size = malloc_usable_size(ptr);
59 alloc->size_reported = 0;
60 alloc->count = 0;
61}
62
63static void FreePtrs(TestDataType* test_data) {
64 for (size_t i = 0; i < test_data->allocs.size(); i++) {
65 free(test_data->allocs[i].ptr);
66 }
67}
68
69static void SavePointers(uintptr_t base, size_t size, void* data) {
70 TestDataType* test_data = reinterpret_cast<TestDataType*>(data);
71
72 test_data->total_allocated_bytes += size;
73
74 uintptr_t end;
75 if (__builtin_add_overflow(base, size, &end)) {
76 // Skip this entry.
77 return;
78 }
79
80 for (size_t i = 0; i < test_data->allocs.size(); i++) {
81 uintptr_t ptr = reinterpret_cast<uintptr_t>(test_data->allocs[i].ptr);
82 if (ptr >= base && ptr < end) {
83 test_data->allocs[i].count++;
84
85 uintptr_t max_size = end - ptr;
86 if (max_size > test_data->allocs[i].size) {
87 test_data->allocs[i].size_reported = test_data->allocs[i].size;
88 } else {
89 test_data->allocs[i].size_reported = max_size;
90 }
91 }
92 }
93}
94
95static void VerifyPtrs(TestDataType* test_data) {
96 test_data->total_allocated_bytes = 0;
97
Christopher Ferris88b2f0d2019-10-02 12:48:23 -070098 // Find all of the maps that are from the native allocator.
Edgar Arriagad02148c2020-11-23 18:11:02 -080099 auto callback = [&](uint64_t start, uint64_t end, uint16_t, uint64_t, ino_t, const char* name,
100 bool) {
Mitch Phillips242387d2020-02-11 16:08:17 -0800101 if (strcmp(name, "[anon:libc_malloc]") == 0 || strncmp(name, "[anon:scudo:", 12) == 0 ||
102 strncmp(name, "[anon:GWP-ASan", 14) == 0) {
Christopher Ferris8ea85af2019-08-16 11:07:50 -0700103 malloc_iterate(start, end - start, SavePointers, test_data);
104 }
105 };
106
107 std::vector<char> buffer(64 * 1024);
108
109 // Avoid doing allocations so that the maps don't change while looking
110 // for the pointers.
111 malloc_disable();
112 bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer.data(),
113 buffer.size(), callback);
114 malloc_enable();
115
116 ASSERT_TRUE(parsed) << "Failed to parse /proc/self/maps";
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700117
118 for (size_t i = 0; i < test_data->allocs.size(); i++) {
119 EXPECT_EQ(1UL, test_data->allocs[i].count) << "Failed on size " << test_data->allocs[i].size;
120 if (test_data->allocs[i].count == 1) {
121 EXPECT_EQ(test_data->allocs[i].size, test_data->allocs[i].size_reported);
122 }
123 }
124}
125
126static void AllocateSizes(TestDataType* test_data, const std::vector<size_t>& sizes) {
127 static constexpr size_t kInitialAllocations = 40;
128 static constexpr size_t kNumAllocs = 50;
129 for (size_t size : sizes) {
130 // Verify that if the tcache is enabled, that tcache pointers
131 // are found by allocating and freeing 20 pointers (should be larger
132 // than the total number of cache entries).
133 for (size_t i = 0; i < kInitialAllocations; i++) {
134 void* ptr = malloc(size);
135 ASSERT_TRUE(ptr != nullptr);
136 memset(ptr, 0, size);
137 free(ptr);
138 }
139 for (size_t i = 0; i < kNumAllocs; i++) {
140 AllocPtr(test_data, size);
141 }
142 }
143}
144#endif
145
146// Verify that small allocs can be found properly.
147TEST(malloc_iterate, small_allocs) {
148#if defined(__BIONIC__)
Evgenii Stepanovacd6f4f2018-11-06 16:48:27 -0800149 SKIP_WITH_HWASAN;
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700150 TestDataType test_data;
151
152 // Try to cycle through all of the different small bins.
153 // This is specific to the implementation of jemalloc and should be
154 // adjusted if a different native memory allocator is used.
155 std::vector<size_t> sizes{8, 16, 32, 48, 64, 80, 96, 112, 128, 160,
156 192, 224, 256, 320, 384, 448, 512, 640, 768, 896,
157 1024, 1280, 1536, 1792, 2048, 2560, 3072, 3584, 4096, 5120,
158 6144, 7168, 8192, 10240, 12288, 14336, 16384, 32768, 65536};
159 AllocateSizes(&test_data, sizes);
160
161 SCOPED_TRACE("");
162 VerifyPtrs(&test_data);
163
164 FreePtrs(&test_data);
165#else
Elliott Hughesbcaa4542019-03-08 15:20:23 -0800166 GTEST_SKIP() << "bionic-only test";
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700167#endif
168}
169
170// Verify that large allocs can be found properly.
171TEST(malloc_iterate, large_allocs) {
172#if defined(__BIONIC__)
Evgenii Stepanovacd6f4f2018-11-06 16:48:27 -0800173 SKIP_WITH_HWASAN;
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700174 TestDataType test_data;
175
176 // Try some larger sizes.
177 std::vector<size_t> sizes{131072, 262144, 524288, 1048576, 2097152};
178 AllocateSizes(&test_data, sizes);
179
180 SCOPED_TRACE("");
181 VerifyPtrs(&test_data);
182
183 FreePtrs(&test_data);
184#else
Elliott Hughesbcaa4542019-03-08 15:20:23 -0800185 GTEST_SKIP() << "bionic-only test";
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700186#endif
187}
188
189// Verify that there are no crashes attempting to get pointers from
190// non-allocated pointers.
191TEST(malloc_iterate, invalid_pointers) {
192#if defined(__BIONIC__)
Evgenii Stepanovacd6f4f2018-11-06 16:48:27 -0800193 SKIP_WITH_HWASAN;
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700194 TestDataType test_data = {};
195
Christopher Ferris8ea85af2019-08-16 11:07:50 -0700196 // Only attempt to get memory data for maps that are not from the native allocator.
Edgar Arriagad02148c2020-11-23 18:11:02 -0800197 auto callback = [&](uint64_t start, uint64_t end, uint16_t, uint64_t, ino_t, const char* name,
198 bool) {
Mitch Phillips242387d2020-02-11 16:08:17 -0800199 if (strcmp(name, "[anon:libc_malloc]") != 0 && strncmp(name, "[anon:scudo:", 12) != 0 &&
200 strncmp(name, "[anon:GWP-ASan", 14) != 0) {
Christopher Ferris8ea85af2019-08-16 11:07:50 -0700201 size_t total = test_data.total_allocated_bytes;
202 malloc_iterate(start, end - start, SavePointers, &test_data);
203 total = test_data.total_allocated_bytes - total;
204 if (total > 0) {
205 char buffer[256];
206 int len = 0;
207 if (name[0] != '\0') {
208 len = async_safe_format_buffer(buffer, sizeof(buffer), "Failed on map %s: %zu\n", name,
209 total);
210 } else {
211 len = async_safe_format_buffer(buffer, sizeof(buffer),
212 "Failed on map anon:<%" PRIx64 "-%" PRIx64 ">: %zu\n",
213 start, end, total);
Sandeep Patil7d2aea02019-01-30 17:45:48 -0800214 }
Christopher Ferris8ea85af2019-08-16 11:07:50 -0700215 if (len > 0) {
216 write(STDOUT_FILENO, buffer, len);
217 }
218 }
219 }
220 };
221
222 std::vector<char> buffer(64 * 1024);
223
224 // Need to make sure that there are no allocations while reading the
225 // maps. Otherwise, it might create a new map during this check and
226 // incorrectly think a map is empty while it actually includes real
227 // allocations.
228 malloc_disable();
229 bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer.data(),
230 buffer.size(), callback);
231 malloc_enable();
232
233 ASSERT_TRUE(parsed) << "Failed to parse /proc/self/maps";
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700234
235 ASSERT_EQ(0UL, test_data.total_allocated_bytes);
236#else
Elliott Hughesbcaa4542019-03-08 15:20:23 -0800237 GTEST_SKIP() << "bionic-only test";
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700238#endif
239}
240
241TEST(malloc_iterate, malloc_disable_prevents_allocs) {
242#if defined(__BIONIC__)
Evgenii Stepanovacd6f4f2018-11-06 16:48:27 -0800243 SKIP_WITH_HWASAN;
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700244 pid_t pid;
245 if ((pid = fork()) == 0) {
246 malloc_disable();
247 void* ptr = malloc(1024);
248 if (ptr == nullptr) {
249 exit(1);
250 }
251 memset(ptr, 0, 1024);
252 exit(0);
253 }
254 ASSERT_NE(-1, pid);
255
256 // Expect that the malloc will hang forever, and that if the process
257 // does not return for two seconds, it is hung.
258 sleep(2);
259 pid_t wait_pid = TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG));
260 if (wait_pid <= 0) {
261 kill(pid, SIGKILL);
262 }
263 ASSERT_NE(-1, wait_pid) << "Unknown failure in waitpid.";
264 ASSERT_EQ(0, wait_pid) << "malloc_disable did not prevent allocation calls.";
265#else
Elliott Hughesbcaa4542019-03-08 15:20:23 -0800266 GTEST_SKIP() << "bionic-only test";
Christopher Ferrisbfd3dc42018-10-15 10:02:38 -0700267#endif
268}