1 /*
2 * ProFTPD - FTP server testsuite
3 * Copyright (c) 2008-2020 The ProFTPD Project team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, The ProFTPD Project team and other respective
20 * copyright holders give permission to link this program with OpenSSL, and
21 * distribute the resulting executable, without including the source code for
22 * OpenSSL in the source distribution.
23 */
24
25 /* Pool API tests */
26
27 #include "tests.h"
28
set_up(void)29 static void set_up(void) {
30 init_pools();
31
32 if (getenv("TEST_VERBOSE") != NULL) {
33 pr_trace_set_levels("pool", 1, 20);
34 }
35 }
36
tear_down(void)37 static void tear_down(void) {
38 if (getenv("TEST_VERBOSE") != NULL) {
39 pr_trace_set_levels("pool", 0, 0);
40 }
41
42 free_pools();
43 }
44
START_TEST(pool_destroy_pool_test)45 START_TEST (pool_destroy_pool_test) {
46 pool *p, *sub_pool;
47
48 mark_point();
49 destroy_pool(NULL);
50
51 mark_point();
52 p = make_sub_pool(permanent_pool);
53 destroy_pool(p);
54
55 /* What happens if we destroy an already-destroyed pool? Answer: IFF
56 * --enable-devel was used, THEN destroying an already-destroyed pool
57 * will result in an exit(2) call from within pool.c, via the
58 * chk_on_blk_list() function. How impolite.
59 *
60 * And if --enable-devel was NOT used, on SOME systems, this test tickles
61 * other libc/malloc/free behaviors, which are unsettling.
62 *
63 * Sigh. So for now, I'll just leave this here, but commented out.
64 */
65 #if 0
66 mark_point();
67 destroy_pool(p);
68 #endif
69
70 mark_point();
71 p = make_sub_pool(permanent_pool);
72 sub_pool = make_sub_pool(p);
73 destroy_pool(p);
74
75 mark_point();
76 p = make_sub_pool(permanent_pool);
77 sub_pool = make_sub_pool(p);
78 destroy_pool(sub_pool);
79 destroy_pool(p);
80 }
81 END_TEST
82
START_TEST(pool_make_sub_pool_test)83 START_TEST (pool_make_sub_pool_test) {
84 pool *p, *sub_pool;
85
86 p = make_sub_pool(NULL);
87 fail_if(p == NULL, "Failed to allocate parent pool");
88 destroy_pool(p);
89
90 p = make_sub_pool(NULL);
91 fail_if(p == NULL, "Failed to allocate parent pool");
92
93 sub_pool = make_sub_pool(p);
94 fail_if(sub_pool == NULL, "Failed to allocate sub pool");
95
96 destroy_pool(p);
97 }
98 END_TEST
99
START_TEST(pool_create_sz_test)100 START_TEST (pool_create_sz_test) {
101 pool *p, *sub_pool;
102 size_t sz;
103
104 p = make_sub_pool(NULL);
105 fail_if(p == NULL, "Failed to allocate parent pool");
106
107 sz = 0;
108 sub_pool = pr_pool_create_sz(p, sz);
109 fail_if(sub_pool == NULL, "Failed to allocate %u byte sub-pool", sz);
110 destroy_pool(sub_pool);
111
112 sz = 1;
113 sub_pool = pr_pool_create_sz(p, sz);
114 fail_if(sub_pool == NULL, "Failed to allocate %u byte sub-pool", sz);
115 destroy_pool(sub_pool);
116
117 sz = 16382;
118 sub_pool = pr_pool_create_sz(p, sz);
119 fail_if(sub_pool == NULL, "Failed to allocate %u byte sub-pool", sz);
120 destroy_pool(sub_pool);
121
122 destroy_pool(p);
123 }
124 END_TEST
125
START_TEST(pool_create_sz_with_alloc_test)126 START_TEST (pool_create_sz_with_alloc_test) {
127 register unsigned int i;
128 pool *p;
129 unsigned int factors[] = { 1, 2, 4, 8, 16, 32, 64, 128, 0 };
130
131 p = make_sub_pool(NULL);
132
133 for (i = 0; factors[i] > 0; i++) {
134 register unsigned int j;
135 size_t pool_sz, alloc_sz;
136 pool *sub_pool;
137 unsigned char *data;
138
139 /* Allocate a pool with a given size, then allocate more than that out of
140 * the pool.
141 */
142 pool_sz = (32 * factors[i]);
143 #ifdef PR_TEST_VERBOSE
144 fprintf(stdout, "pool_sz: %lu bytes (factor %u)\n", pool_sz, factors[i]);
145 #endif /* PR_TEST_VERBOSE */
146 sub_pool = pr_pool_create_sz(p, pool_sz);
147 fail_if(sub_pool == NULL, "Failed to allocate %u byte sub-pool", pool_sz);
148
149 alloc_sz = (pool_sz * 2);
150 #ifdef PR_TEST_VERBOSE
151 fprintf(stdout, "alloc_sz: %lu bytes (factor %u)\n", alloc_sz, factors[i]);
152 #endif /* PR_TEST_VERBOSE */
153 data = palloc(sub_pool, alloc_sz);
154
155 /* Initialize our allocated memory with some values. */
156 mark_point();
157 for (j = 0; j < alloc_sz; j++) {
158 data[j] = j;
159 }
160
161 /* Verify that our values are still there. */
162 mark_point();
163 for (j = 0; j < alloc_sz; j++) {
164 #ifdef PR_TEST_VERBOSE
165 if (data[j] != j) {
166 fprintf(stdout,
167 "Iteration #%u: Expected value %u at memory index %u, got %u\n",
168 i + 1, j, j, data[j]);
169 }
170 #endif /* PR_TEST_VERBOSE */
171 fail_if(data[j] != j,
172 "Iteration #%u: Expected value %u at memory index %u, got %u\n", i + 1,
173 j, j, data[j]);
174 }
175
176 destroy_pool(sub_pool);
177 }
178
179 destroy_pool(p);
180 }
181 END_TEST
182
START_TEST(pool_palloc_test)183 START_TEST (pool_palloc_test) {
184 pool *p;
185 char *v;
186 size_t sz;
187
188 p = make_sub_pool(NULL);
189 fail_if(p == NULL, "Failed to allocate parent pool");
190
191 sz = 0;
192 v = palloc(p, sz);
193 fail_unless(v == NULL, "Allocated %u-len memory", sz);
194
195 sz = 1;
196 v = palloc(p, sz);
197 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
198
199 sz = 16382;
200 v = palloc(p, sz);
201 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
202
203 destroy_pool(p);
204 }
205 END_TEST
206
START_TEST(pool_pallocsz_test)207 START_TEST (pool_pallocsz_test) {
208 pool *p;
209 char *v;
210 size_t sz;
211
212 p = make_sub_pool(NULL);
213 fail_if(p == NULL, "Failed to allocate parent pool");
214
215 sz = 0;
216 v = pallocsz(p, sz);
217 fail_unless(v == NULL, "Allocated %u-len memory", sz);
218
219 sz = 1;
220 v = pallocsz(p, sz);
221 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
222
223 sz = 16382;
224 v = pallocsz(p, sz);
225 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
226
227 destroy_pool(p);
228 }
229 END_TEST
230
START_TEST(pool_pcalloc_test)231 START_TEST (pool_pcalloc_test) {
232 register unsigned int i;
233 pool *p;
234 char *v;
235 size_t sz;
236
237 p = make_sub_pool(NULL);
238 fail_if(p == NULL, "Failed to allocate parent pool");
239
240 sz = 0;
241 v = pcalloc(p, sz);
242 fail_unless(v == NULL, "Allocated %u-len memory", sz);
243
244 sz = 1;
245 v = pcalloc(p, sz);
246 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
247 for (i = 0; i < sz; i++) {
248 fail_unless(v[i] == 0, "Allocated non-zero memory at position %u", i);
249 }
250
251 sz = 16382;
252 v = pcalloc(p, sz);
253 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
254 for (i = 0; i < sz; i++) {
255 fail_unless(v[i] == 0, "Allocated non-zero memory at position %u", i);
256 }
257
258 destroy_pool(p);
259 }
260 END_TEST
261
START_TEST(pool_pcallocsz_test)262 START_TEST (pool_pcallocsz_test) {
263 pool *p;
264 char *v;
265 size_t sz;
266
267 p = make_sub_pool(NULL);
268 fail_if(p == NULL, "Failed to allocate parent pool");
269
270 sz = 0;
271 v = pcallocsz(p, sz);
272 fail_unless(v == NULL, "Allocated %u-len memory", sz);
273
274 sz = 1;
275 v = pcallocsz(p, sz);
276 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
277
278 sz = 16382;
279 v = pcallocsz(p, sz);
280 fail_if(v == NULL, "Failed to allocate %u-len memory", sz);
281
282 destroy_pool(p);
283 }
284 END_TEST
285
START_TEST(pool_tag_test)286 START_TEST (pool_tag_test) {
287 pool *p;
288
289 p = make_sub_pool(permanent_pool);
290
291 mark_point();
292 pr_pool_tag(NULL, NULL);
293
294 mark_point();
295 pr_pool_tag(p, NULL);
296
297 mark_point();
298 pr_pool_tag(p, "foo");
299
300 destroy_pool(p);
301 }
302 END_TEST
303
START_TEST(pool_get_tag_test)304 START_TEST (pool_get_tag_test) {
305 pool *p;
306 const char *res;
307
308 res = pr_pool_get_tag(NULL);
309 fail_unless(res == NULL, "Failed to handle null pool");
310
311 p = make_sub_pool(permanent_pool);
312
313 mark_point();
314 res = pr_pool_get_tag(p);
315 fail_unless(res == NULL, "Failed to handle untagged pool");
316
317 mark_point();
318 pr_pool_tag(p, "foo");
319 res = pr_pool_get_tag(p);
320 fail_unless(res != NULL, "Failed to get pool tag: %s", strerror(errno));
321 fail_unless(strcmp(res, "foo") == 0, "Expected tag 'foo', got '%s'", res);
322
323 destroy_pool(p);
324
325 }
326 END_TEST
327
328 #if defined(PR_USE_DEVEL)
START_TEST(pool_debug_memory_test)329 START_TEST (pool_debug_memory_test) {
330 pool *p, *sub_pool;
331
332 mark_point();
333 pr_pool_debug_memory(NULL);
334
335 mark_point();
336 p = make_sub_pool(permanent_pool);
337 pr_pool_debug_memory(NULL);
338
339 mark_point();
340 destroy_pool(p);
341 pr_pool_debug_memory(NULL);
342
343 mark_point();
344 p = make_sub_pool(permanent_pool);
345 sub_pool = make_sub_pool(p);
346 pr_pool_debug_memory(NULL);
347
348 destroy_pool(sub_pool);
349 pr_pool_debug_memory(NULL);
350
351 destroy_pool(p);
352 pr_pool_debug_memory(NULL);
353 }
354 END_TEST
355
START_TEST(pool_debug_flags_test)356 START_TEST (pool_debug_flags_test) {
357 int res;
358
359 res = pr_pool_debug_set_flags(-1);
360 fail_unless(res < 0, "Failed to handle invalid flags");
361 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
362 strerror(errno), errno);
363
364 res = pr_pool_debug_set_flags(0);
365 fail_if(res < 0, "Failed to set flags: %s", strerror(errno));
366 }
367 END_TEST
368 #endif /* PR_USE_DEVEL */
369
370 static unsigned int pool_cleanup_count = 0;
371
cleanup_cb(void * data)372 static void cleanup_cb(void *data) {
373 pool_cleanup_count++;
374 }
375
START_TEST(pool_register_cleanup_test)376 START_TEST (pool_register_cleanup_test) {
377 pool *p;
378
379 pool_cleanup_count = 0;
380
381 mark_point();
382 register_cleanup(NULL, NULL, NULL, NULL);
383
384 mark_point();
385 p = make_sub_pool(permanent_pool);
386 register_cleanup(p, NULL, NULL, NULL);
387
388 register_cleanup(p, NULL, cleanup_cb, cleanup_cb);
389 destroy_pool(p);
390 fail_unless(pool_cleanup_count > 0, "Expected cleanup count >0, got %u",
391 pool_cleanup_count);
392 }
393 END_TEST
394
START_TEST(pool_register_cleanup2_test)395 START_TEST (pool_register_cleanup2_test) {
396 pool *p;
397
398 pool_cleanup_count = 0;
399
400 mark_point();
401 register_cleanup2(NULL, NULL, NULL);
402
403 mark_point();
404 p = make_sub_pool(permanent_pool);
405 register_cleanup2(p, NULL, NULL);
406
407 register_cleanup2(p, NULL, cleanup_cb);
408 destroy_pool(p);
409 fail_unless(pool_cleanup_count > 0, "Expected cleanup count >0, got %u",
410 pool_cleanup_count);
411 }
412 END_TEST
413
START_TEST(pool_unregister_cleanup_test)414 START_TEST (pool_unregister_cleanup_test) {
415 pool *p;
416
417 pool_cleanup_count = 0;
418
419 mark_point();
420 unregister_cleanup(NULL, NULL, NULL);
421
422 mark_point();
423 p = make_sub_pool(permanent_pool);
424 register_cleanup(p, NULL, cleanup_cb, cleanup_cb);
425 unregister_cleanup(p, NULL, NULL);
426 fail_unless(pool_cleanup_count == 0, "Expected cleanup count 0, got %u",
427 pool_cleanup_count);
428
429 pool_cleanup_count = 0;
430 register_cleanup(p, NULL, cleanup_cb, cleanup_cb);
431 unregister_cleanup(p, NULL, cleanup_cb);
432 fail_unless(pool_cleanup_count == 0, "Expected cleanup count >0, got %u",
433 pool_cleanup_count);
434
435 destroy_pool(p);
436 fail_unless(pool_cleanup_count == 0, "Expected cleanup count >0, got %u",
437 pool_cleanup_count);
438 }
439 END_TEST
440
tests_get_pool_suite(void)441 Suite *tests_get_pool_suite(void) {
442 Suite *suite;
443 TCase *testcase;
444
445 suite = suite_create("pool");
446
447 testcase = tcase_create("base");
448 tcase_add_checked_fixture(testcase, set_up, tear_down);
449
450 tcase_add_test(testcase, pool_destroy_pool_test);
451 tcase_add_test(testcase, pool_make_sub_pool_test);
452 tcase_add_test(testcase, pool_create_sz_test);
453
454 /* Seems this particular testcase reveals a bug in the pool code. On the
455 * third iteration of the loop (pool size = 256, alloc size = 512), the
456 * memory check fails. Perhaps related to PR_TUNABLE_NEW_POOL_SIZE being
457 * 512 bytes? Need to dig into this more. In the mean time, keep the
458 * testcase commented out.
459 *
460 * Note: when it fails, it looks like:
461 *
462 * api/pool.c:116:F:base:pool_create_sz_with_alloc_test:0: Iteration #3: Expected value 256 at memory index 256, got 0
463 *
464 * If the PR_TEST_VERBOSE macro is defined, you can see the printout of
465 * where the memory read does not meet expectations.
466 */
467 #if 0
468 tcase_add_test(testcase, pool_create_sz_with_alloc_test);
469 #endif
470 tcase_add_test(testcase, pool_palloc_test);
471 tcase_add_test(testcase, pool_pallocsz_test);
472 tcase_add_test(testcase, pool_pcalloc_test);
473 tcase_add_test(testcase, pool_pcallocsz_test);
474 tcase_add_test(testcase, pool_tag_test);
475 tcase_add_test(testcase, pool_get_tag_test);
476 #if defined(PR_USE_DEVEL)
477 tcase_add_test(testcase, pool_debug_memory_test);
478 tcase_add_test(testcase, pool_debug_flags_test);
479 #endif /* PR_USE_DEVEL */
480 tcase_add_test(testcase, pool_register_cleanup_test);
481 tcase_add_test(testcase, pool_register_cleanup2_test);
482 tcase_add_test(testcase, pool_unregister_cleanup_test);
483
484 suite_add_tcase(suite, testcase);
485 return suite;
486 }
487