r7372: abartet's patch for BUG 2391 (segv caused by free a static pointer)
[Samba/gbeck.git] / source / lib / talloctort.c
blob0447749abdeca0c6cd9b3e2e77c8689df29c719a
1 /*
2 Unix SMB/CIFS implementation.
4 local testing of talloc routines.
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #ifdef _SAMBA_BUILD_
24 #include "includes.h"
25 #else
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <sys/time.h>
31 #include <time.h>
32 #include "talloc.h"
33 #endif
35 /* the test suite can be built standalone, or as part of Samba */
36 #ifndef _SAMBA_BUILD_
37 typedef enum {False=0,True=1} BOOL;
38 #endif
40 /* Samba3 does not define the timeval functions below */
41 #if !defined(_SAMBA_BUILD_) || ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
43 static struct timeval timeval_current(void)
45 struct timeval tv;
46 gettimeofday(&tv, NULL);
47 return tv;
50 static double timeval_elapsed(struct timeval *tv)
52 struct timeval tv2 = timeval_current();
53 return (tv2.tv_sec - tv->tv_sec) +
54 (tv2.tv_usec - tv->tv_usec)*1.0e-6;
56 #endif /* _SAMBA_BUILD_ */
58 #if SAMBA_VERSION_MAJOR<4
59 #ifdef malloc
60 #undef malloc
61 #endif
62 #ifdef strdup
63 #undef strdup
64 #endif
65 #endif
67 #define CHECK_SIZE(ptr, tsize) do { \
68 if (talloc_total_size(ptr) != (tsize)) { \
69 printf(__location__ " failed: wrong '%s' tree size: got %u expected %u\n", \
70 #ptr, \
71 (unsigned)talloc_total_size(ptr), \
72 (unsigned)tsize); \
73 talloc_report_full(ptr, stdout); \
74 return False; \
75 } \
76 } while (0)
78 #define CHECK_BLOCKS(ptr, tblocks) do { \
79 if (talloc_total_blocks(ptr) != (tblocks)) { \
80 printf(__location__ " failed: wrong '%s' tree blocks: got %u expected %u\n", \
81 #ptr, \
82 (unsigned)talloc_total_blocks(ptr), \
83 (unsigned)tblocks); \
84 talloc_report_full(ptr, stdout); \
85 return False; \
86 } \
87 } while (0)
91 test references
93 static BOOL test_ref1(void)
95 void *root, *p1, *p2, *ref, *r1;
97 printf("TESTING SINGLE REFERENCE FREE\n");
99 root = talloc_named_const(NULL, 0, "root");
100 p1 = talloc_named_const(root, 1, "p1");
101 p2 = talloc_named_const(p1, 1, "p2");
102 talloc_named_const(p1, 1, "x1");
103 talloc_named_const(p1, 2, "x2");
104 talloc_named_const(p1, 3, "x3");
106 r1 = talloc_named_const(root, 1, "r1");
107 ref = talloc_reference(r1, p2);
108 talloc_report_full(root, stdout);
110 CHECK_BLOCKS(p1, 5);
111 CHECK_BLOCKS(p2, 1);
112 CHECK_BLOCKS(r1, 2);
114 printf("Freeing p2\n");
115 talloc_free(p2);
116 talloc_report_full(root, stdout);
118 CHECK_BLOCKS(p1, 5);
119 CHECK_BLOCKS(p2, 1);
120 CHECK_BLOCKS(r1, 1);
122 printf("Freeing p1\n");
123 talloc_free(p1);
124 talloc_report_full(root, stdout);
126 CHECK_BLOCKS(r1, 1);
128 printf("Freeing r1\n");
129 talloc_free(r1);
130 talloc_report_full(NULL, stdout);
132 printf("Testing NULL\n");
133 if (talloc_reference(root, NULL)) {
134 return False;
137 CHECK_BLOCKS(root, 1);
139 CHECK_SIZE(root, 0);
141 talloc_free(root);
143 return True;
147 test references
149 static BOOL test_ref2(void)
151 void *root, *p1, *p2, *ref, *r1;
153 printf("TESTING DOUBLE REFERENCE FREE\n");
155 root = talloc_named_const(NULL, 0, "root");
156 p1 = talloc_named_const(root, 1, "p1");
157 talloc_named_const(p1, 1, "x1");
158 talloc_named_const(p1, 1, "x2");
159 talloc_named_const(p1, 1, "x3");
160 p2 = talloc_named_const(p1, 1, "p2");
162 r1 = talloc_named_const(root, 1, "r1");
163 ref = talloc_reference(r1, p2);
164 talloc_report_full(root, stdout);
166 CHECK_BLOCKS(p1, 5);
167 CHECK_BLOCKS(p2, 1);
168 CHECK_BLOCKS(r1, 2);
170 printf("Freeing ref\n");
171 talloc_free(ref);
172 talloc_report_full(root, stdout);
174 CHECK_BLOCKS(p1, 5);
175 CHECK_BLOCKS(p2, 1);
176 CHECK_BLOCKS(r1, 1);
178 printf("Freeing p2\n");
179 talloc_free(p2);
180 talloc_report_full(root, stdout);
182 CHECK_BLOCKS(p1, 4);
183 CHECK_BLOCKS(r1, 1);
185 printf("Freeing p1\n");
186 talloc_free(p1);
187 talloc_report_full(root, stdout);
189 CHECK_BLOCKS(r1, 1);
191 printf("Freeing r1\n");
192 talloc_free(r1);
193 talloc_report_full(root, stdout);
195 CHECK_SIZE(root, 0);
197 talloc_free(root);
199 return True;
203 test references
205 static BOOL test_ref3(void)
207 void *root, *p1, *p2, *ref, *r1;
209 printf("TESTING PARENT REFERENCE FREE\n");
211 root = talloc_named_const(NULL, 0, "root");
212 p1 = talloc_named_const(root, 1, "p1");
213 p2 = talloc_named_const(root, 1, "p2");
214 r1 = talloc_named_const(p1, 1, "r1");
215 ref = talloc_reference(p2, r1);
216 talloc_report_full(root, stdout);
218 CHECK_BLOCKS(p1, 2);
219 CHECK_BLOCKS(p2, 2);
220 CHECK_BLOCKS(r1, 1);
222 printf("Freeing p1\n");
223 talloc_free(p1);
224 talloc_report_full(root, stdout);
226 CHECK_BLOCKS(p2, 2);
227 CHECK_BLOCKS(r1, 1);
229 printf("Freeing p2\n");
230 talloc_free(p2);
231 talloc_report_full(root, stdout);
233 CHECK_SIZE(root, 0);
235 talloc_free(root);
237 return True;
241 test references
243 static BOOL test_ref4(void)
245 void *root, *p1, *p2, *ref, *r1;
247 printf("TESTING REFERRER REFERENCE FREE\n");
249 root = talloc_named_const(NULL, 0, "root");
250 p1 = talloc_named_const(root, 1, "p1");
251 talloc_named_const(p1, 1, "x1");
252 talloc_named_const(p1, 1, "x2");
253 talloc_named_const(p1, 1, "x3");
254 p2 = talloc_named_const(p1, 1, "p2");
256 r1 = talloc_named_const(root, 1, "r1");
257 ref = talloc_reference(r1, p2);
258 talloc_report_full(root, stdout);
260 CHECK_BLOCKS(p1, 5);
261 CHECK_BLOCKS(p2, 1);
262 CHECK_BLOCKS(r1, 2);
264 printf("Freeing r1\n");
265 talloc_free(r1);
266 talloc_report_full(root, stdout);
268 CHECK_BLOCKS(p1, 5);
269 CHECK_BLOCKS(p2, 1);
271 printf("Freeing p2\n");
272 talloc_free(p2);
273 talloc_report_full(root, stdout);
275 CHECK_BLOCKS(p1, 4);
277 printf("Freeing p1\n");
278 talloc_free(p1);
279 talloc_report_full(root, stdout);
281 CHECK_SIZE(root, 0);
283 talloc_free(root);
285 return True;
290 test references
292 static BOOL test_unlink1(void)
294 void *root, *p1, *p2, *ref, *r1;
296 printf("TESTING UNLINK\n");
298 root = talloc_named_const(NULL, 0, "root");
299 p1 = talloc_named_const(root, 1, "p1");
300 talloc_named_const(p1, 1, "x1");
301 talloc_named_const(p1, 1, "x2");
302 talloc_named_const(p1, 1, "x3");
303 p2 = talloc_named_const(p1, 1, "p2");
305 r1 = talloc_named_const(p1, 1, "r1");
306 ref = talloc_reference(r1, p2);
307 talloc_report_full(root, stdout);
309 CHECK_BLOCKS(p1, 7);
310 CHECK_BLOCKS(p2, 1);
311 CHECK_BLOCKS(r1, 2);
313 printf("Unreferencing r1\n");
314 talloc_unlink(r1, p2);
315 talloc_report_full(root, stdout);
317 CHECK_BLOCKS(p1, 6);
318 CHECK_BLOCKS(p2, 1);
319 CHECK_BLOCKS(r1, 1);
321 printf("Freeing p1\n");
322 talloc_free(p1);
323 talloc_report_full(root, stdout);
325 CHECK_SIZE(root, 0);
327 talloc_free(root);
329 return True;
332 static int fail_destructor(void *ptr)
334 return -1;
338 miscellaneous tests to try to get a higher test coverage percentage
340 static BOOL test_misc(void)
342 void *root, *p1;
343 char *p2;
344 double *d;
346 printf("TESTING MISCELLANEOUS\n");
348 root = talloc_new(NULL);
350 p1 = talloc_size(root, 0x7fffffff);
351 if (p1) {
352 printf("failed: large talloc allowed\n");
353 return False;
356 p1 = talloc_strdup(root, "foo");
357 talloc_increase_ref_count(p1);
358 talloc_increase_ref_count(p1);
359 talloc_increase_ref_count(p1);
360 CHECK_BLOCKS(p1, 1);
361 CHECK_BLOCKS(root, 2);
362 talloc_free(p1);
363 CHECK_BLOCKS(p1, 1);
364 CHECK_BLOCKS(root, 2);
365 talloc_unlink(NULL, p1);
366 CHECK_BLOCKS(p1, 1);
367 CHECK_BLOCKS(root, 2);
368 p2 = talloc_strdup(p1, "foo");
369 if (talloc_unlink(root, p2) != -1) {
370 printf("failed: talloc_unlink() of non-reference context should return -1\n");
371 return False;
373 if (talloc_unlink(p1, p2) != 0) {
374 printf("failed: talloc_unlink() of parent should succeed\n");
375 return False;
377 talloc_free(p1);
378 CHECK_BLOCKS(p1, 1);
379 CHECK_BLOCKS(root, 2);
381 talloc_set_name(p1, "my name is %s", "foo");
382 if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
383 printf("failed: wrong name after talloc_set_name\n");
384 return False;
386 CHECK_BLOCKS(p1, 2);
387 CHECK_BLOCKS(root, 3);
389 talloc_set_name_const(p1, NULL);
390 if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
391 printf("failed: wrong name after talloc_set_name(NULL)\n");
392 return False;
394 CHECK_BLOCKS(p1, 2);
395 CHECK_BLOCKS(root, 3);
398 if (talloc_free(NULL) != -1) {
399 printf("talloc_free(NULL) should give -1\n");
400 return False;
403 talloc_set_destructor(p1, fail_destructor);
404 if (talloc_free(p1) != -1) {
405 printf("Failed destructor should cause talloc_free to fail\n");
406 return False;
408 talloc_set_destructor(p1, NULL);
410 talloc_report(root, stdout);
413 p2 = talloc_zero_size(p1, 20);
414 if (p2[19] != 0) {
415 printf("Failed to give zero memory\n");
416 return False;
418 talloc_free(p2);
420 if (talloc_strdup(root, NULL) != NULL) {
421 printf("failed: strdup on NULL should give NULL\n");
422 return False;
425 p2 = talloc_strndup(p1, "foo", 2);
426 if (strcmp("fo", p2) != 0) {
427 printf("failed: strndup doesn't work\n");
428 return False;
430 p2 = talloc_asprintf_append(p2, "o%c", 'd');
431 if (strcmp("food", p2) != 0) {
432 printf("failed: talloc_asprintf_append doesn't work\n");
433 return False;
435 CHECK_BLOCKS(p2, 1);
436 CHECK_BLOCKS(p1, 3);
438 p2 = talloc_asprintf_append(NULL, "hello %s", "world");
439 if (strcmp("hello world", p2) != 0) {
440 printf("failed: talloc_asprintf_append doesn't work\n");
441 return False;
443 CHECK_BLOCKS(p2, 1);
444 CHECK_BLOCKS(p1, 3);
445 talloc_free(p2);
447 d = talloc_array(p1, double, 0x20000000);
448 if (d) {
449 printf("failed: integer overflow not detected\n");
450 return False;
453 d = talloc_realloc(p1, d, double, 0x20000000);
454 if (d) {
455 printf("failed: integer overflow not detected\n");
456 return False;
459 talloc_free(p1);
460 CHECK_BLOCKS(root, 1);
462 p1 = talloc_named(root, 100, "%d bytes", 100);
463 CHECK_BLOCKS(p1, 2);
464 CHECK_BLOCKS(root, 3);
465 talloc_unlink(root, p1);
467 p1 = talloc_init("%d bytes", 200);
468 p2 = talloc_asprintf(p1, "my test '%s'", "string");
469 CHECK_BLOCKS(p1, 3);
470 CHECK_SIZE(p2, 17);
471 CHECK_BLOCKS(root, 1);
472 talloc_unlink(NULL, p1);
474 p1 = talloc_named_const(root, 10, "p1");
475 p2 = talloc_named_const(root, 20, "p2");
476 talloc_reference(p1, p2);
477 talloc_report_full(root, stdout);
478 talloc_unlink(root, p2);
479 talloc_report_full(root, stdout);
480 CHECK_BLOCKS(p2, 1);
481 CHECK_BLOCKS(p1, 2);
482 CHECK_BLOCKS(root, 3);
483 talloc_unlink(p1, p2);
484 talloc_unlink(root, p1);
486 p1 = talloc_named_const(root, 10, "p1");
487 p2 = talloc_named_const(root, 20, "p2");
488 talloc_reference(NULL, p2);
489 talloc_report_full(root, stdout);
490 talloc_unlink(root, p2);
491 talloc_report_full(root, stdout);
492 CHECK_BLOCKS(p2, 1);
493 CHECK_BLOCKS(p1, 1);
494 CHECK_BLOCKS(root, 2);
495 talloc_unlink(NULL, p2);
496 talloc_unlink(root, p1);
498 /* Test that talloc_unlink is a no-op */
500 if (talloc_unlink(root, NULL) != -1) {
501 printf("failed: talloc_unlink(root, NULL) == -1\n");
502 return False;
505 talloc_report(root, stdout);
506 talloc_report(NULL, stdout);
508 CHECK_SIZE(root, 0);
510 talloc_free(root);
512 CHECK_SIZE(NULL, 0);
514 talloc_enable_leak_report();
515 talloc_enable_leak_report_full();
517 return True;
522 test realloc
524 static BOOL test_realloc(void)
526 void *root, *p1, *p2;
528 printf("TESTING REALLOC\n");
530 root = talloc_new(NULL);
532 p1 = talloc_size(root, 10);
533 CHECK_SIZE(p1, 10);
535 p1 = talloc_realloc_size(NULL, p1, 20);
536 CHECK_SIZE(p1, 20);
538 talloc_new(p1);
540 p2 = talloc_realloc_size(p1, NULL, 30);
542 talloc_new(p1);
544 p2 = talloc_realloc_size(p1, p2, 40);
546 CHECK_SIZE(p2, 40);
547 CHECK_SIZE(root, 60);
548 CHECK_BLOCKS(p1, 4);
550 p1 = talloc_realloc_size(NULL, p1, 20);
551 CHECK_SIZE(p1, 60);
553 talloc_increase_ref_count(p2);
554 if (talloc_realloc_size(NULL, p2, 5) != NULL) {
555 printf("failed: talloc_realloc() on a referenced pointer should fail\n");
556 return False;
558 CHECK_BLOCKS(p1, 4);
560 talloc_realloc_size(NULL, p2, 0);
561 talloc_realloc_size(NULL, p2, 0);
562 CHECK_BLOCKS(p1, 3);
564 if (talloc_realloc_size(NULL, p1, 0x7fffffff) != NULL) {
565 printf("failed: oversize talloc should fail\n");
566 return False;
569 talloc_realloc_size(NULL, p1, 0);
571 CHECK_BLOCKS(root, 1);
572 CHECK_SIZE(root, 0);
574 talloc_free(root);
576 return True;
581 test realloc with a child
583 static BOOL test_realloc_child(void)
585 void *root;
586 struct el1 {
587 int count;
588 struct el2 {
589 const char *name;
590 } **list, **list2, **list3;
591 } *el1;
592 struct el2 *el2;
594 printf("TESTING REALLOC WITH CHILD\n");
596 root = talloc_new(NULL);
598 el1 = talloc(root, struct el1);
599 el1->list = talloc(el1, struct el2 *);
600 el1->list[0] = talloc(el1->list, struct el2);
601 el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
603 el1->list2 = talloc(el1, struct el2 *);
604 el1->list2[0] = talloc(el1->list2, struct el2);
605 el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
607 el1->list3 = talloc(el1, struct el2 *);
608 el1->list3[0] = talloc(el1->list3, struct el2);
609 el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
611 el2 = talloc(el1->list, struct el2);
612 el2 = talloc(el1->list2, struct el2);
613 el2 = talloc(el1->list3, struct el2);
615 el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
616 el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
617 el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
619 talloc_free(root);
621 return True;
626 test type checking
628 static BOOL test_type(void)
630 void *root;
631 struct el1 {
632 int count;
634 struct el2 {
635 int count;
637 struct el1 *el1;
639 printf("TESTING talloc type checking\n");
641 root = talloc_new(NULL);
643 el1 = talloc(root, struct el1);
645 el1->count = 1;
647 if (talloc_get_type(el1, struct el1) != el1) {
648 printf("type check failed on el1\n");
649 return False;
651 if (talloc_get_type(el1, struct el2) != NULL) {
652 printf("type check failed on el1 with el2\n");
653 return False;
655 talloc_set_type(el1, struct el2);
656 if (talloc_get_type(el1, struct el2) != (struct el2 *)el1) {
657 printf("type set failed on el1 with el2\n");
658 return False;
661 talloc_free(root);
663 return True;
667 test steal
669 static BOOL test_steal(void)
671 void *root, *p1, *p2;
673 printf("TESTING STEAL\n");
675 root = talloc_new(NULL);
677 p1 = talloc_array(root, char, 10);
678 CHECK_SIZE(p1, 10);
680 p2 = talloc_realloc(root, NULL, char, 20);
681 CHECK_SIZE(p1, 10);
682 CHECK_SIZE(root, 30);
684 if (talloc_steal(p1, NULL) != NULL) {
685 printf("failed: stealing NULL should give NULL\n");
686 return False;
689 if (talloc_steal(p1, p1) != p1) {
690 printf("failed: stealing to ourselves is a nop\n");
691 return False;
693 CHECK_BLOCKS(root, 3);
694 CHECK_SIZE(root, 30);
696 talloc_steal(NULL, p1);
697 talloc_steal(NULL, p2);
698 CHECK_BLOCKS(root, 1);
699 CHECK_SIZE(root, 0);
701 talloc_free(p1);
702 talloc_steal(root, p2);
703 CHECK_BLOCKS(root, 2);
704 CHECK_SIZE(root, 20);
706 talloc_free(p2);
708 CHECK_BLOCKS(root, 1);
709 CHECK_SIZE(root, 0);
711 talloc_free(root);
713 p1 = talloc_size(NULL, 3);
714 CHECK_SIZE(NULL, 3);
715 talloc_free(p1);
717 return True;
721 test talloc_realloc_fn
723 static BOOL test_realloc_fn(void)
725 void *root, *p1;
727 printf("TESTING talloc_realloc_fn\n");
729 root = talloc_new(NULL);
731 p1 = talloc_realloc_fn(root, NULL, 10);
732 CHECK_BLOCKS(root, 2);
733 CHECK_SIZE(root, 10);
734 p1 = talloc_realloc_fn(root, p1, 20);
735 CHECK_BLOCKS(root, 2);
736 CHECK_SIZE(root, 20);
737 p1 = talloc_realloc_fn(root, p1, 0);
738 CHECK_BLOCKS(root, 1);
739 CHECK_SIZE(root, 0);
741 talloc_free(root);
744 return True;
748 static BOOL test_unref_reparent(void)
750 void *root, *p1, *p2, *c1;
752 printf("TESTING UNREFERENCE AFTER PARENT FREED\n");
754 root = talloc_named_const(NULL, 0, "root");
755 p1 = talloc_named_const(root, 1, "orig parent");
756 p2 = talloc_named_const(root, 1, "parent by reference");
758 c1 = talloc_named_const(p1, 1, "child");
759 talloc_reference(p2, c1);
761 talloc_free(p1);
762 talloc_unlink(p2, c1);
764 CHECK_SIZE(root, 1);
766 talloc_free(p2);
767 talloc_free(root);
769 return True;
773 measure the speed of talloc versus malloc
775 static BOOL test_speed(void)
777 void *ctx = talloc_new(NULL);
778 unsigned count;
779 struct timeval tv;
781 printf("MEASURING TALLOC VS MALLOC SPEED\n");
783 tv = timeval_current();
784 count = 0;
785 do {
786 void *p1, *p2, *p3;
787 p1 = talloc_size(ctx, count);
788 p2 = talloc_strdup(p1, "foo bar");
789 p3 = talloc_size(p1, 300);
790 talloc_free(p1);
791 count += 3;
792 } while (timeval_elapsed(&tv) < 5.0);
794 printf("talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
796 talloc_free(ctx);
798 tv = timeval_current();
799 count = 0;
800 do {
801 void *p1, *p2, *p3;
802 p1 = malloc(count);
803 p2 = strdup("foo bar");
804 p3 = malloc(300);
805 free(p1);
806 free(p2);
807 free(p3);
808 count += 3;
809 } while (timeval_elapsed(&tv) < 5.0);
811 printf("malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
813 return True;
817 BOOL torture_local_talloc(void)
819 BOOL ret = True;
821 ret &= test_ref1();
822 ret &= test_ref2();
823 ret &= test_ref3();
824 ret &= test_ref4();
825 ret &= test_unlink1();
826 ret &= test_misc();
827 ret &= test_realloc();
828 ret &= test_realloc_child();
829 ret &= test_steal();
830 ret &= test_unref_reparent();
831 ret &= test_realloc_fn();
832 ret &= test_type();
833 if (ret) {
834 ret &= test_speed();
837 return ret;
842 #if !defined(_SAMBA_BUILD_) || ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
843 int main(void)
845 if (!torture_local_talloc()) {
846 printf("ERROR: TESTSUIE FAILED\n");
847 return -1;
849 return 0;
851 #endif