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