2 Unix SMB/CIFS implementation.
4 local testing of talloc routines.
6 Copyright (C) Andrew Tridgell 2004
8 ** NOTE! The following LGPL license applies to the talloc
9 ** library. This does NOT imply that all of Samba is released
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 2 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 struct torture_context;
53 static struct timeval timeval_current(void)
56 gettimeofday(&tv, NULL);
60 static double timeval_elapsed(struct timeval *tv)
62 struct timeval tv2 = timeval_current();
63 return (tv2.tv_sec - tv->tv_sec) +
64 (tv2.tv_usec - tv->tv_usec)*1.0e-6;
67 #if SAMBA_VERSION_MAJOR<4
76 #define CHECK_SIZE(ptr, tsize) do { \
77 if (talloc_total_size(ptr) != (tsize)) { \
78 printf(__location__ " failed: wrong '%s' tree size: got %u expected %u\n", \
80 (unsigned)talloc_total_size(ptr), \
82 talloc_report_full(ptr, stdout); \
87 #define CHECK_BLOCKS(ptr, tblocks) do { \
88 if (talloc_total_blocks(ptr) != (tblocks)) { \
89 printf(__location__ " failed: wrong '%s' tree blocks: got %u expected %u\n", \
91 (unsigned)talloc_total_blocks(ptr), \
93 talloc_report_full(ptr, stdout); \
98 #define CHECK_PARENT(ptr, parent) do { \
99 if (talloc_parent(ptr) != (parent)) { \
100 printf(__location__ " failed: '%s' has wrong parent: got %p expected %p\n", \
102 talloc_parent(ptr), \
104 talloc_report_full(ptr, stdout); \
105 talloc_report_full(parent, stdout); \
106 talloc_report_full(NULL, stdout); \
115 static BOOL test_ref1(void)
117 void *root, *p1, *p2, *ref, *r1;
119 printf("TESTING SINGLE REFERENCE FREE\n");
121 root = talloc_named_const(NULL, 0, "root");
122 p1 = talloc_named_const(root, 1, "p1");
123 p2 = talloc_named_const(p1, 1, "p2");
124 talloc_named_const(p1, 1, "x1");
125 talloc_named_const(p1, 2, "x2");
126 talloc_named_const(p1, 3, "x3");
128 r1 = talloc_named_const(root, 1, "r1");
129 ref = talloc_reference(r1, p2);
130 talloc_report_full(root, stdout);
136 printf("Freeing p2\n");
138 talloc_report_full(root, stdout);
144 printf("Freeing p1\n");
146 talloc_report_full(root, stdout);
150 printf("Freeing r1\n");
152 talloc_report_full(NULL, stdout);
154 printf("Testing NULL\n");
155 if (talloc_reference(root, NULL)) {
159 CHECK_BLOCKS(root, 1);
171 static BOOL test_ref2(void)
173 void *root, *p1, *p2, *ref, *r1;
175 printf("TESTING DOUBLE REFERENCE FREE\n");
177 root = talloc_named_const(NULL, 0, "root");
178 p1 = talloc_named_const(root, 1, "p1");
179 talloc_named_const(p1, 1, "x1");
180 talloc_named_const(p1, 1, "x2");
181 talloc_named_const(p1, 1, "x3");
182 p2 = talloc_named_const(p1, 1, "p2");
184 r1 = talloc_named_const(root, 1, "r1");
185 ref = talloc_reference(r1, p2);
186 talloc_report_full(root, stdout);
192 printf("Freeing ref\n");
194 talloc_report_full(root, stdout);
200 printf("Freeing p2\n");
202 talloc_report_full(root, stdout);
207 printf("Freeing p1\n");
209 talloc_report_full(root, stdout);
213 printf("Freeing r1\n");
215 talloc_report_full(root, stdout);
227 static BOOL test_ref3(void)
229 void *root, *p1, *p2, *ref, *r1;
231 printf("TESTING PARENT REFERENCE FREE\n");
233 root = talloc_named_const(NULL, 0, "root");
234 p1 = talloc_named_const(root, 1, "p1");
235 p2 = talloc_named_const(root, 1, "p2");
236 r1 = talloc_named_const(p1, 1, "r1");
237 ref = talloc_reference(p2, r1);
238 talloc_report_full(root, stdout);
244 printf("Freeing p1\n");
246 talloc_report_full(root, stdout);
251 printf("Freeing p2\n");
253 talloc_report_full(root, stdout);
265 static BOOL test_ref4(void)
267 void *root, *p1, *p2, *ref, *r1;
269 printf("TESTING REFERRER REFERENCE FREE\n");
271 root = talloc_named_const(NULL, 0, "root");
272 p1 = talloc_named_const(root, 1, "p1");
273 talloc_named_const(p1, 1, "x1");
274 talloc_named_const(p1, 1, "x2");
275 talloc_named_const(p1, 1, "x3");
276 p2 = talloc_named_const(p1, 1, "p2");
278 r1 = talloc_named_const(root, 1, "r1");
279 ref = talloc_reference(r1, p2);
280 talloc_report_full(root, stdout);
286 printf("Freeing r1\n");
288 talloc_report_full(root, stdout);
293 printf("Freeing p2\n");
295 talloc_report_full(root, stdout);
299 printf("Freeing p1\n");
301 talloc_report_full(root, stdout);
314 static BOOL test_unlink1(void)
316 void *root, *p1, *p2, *ref, *r1;
318 printf("TESTING UNLINK\n");
320 root = talloc_named_const(NULL, 0, "root");
321 p1 = talloc_named_const(root, 1, "p1");
322 talloc_named_const(p1, 1, "x1");
323 talloc_named_const(p1, 1, "x2");
324 talloc_named_const(p1, 1, "x3");
325 p2 = talloc_named_const(p1, 1, "p2");
327 r1 = talloc_named_const(p1, 1, "r1");
328 ref = talloc_reference(r1, p2);
329 talloc_report_full(root, stdout);
335 printf("Unreferencing r1\n");
336 talloc_unlink(r1, p2);
337 talloc_report_full(root, stdout);
343 printf("Freeing p1\n");
345 talloc_report_full(root, stdout);
354 static int fail_destructor(void *ptr)
360 miscellaneous tests to try to get a higher test coverage percentage
362 static BOOL test_misc(void)
369 printf("TESTING MISCELLANEOUS\n");
371 root = talloc_new(NULL);
373 p1 = talloc_size(root, 0x7fffffff);
375 printf("failed: large talloc allowed\n");
379 p1 = talloc_strdup(root, "foo");
380 talloc_increase_ref_count(p1);
381 talloc_increase_ref_count(p1);
382 talloc_increase_ref_count(p1);
384 CHECK_BLOCKS(root, 2);
387 CHECK_BLOCKS(root, 2);
388 talloc_unlink(NULL, p1);
390 CHECK_BLOCKS(root, 2);
391 p2 = talloc_strdup(p1, "foo");
392 if (talloc_unlink(root, p2) != -1) {
393 printf("failed: talloc_unlink() of non-reference context should return -1\n");
396 if (talloc_unlink(p1, p2) != 0) {
397 printf("failed: talloc_unlink() of parent should succeed\n");
402 CHECK_BLOCKS(root, 2);
404 name = talloc_set_name(p1, "my name is %s", "foo");
405 if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
406 printf("failed: wrong name after talloc_set_name(my name is foo) - '%s'=>'%s'\n",
407 (name?name:"NULL"), talloc_get_name(p1));
411 CHECK_BLOCKS(root, 3);
413 talloc_set_name_const(p1, NULL);
414 if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
415 printf("failed: wrong name after talloc_set_name(NULL) - '%s'\n",
416 talloc_get_name(p1));
420 CHECK_BLOCKS(root, 3);
423 if (talloc_free(NULL) != -1) {
424 printf("talloc_free(NULL) should give -1\n");
428 talloc_set_destructor(p1, fail_destructor);
429 if (talloc_free(p1) != -1) {
430 printf("Failed destructor should cause talloc_free to fail\n");
433 talloc_set_destructor(p1, NULL);
435 talloc_report(root, stdout);
438 p2 = talloc_zero_size(p1, 20);
440 printf("Failed to give zero memory\n");
445 if (talloc_strdup(root, NULL) != NULL) {
446 printf("failed: strdup on NULL should give NULL\n");
450 p2 = talloc_strndup(p1, "foo", 2);
451 if (strcmp("fo", p2) != 0) {
452 printf("failed: strndup doesn't work\n");
455 p2 = talloc_asprintf_append(p2, "o%c", 'd');
456 if (strcmp("food", p2) != 0) {
457 printf("failed: talloc_asprintf_append doesn't work\n");
463 p2 = talloc_asprintf_append(NULL, "hello %s", "world");
464 if (strcmp("hello world", p2) != 0) {
465 printf("failed: talloc_asprintf_append doesn't work\n");
472 d = talloc_array(p1, double, 0x20000000);
474 printf("failed: integer overflow not detected\n");
478 d = talloc_realloc(p1, d, double, 0x20000000);
480 printf("failed: integer overflow not detected\n");
485 CHECK_BLOCKS(root, 1);
487 p1 = talloc_named(root, 100, "%d bytes", 100);
489 CHECK_BLOCKS(root, 3);
490 talloc_unlink(root, p1);
492 p1 = talloc_init("%d bytes", 200);
493 p2 = talloc_asprintf(p1, "my test '%s'", "string");
494 if (strcmp(p2, "my test 'string'") != 0) {
495 printf("failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"\n", p2);
500 CHECK_BLOCKS(root, 1);
501 talloc_unlink(NULL, p1);
503 p1 = talloc_named_const(root, 10, "p1");
504 p2 = talloc_named_const(root, 20, "p2");
505 talloc_reference(p1, p2);
506 talloc_report_full(root, stdout);
507 talloc_unlink(root, p2);
508 talloc_report_full(root, stdout);
511 CHECK_BLOCKS(root, 3);
512 talloc_unlink(p1, p2);
513 talloc_unlink(root, p1);
515 p1 = talloc_named_const(root, 10, "p1");
516 p2 = talloc_named_const(root, 20, "p2");
517 talloc_reference(NULL, p2);
518 talloc_report_full(root, stdout);
519 talloc_unlink(root, p2);
520 talloc_report_full(root, stdout);
523 CHECK_BLOCKS(root, 2);
524 talloc_unlink(NULL, p2);
525 talloc_unlink(root, p1);
527 /* Test that talloc_unlink is a no-op */
529 if (talloc_unlink(root, NULL) != -1) {
530 printf("failed: talloc_unlink(root, NULL) == -1\n");
534 talloc_report(root, stdout);
535 talloc_report(NULL, stdout);
543 talloc_enable_leak_report();
544 talloc_enable_leak_report_full();
553 static BOOL test_realloc(void)
555 void *root, *p1, *p2;
557 printf("TESTING REALLOC\n");
559 root = talloc_new(NULL);
561 p1 = talloc_size(root, 10);
564 p1 = talloc_realloc_size(NULL, p1, 20);
569 p2 = talloc_realloc_size(p1, NULL, 30);
573 p2 = talloc_realloc_size(p1, p2, 40);
576 CHECK_SIZE(root, 60);
579 p1 = talloc_realloc_size(NULL, p1, 20);
582 talloc_increase_ref_count(p2);
583 if (talloc_realloc_size(NULL, p2, 5) != NULL) {
584 printf("failed: talloc_realloc() on a referenced pointer should fail\n");
589 talloc_realloc_size(NULL, p2, 0);
590 talloc_realloc_size(NULL, p2, 0);
593 if (talloc_realloc_size(NULL, p1, 0x7fffffff) != NULL) {
594 printf("failed: oversize talloc should fail\n");
598 talloc_realloc_size(NULL, p1, 0);
600 CHECK_BLOCKS(root, 1);
610 test realloc with a child
612 static BOOL test_realloc_child(void)
619 } **list, **list2, **list3;
623 printf("TESTING REALLOC WITH CHILD\n");
625 root = talloc_new(NULL);
627 el1 = talloc(root, struct el1);
628 el1->list = talloc(el1, struct el2 *);
629 el1->list[0] = talloc(el1->list, struct el2);
630 el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
632 el1->list2 = talloc(el1, struct el2 *);
633 el1->list2[0] = talloc(el1->list2, struct el2);
634 el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
636 el1->list3 = talloc(el1, struct el2 *);
637 el1->list3[0] = talloc(el1->list3, struct el2);
638 el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
640 el2 = talloc(el1->list, struct el2);
641 el2 = talloc(el1->list2, struct el2);
642 el2 = talloc(el1->list3, struct el2);
644 el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
645 el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
646 el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
657 static BOOL test_type(void)
668 printf("TESTING talloc type checking\n");
670 root = talloc_new(NULL);
672 el1 = talloc(root, struct el1);
676 if (talloc_get_type(el1, struct el1) != el1) {
677 printf("type check failed on el1\n");
680 if (talloc_get_type(el1, struct el2) != NULL) {
681 printf("type check failed on el1 with el2\n");
684 talloc_set_type(el1, struct el2);
685 if (talloc_get_type(el1, struct el2) != (struct el2 *)el1) {
686 printf("type set failed on el1 with el2\n");
698 static BOOL test_steal(void)
700 void *root, *p1, *p2;
702 printf("TESTING STEAL\n");
704 root = talloc_new(NULL);
706 p1 = talloc_array(root, char, 10);
709 p2 = talloc_realloc(root, NULL, char, 20);
711 CHECK_SIZE(root, 30);
713 if (talloc_steal(p1, NULL) != NULL) {
714 printf("failed: stealing NULL should give NULL\n");
718 if (talloc_steal(p1, p1) != p1) {
719 printf("failed: stealing to ourselves is a nop\n");
722 CHECK_BLOCKS(root, 3);
723 CHECK_SIZE(root, 30);
725 talloc_steal(NULL, p1);
726 talloc_steal(NULL, p2);
727 CHECK_BLOCKS(root, 1);
731 talloc_steal(root, p2);
732 CHECK_BLOCKS(root, 2);
733 CHECK_SIZE(root, 20);
737 CHECK_BLOCKS(root, 1);
742 p1 = talloc_size(NULL, 3);
743 talloc_report_full(NULL, stdout);
751 test talloc_realloc_fn
753 static BOOL test_realloc_fn(void)
757 printf("TESTING talloc_realloc_fn\n");
759 root = talloc_new(NULL);
761 p1 = talloc_realloc_fn(root, NULL, 10);
762 CHECK_BLOCKS(root, 2);
763 CHECK_SIZE(root, 10);
764 p1 = talloc_realloc_fn(root, p1, 20);
765 CHECK_BLOCKS(root, 2);
766 CHECK_SIZE(root, 20);
767 p1 = talloc_realloc_fn(root, p1, 0);
768 CHECK_BLOCKS(root, 1);
778 static BOOL test_unref_reparent(void)
780 void *root, *p1, *p2, *c1;
782 printf("TESTING UNREFERENCE AFTER PARENT FREED\n");
784 root = talloc_named_const(NULL, 0, "root");
785 p1 = talloc_named_const(root, 1, "orig parent");
786 p2 = talloc_named_const(root, 1, "parent by reference");
788 c1 = talloc_named_const(p1, 1, "child");
789 talloc_reference(p2, c1);
791 CHECK_PARENT(c1, p1);
795 CHECK_PARENT(c1, p2);
797 talloc_unlink(p2, c1);
808 measure the speed of talloc versus malloc
810 static BOOL test_speed(void)
812 void *ctx = talloc_new(NULL);
816 printf("MEASURING TALLOC VS MALLOC SPEED\n");
818 tv = timeval_current();
822 p1 = talloc_size(ctx, count);
823 p2 = talloc_strdup(p1, "foo bar");
824 p3 = talloc_size(p1, 300);
827 } while (timeval_elapsed(&tv) < 5.0);
829 printf("talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
833 tv = timeval_current();
838 p2 = strdup("foo bar");
844 } while (timeval_elapsed(&tv) < 5.0);
846 printf("malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
852 static BOOL test_lifeless(void)
854 char *top = talloc_new(NULL);
855 char *parent, *child;
856 char *child_owner = talloc_new(NULL);
858 printf("TESTING TALLOC_UNLINK LOOP\n");
860 parent = talloc_strdup(top, "parent");
861 child = talloc_strdup(parent, "child");
862 talloc_reference(child, parent);
863 talloc_reference(child_owner, child);
864 talloc_report_full(top, stdout);
865 talloc_unlink(top, parent);
867 talloc_report_full(top, stdout);
869 talloc_free(child_owner);
875 static int loop_destructor_count;
877 static int test_loop_destructor(char *ptr)
879 printf("loop destructor\n");
880 loop_destructor_count++;
884 static BOOL test_loop(void)
886 char *top = talloc_new(NULL);
892 printf("TESTING TALLOC LOOP DESTRUCTION\n");
893 parent = talloc_strdup(top, "parent");
894 req1 = talloc(parent, struct req1);
895 req1->req2 = talloc_strdup(req1, "req2");
896 talloc_set_destructor(req1->req2, test_loop_destructor);
897 req1->req3 = talloc_strdup(req1, "req3");
898 talloc_reference(req1->req3, req1);
899 talloc_report_full(top, stdout);
901 talloc_report_full(top, stdout);
902 talloc_report_full(NULL, stdout);
905 if (loop_destructor_count != 1) {
906 printf("FAILED TO FIRE LOOP DESTRUCTOR\n");
913 static int fail_destructor_str(char *ptr)
918 static BOOL test_free_parent_deny_child(void)
920 char *top = talloc_new(NULL);
925 printf("TESTING TALLOC FREE PARENT DENY CHILD\n");
926 level1 = talloc_strdup(top, "level1");
927 level2 = talloc_strdup(level1, "level2");
928 level3 = talloc_strdup(level2, "level3");
930 talloc_set_destructor(level3, fail_destructor_str);
932 talloc_set_destructor(level3, NULL);
934 CHECK_PARENT(level3, top);
941 BOOL torture_local_talloc(struct torture_context *torture)
945 talloc_enable_null_tracking();
951 ret &= test_unlink1();
953 ret &= test_realloc();
954 ret &= test_realloc_child();
956 ret &= test_unref_reparent();
957 ret &= test_realloc_fn();
959 ret &= test_lifeless();
961 ret &= test_free_parent_deny_child();
971 #if !defined(_SAMBA_BUILD_) || ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
974 if (!torture_local_talloc(NULL)) {
975 printf("ERROR: TESTSUITE FAILED\n");