1/*
2 * Copyright (C) 2013 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 <stdlib.h>
18#include <string.h>
19#include <sys/mman.h>
20
21#include <gtest/gtest.h>
22
23#include "../linker_allocator.h"
24
25#include <unistd.h>
26
27namespace {
28
29/*
30 * this one has size below allocator cap which is 2*sizeof(void*)
31 */
32struct test_struct_small {
33  char dummy_str[5];
34};
35
36struct test_struct_large {
37  char dummy_str[1009];
38};
39
40struct test_struct_huge {
41  char dummy_str[73939];
42};
43
44struct test_struct_512 {
45  char dummy_str[503];
46};
47
48};
49
50static size_t kPageSize = sysconf(_SC_PAGE_SIZE);
51
52TEST(linker_memory, test_alloc_0) {
53  LinkerMemoryAllocator allocator;
54  void* ptr = allocator.alloc(0);
55  ASSERT_TRUE(ptr != nullptr);
56  allocator.free(ptr);
57}
58
59TEST(linker_memory, test_free_nullptr) {
60  LinkerMemoryAllocator allocator;
61  allocator.free(nullptr);
62}
63
64TEST(linker_memory, test_realloc) {
65  LinkerMemoryAllocator allocator;
66  uint32_t* array = reinterpret_cast<uint32_t*>(allocator.alloc(512));
67  const size_t array_size = 512 / sizeof(uint32_t);
68
69  uint32_t model[1000];
70
71  model[0] = 1;
72  model[1] = 1;
73
74  for (size_t i = 2; i < 1000; ++i) {
75    model[i] = model[i - 1] + model[i - 2];
76  }
77
78  memcpy(array, model, array_size);
79
80  uint32_t* reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 1024));
81
82  ASSERT_TRUE(reallocated_ptr != nullptr);
83  ASSERT_TRUE(reallocated_ptr != array);
84
85  ASSERT_TRUE(memcmp(reallocated_ptr, model, array_size) == 0);
86
87  array = reallocated_ptr;
88
89  memcpy(array, model, 2*array_size);
90
91  reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 62));
92
93  ASSERT_TRUE(reallocated_ptr == array);
94
95  reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 4000));
96
97  ASSERT_TRUE(reallocated_ptr != nullptr);
98  ASSERT_TRUE(reallocated_ptr != array);
99  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(reallocated_ptr) % 16);
100
101  ASSERT_TRUE(memcmp(reallocated_ptr, model, array_size * 2) == 0);
102
103  array = reallocated_ptr;
104
105  memcpy(array, model, 4000);
106
107  reallocated_ptr = reinterpret_cast<uint32_t*>(allocator.realloc(array, 64000));
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, 4000) == 0);
114
115  ASSERT_EQ(nullptr, allocator.realloc(reallocated_ptr, 0));
116}
117
118TEST(linker_memory, test_small_smoke) {
119  LinkerMemoryAllocator allocator;
120
121  uint8_t zeros[16];
122  memset(zeros, 0, sizeof(zeros));
123
124  test_struct_small* ptr1 =
125      reinterpret_cast<test_struct_small*>(allocator.alloc(sizeof(test_struct_small)));
126  test_struct_small* ptr2 =
127      reinterpret_cast<test_struct_small*>(allocator.alloc(sizeof(test_struct_small)));
128
129  ASSERT_TRUE(ptr1 != nullptr);
130  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr1) % 16);
131  ASSERT_TRUE(ptr2 != nullptr);
132  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr2) % 16);
133
134  ASSERT_EQ(reinterpret_cast<uintptr_t>(ptr1)+16, reinterpret_cast<uintptr_t>(ptr2));
135  ASSERT_TRUE(memcmp(ptr1, zeros, 16) == 0);
136
137  allocator.free(ptr1);
138  allocator.free(ptr2);
139}
140
141TEST(linker_memory, test_huge_smoke) {
142  LinkerMemoryAllocator allocator;
143
144  // this should trigger proxy-to-mmap
145  test_struct_huge* ptr1 =
146      reinterpret_cast<test_struct_huge*>(allocator.alloc(sizeof(test_struct_huge)));
147  test_struct_huge* ptr2 =
148      reinterpret_cast<test_struct_huge*>(allocator.alloc(sizeof(test_struct_huge)));
149
150  ASSERT_TRUE(ptr1 != nullptr);
151  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr1) % 16);
152  ASSERT_TRUE(ptr2 != nullptr);
153  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr2) % 16);
154
155  ASSERT_TRUE(
156      reinterpret_cast<uintptr_t>(ptr1)/kPageSize != reinterpret_cast<uintptr_t>(ptr2)/kPageSize);
157  allocator.free(ptr2);
158  allocator.free(ptr1);
159}
160
161TEST(linker_memory, test_large) {
162  LinkerMemoryAllocator allocator;
163
164  test_struct_large* ptr1 =
165      reinterpret_cast<test_struct_large*>(allocator.alloc(sizeof(test_struct_large)));
166  test_struct_large* ptr2 =
167      reinterpret_cast<test_struct_large*>(allocator.alloc(1024));
168
169  ASSERT_TRUE(ptr1 != nullptr);
170  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr1) % 16);
171  ASSERT_TRUE(ptr2 != nullptr);
172  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr2) % 16);
173
174  ASSERT_EQ(reinterpret_cast<uintptr_t>(ptr1) + 1024, reinterpret_cast<uintptr_t>(ptr2));
175
176  // let's allocate until we reach the next page.
177  size_t n = kPageSize / sizeof(test_struct_large) + 1 - 2;
178  test_struct_large* objects[n];
179
180  for (size_t i = 0; i < n; ++i) {
181    test_struct_large* obj_ptr =
182        reinterpret_cast<test_struct_large*>(allocator.alloc(sizeof(test_struct_large)));
183    ASSERT_TRUE(obj_ptr != nullptr);
184    objects[i] = obj_ptr;
185  }
186
187  test_struct_large* ptr_to_free =
188      reinterpret_cast<test_struct_large*>(allocator.alloc(sizeof(test_struct_large)));
189
190  ASSERT_TRUE(ptr_to_free != nullptr);
191  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr_to_free) % 16);
192
193  allocator.free(ptr1);
194
195  for (size_t i=0; i<n; ++i) {
196    allocator.free(objects[i]);
197  }
198
199  allocator.free(ptr2);
200  allocator.free(ptr_to_free);
201}
202
203
204