1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/mman.h>
32
33 #include <gtest/gtest.h>
34
35 #include "private/bionic_allocator.h"
36
37 #include <unistd.h>
38
39 namespace {
40
41 /*
42 * this one has size below allocator cap which is 2*sizeof(void*)
43 */
44 struct test_struct_small {
45 char str[5];
46 };
47
48 struct test_struct_large {
49 char str[1009];
50 };
51
52 struct test_struct_huge {
53 char str[73939];
54 };
55
56 struct test_struct_512 {
57 char str[503];
58 };
59
60 };
61
62 static size_t kPageSize = sysconf(_SC_PAGE_SIZE);
63
TEST(bionic_allocator,test_alloc_0)64 TEST(bionic_allocator, test_alloc_0) {
65 BionicAllocator allocator;
66 void* ptr = allocator.alloc(0);
67 ASSERT_TRUE(ptr != nullptr);
68 allocator.free(ptr);
69 }
70
TEST(bionic_allocator,test_free_nullptr)71 TEST(bionic_allocator, test_free_nullptr) {
72 BionicAllocator allocator;
73 allocator.free(nullptr);
74 }
75
TEST(bionic_allocator,test_realloc)76 TEST(bionic_allocator, test_realloc) {
77 BionicAllocator allocator;
78 uint32_t* array = reinterpret_cast<uint32_t*>(allocator.alloc(512));
79 const size_t array_size = 512 / sizeof(uint32_t);
80
81 uint32_t model[1000];
82
83 model[0] = 1;
84 model[1] = 1;
85
86 for (size_t i = 2; i < 1000; ++i) {
87 model[i] = model[i - 1] + model[i - 2];
88 }
89
90 memcpy(array, model, array_size);
91
92 uint32_t* reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 1024));
93
94 ASSERT_TRUE(reallocated_ptr != nullptr);
95 ASSERT_TRUE(reallocated_ptr != array);
96
97 ASSERT_TRUE(memcmp(reallocated_ptr, model, array_size) == 0);
98
99 array = reallocated_ptr;
100
101 memcpy(array, model, 2*array_size);
102
103 reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 62));
104
105 ASSERT_TRUE(reallocated_ptr == array);
106
107 reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 4000));
108
109 ASSERT_TRUE(reallocated_ptr != nullptr);
110 ASSERT_TRUE(reallocated_ptr != array);
111 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(reallocated_ptr) % 16);
112
113 ASSERT_TRUE(memcmp(reallocated_ptr, model, array_size * 2) == 0);
114
115 array = reallocated_ptr;
116
117 memcpy(array, model, 4000);
118
119 reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 64000));
120
121 ASSERT_TRUE(reallocated_ptr != nullptr);
122 ASSERT_TRUE(reallocated_ptr != array);
123 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(reallocated_ptr) % 16);
124
125 ASSERT_TRUE(memcmp(reallocated_ptr, model, 4000) == 0);
126
127 ASSERT_EQ(nullptr, allocator.realloc(reallocated_ptr, 0));
128 }
129
TEST(bionic_allocator,test_small_smoke)130 TEST(bionic_allocator, test_small_smoke) {
131 BionicAllocator allocator;
132
133 uint8_t zeros[16];
134 memset(zeros, 0, sizeof(zeros));
135
136 test_struct_small* ptr1 =
137 reinterpret_cast<test_struct_small*>(allocator.alloc(sizeof(test_struct_small)));
138 test_struct_small* ptr2 =
139 reinterpret_cast<test_struct_small*>(allocator.alloc(sizeof(test_struct_small)));
140
141 ASSERT_TRUE(ptr1 != nullptr);
142 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr1) % 16);
143 ASSERT_TRUE(ptr2 != nullptr);
144 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr2) % 16);
145
146 ASSERT_EQ(reinterpret_cast<uintptr_t>(ptr1)+16, reinterpret_cast<uintptr_t>(ptr2));
147 ASSERT_TRUE(memcmp(ptr1, zeros, 16) == 0);
148
149 allocator.free(ptr1);
150 allocator.free(ptr2);
151 }
152
TEST(bionic_allocator,test_huge_smoke)153 TEST(bionic_allocator, test_huge_smoke) {
154 BionicAllocator allocator;
155
156 // this should trigger proxy-to-mmap
157 test_struct_huge* ptr1 =
158 reinterpret_cast<test_struct_huge*>(allocator.alloc(sizeof(test_struct_huge)));
159 test_struct_huge* ptr2 =
160 reinterpret_cast<test_struct_huge*>(allocator.alloc(sizeof(test_struct_huge)));
161
162 ASSERT_TRUE(ptr1 != nullptr);
163 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr1) % 16);
164 ASSERT_TRUE(ptr2 != nullptr);
165 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr2) % 16);
166
167 ASSERT_TRUE(
168 reinterpret_cast<uintptr_t>(ptr1)/kPageSize != reinterpret_cast<uintptr_t>(ptr2)/kPageSize);
169 allocator.free(ptr2);
170 allocator.free(ptr1);
171 }
172
TEST(bionic_allocator,test_large)173 TEST(bionic_allocator, test_large) {
174 BionicAllocator allocator;
175
176 test_struct_large* ptr1 =
177 reinterpret_cast<test_struct_large*>(allocator.alloc(sizeof(test_struct_large)));
178 test_struct_large* ptr2 =
179 reinterpret_cast<test_struct_large*>(allocator.alloc(1024));
180
181 ASSERT_TRUE(ptr1 != nullptr);
182 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr1) % 16);
183 ASSERT_TRUE(ptr2 != nullptr);
184 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr2) % 16);
185
186 ASSERT_EQ(reinterpret_cast<uintptr_t>(ptr1) + 1024, reinterpret_cast<uintptr_t>(ptr2));
187
188 // let's allocate until we reach the next page.
189 size_t n = kPageSize / sizeof(test_struct_large) + 1 - 2;
190 test_struct_large* objects[n];
191
192 for (size_t i = 0; i < n; ++i) {
193 test_struct_large* obj_ptr =
194 reinterpret_cast<test_struct_large*>(allocator.alloc(sizeof(test_struct_large)));
195 ASSERT_TRUE(obj_ptr != nullptr);
196 objects[i] = obj_ptr;
197 }
198
199 test_struct_large* ptr_to_free =
200 reinterpret_cast<test_struct_large*>(allocator.alloc(sizeof(test_struct_large)));
201
202 ASSERT_TRUE(ptr_to_free != nullptr);
203 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr_to_free) % 16);
204
205 allocator.free(ptr1);
206
207 for (size_t i=0; i<n; ++i) {
208 allocator.free(objects[i]);
209 }
210
211 allocator.free(ptr2);
212 allocator.free(ptr_to_free);
213 }
214
TEST(bionic_allocator,test_memalign_small)215 TEST(bionic_allocator, test_memalign_small) {
216 BionicAllocator allocator;
217 void* ptr;
218
219 // simple case
220 ptr = allocator.memalign(0x100, 0x100);
221 ASSERT_TRUE(ptr != nullptr);
222 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % 0x100);
223 allocator.free(ptr);
224
225 // small objects are automatically aligned to their size.
226 ptr = allocator.alloc(0x200);
227 ASSERT_TRUE(ptr != nullptr);
228 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % 0x200);
229 allocator.free(ptr);
230
231 // the size (0x10) is bumped up to the alignment (0x100)
232 ptr = allocator.memalign(0x100, 0x10);
233 ASSERT_TRUE(ptr != nullptr);
234 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % 0x100);
235 allocator.free(ptr);
236 }
237
TEST(bionic_allocator,test_memalign_large)238 TEST(bionic_allocator, test_memalign_large) {
239 BionicAllocator allocator;
240 void* ptr;
241 size_t alignment;
242
243 // a large object with alignment < kPageSize
244 alignment = kPageSize >> 1;
245 ptr = allocator.memalign(alignment, 0x2000);
246 ASSERT_TRUE(ptr != nullptr);
247 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % alignment);
248 allocator.free(ptr);
249
250 // a large object with alignment == kPageSize
251 alignment = kPageSize;
252 ptr = allocator.memalign(alignment, 0x2000);
253 ASSERT_TRUE(ptr != nullptr);
254 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % alignment);
255 allocator.free(ptr);
256
257 // A large object with alignment > kPageSize is only guaranteed to have page
258 // alignment.
259 alignment = kPageSize << 1;
260 ptr = allocator.memalign(alignment, 0x4000);
261 ASSERT_TRUE(ptr != nullptr);
262 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % kPageSize);
263 allocator.free(ptr);
264 }
265