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 "../linker_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 dummy_str[5];
46 };
47 
48 struct test_struct_large {
49   char dummy_str[1009];
50 };
51 
52 struct test_struct_huge {
53   char dummy_str[73939];
54 };
55 
56 struct test_struct_512 {
57   char dummy_str[503];
58 };
59 
60 };
61 
62 static size_t kPageSize = sysconf(_SC_PAGE_SIZE);
63 
TEST(linker_memory,test_alloc_0)64 TEST(linker_memory, test_alloc_0) {
65   LinkerMemoryAllocator allocator;
66   void* ptr = allocator.alloc(0);
67   ASSERT_TRUE(ptr != nullptr);
68   allocator.free(ptr);
69 }
70 
TEST(linker_memory,test_free_nullptr)71 TEST(linker_memory, test_free_nullptr) {
72   LinkerMemoryAllocator allocator;
73   allocator.free(nullptr);
74 }
75 
TEST(linker_memory,test_realloc)76 TEST(linker_memory, test_realloc) {
77   LinkerMemoryAllocator 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(linker_memory,test_small_smoke)130 TEST(linker_memory, test_small_smoke) {
131   LinkerMemoryAllocator 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(linker_memory,test_huge_smoke)153 TEST(linker_memory, test_huge_smoke) {
154   LinkerMemoryAllocator 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(linker_memory,test_large)173 TEST(linker_memory, test_large) {
174   LinkerMemoryAllocator 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 
215 
216