1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /* See http://code.google.com/p/googletest/wiki/Primer */
24
25 // First include (the generated) my_config.h, to get correct platform defines.
26 #include "my_config.h"
27
28 #include <gtest/gtest.h>
29
30 #include "univ.i"
31
32 #include "ut0new.h"
33
34 namespace innodb_ut0new_unittest {
35
36 class C {
37 public:
C(int x=42)38 C(int x = 42)
39 :
40 m_x(x)
41 {
42 }
43
44 int m_x;
45 };
46
47 static
48 void
start()49 start()
50 {
51 static bool ut_new_boot_called = false;
52
53 if (!ut_new_boot_called) {
54 ut_new_boot();
55 ut_new_boot_called = true;
56 }
57 }
58
59 /* test UT_NEW*() */
TEST(ut0new,utnew)60 TEST(ut0new, utnew)
61 {
62 start();
63
64 C* p;
65
66 p = UT_NEW_NOKEY(C(12));
67 EXPECT_EQ(12, p->m_x);
68 UT_DELETE(p);
69
70 p = UT_NEW(C(34), mem_key_buf_buf_pool);
71 EXPECT_EQ(34, p->m_x);
72 UT_DELETE(p);
73
74 p = UT_NEW_ARRAY_NOKEY(C, 5);
75 EXPECT_EQ(42, p[0].m_x);
76 EXPECT_EQ(42, p[1].m_x);
77 EXPECT_EQ(42, p[2].m_x);
78 EXPECT_EQ(42, p[3].m_x);
79 EXPECT_EQ(42, p[4].m_x);
80 UT_DELETE_ARRAY(p);
81
82 p = UT_NEW_ARRAY(C, 5, mem_key_buf_buf_pool);
83 EXPECT_EQ(42, p[0].m_x);
84 EXPECT_EQ(42, p[1].m_x);
85 EXPECT_EQ(42, p[2].m_x);
86 EXPECT_EQ(42, p[3].m_x);
87 EXPECT_EQ(42, p[4].m_x);
88 UT_DELETE_ARRAY(p);
89 }
90
91 /* test ut_*alloc*() */
TEST(ut0new,utmalloc)92 TEST(ut0new, utmalloc)
93 {
94 start();
95
96 int* p;
97
98 p = static_cast<int*>(ut_malloc_nokey(sizeof(int)));
99 *p = 12;
100 ut_free(p);
101
102 p = static_cast<int*>(ut_malloc(sizeof(int), mem_key_buf_buf_pool));
103 *p = 34;
104 ut_free(p);
105
106 p = static_cast<int*>(ut_zalloc_nokey(sizeof(int)));
107 EXPECT_EQ(0, *p);
108 *p = 56;
109 ut_free(p);
110
111 p = static_cast<int*>(ut_zalloc(sizeof(int), mem_key_buf_buf_pool));
112 EXPECT_EQ(0, *p);
113 *p = 78;
114 ut_free(p);
115
116 p = static_cast<int*>(ut_malloc_nokey(sizeof(int)));
117 *p = 90;
118 p = static_cast<int*>(ut_realloc(p, 2 * sizeof(int)));
119 EXPECT_EQ(90, p[0]);
120 p[1] = 91;
121 ut_free(p);
122 }
123
124 /* test ut_allocator() */
TEST(ut0new,utallocator)125 TEST(ut0new, utallocator)
126 {
127 start();
128
129 typedef int basic_t;
130 typedef ut_allocator<basic_t> vec_allocator_t;
131 typedef std::vector<basic_t, vec_allocator_t> vec_t;
132
133 vec_t v1;
134 v1.push_back(21);
135 v1.push_back(31);
136 v1.push_back(41);
137 EXPECT_EQ(21, v1[0]);
138 EXPECT_EQ(31, v1[1]);
139 EXPECT_EQ(41, v1[2]);
140
141 /* We use "new" instead of "UT_NEW()" for simplicity here. Real InnoDB
142 code should use UT_NEW(). */
143
144 /* This could of course be written as:
145 std::vector<int, ut_allocator<int> >* v2
146 = new std::vector<int, ut_allocator<int> >(ut_allocator<int>(
147 mem_key_buf_buf_pool)); */
148 vec_t* v2 = new vec_t(vec_allocator_t(mem_key_buf_buf_pool));
149 v2->push_back(27);
150 v2->push_back(37);
151 v2->push_back(47);
152 EXPECT_EQ(27, v2->at(0));
153 EXPECT_EQ(37, v2->at(1));
154 EXPECT_EQ(47, v2->at(2));
155 delete v2;
156 }
157
158 static int n_construct = 0;
159
160 class cc_t {
161 public:
cc_t()162 cc_t()
163 {
164 n_construct++;
165 if (n_construct % 4 == 0) {
166 throw(1);
167 }
168 }
169 };
170
171 struct big_t {
172 char x[128];
173 };
174
175 /* test edge cases */
TEST(ut0new,edgecases)176 TEST(ut0new, edgecases)
177 {
178 ut_allocator<byte> alloc1(mem_key_buf_buf_pool);
179 ut_new_pfx_t pfx;
180 void* ret;
181 const void* null_ptr= NULL;
182
183 ret = alloc1.allocate_large(0, &pfx, false);
184 EXPECT_EQ(null_ptr, ret);
185
186 #ifdef UNIV_PFS_MEMORY
187 ret = alloc1.allocate(16);
188 ASSERT_TRUE(ret != NULL);
189 ret = alloc1.reallocate(ret, 0, __FILE__);
190 EXPECT_EQ(null_ptr, ret);
191
192 ret = UT_NEW_ARRAY_NOKEY(byte, 0);
193 EXPECT_EQ(null_ptr, ret);
194 #endif /* UNIV_PFS_MEMORY */
195
196 ut_allocator<big_t> alloc2(mem_key_buf_buf_pool);
197
198 const ut_allocator<big_t>::size_type too_many_elements
199 = std::numeric_limits<ut_allocator<big_t>::size_type>::max()
200 / sizeof(big_t) + 1;
201
202 #ifdef UNIV_PFS_MEMORY
203 ret = alloc2.allocate(16);
204 ASSERT_TRUE(ret != NULL);
205 void *ret2 = alloc2.reallocate(ret, too_many_elements, __FILE__);
206 EXPECT_EQ(null_ptr, ret2);
207 /* If reallocate fails due to too many elements,
208 memory is still allocated. Do explicit deallocate do avoid mem leak. */
209 alloc2.deallocate(static_cast<big_t*>(ret));
210 #endif /* UNIV_PFS_MEMORY */
211
212 bool threw = false;
213
214 try {
215 ret = alloc2.allocate(too_many_elements);
216 } catch (...) {
217 threw = true;
218 }
219 EXPECT_TRUE(threw);
220
221 ret = alloc2.allocate(too_many_elements, NULL, NULL, false, false);
222 EXPECT_EQ(null_ptr, ret);
223
224 threw = false;
225 try {
226 cc_t* cc = UT_NEW_ARRAY_NOKEY(cc_t, 16);
227 /* Not reached, but silence a compiler warning
228 about unused 'cc': */
229 ASSERT_TRUE(cc != NULL);
230 } catch (...) {
231 threw = true;
232 }
233 EXPECT_TRUE(threw);
234 }
235
236 }
237