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