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