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 3 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, see <http://www.gnu.org/licenses/>.
27 #include "system/time.h"
30 static struct timeval timeval_current(void)
33 gettimeofday(&tv, NULL);
37 static double timeval_elapsed(struct timeval *tv)
39 struct timeval tv2 = timeval_current();
40 return (tv2.tv_sec - tv->tv_sec) +
41 (tv2.tv_usec - tv->tv_usec)*1.0e-6;
44 #define torture_assert(test, expr, str) if (!(expr)) { \
45 printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \
46 test, __location__, #expr, str); \
50 #define torture_assert_str_equal(test, arg1, arg2, desc) \
51 if (arg1 == NULL && arg2 == NULL) { \
52 } else if (strcmp(arg1, arg2)) { \
53 printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
54 test, __location__, arg1, arg2, desc); \
67 #define CHECK_SIZE(test, ptr, tsize) do { \
68 if (talloc_total_size(ptr) != (tsize)) { \
69 printf("failed: %s:%d [\nwrong '%s' tree size: got %u expected %u\n]\n", \
70 test, __LINE__, #ptr, \
71 (unsigned)talloc_total_size(ptr), \
73 talloc_report_full(ptr, stdout); \
78 #define CHECK_BLOCKS(test, ptr, tblocks) do { \
79 if (talloc_total_blocks(ptr) != (tblocks)) { \
80 printf("failed: %s:%d [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
81 test, __LINE__, #ptr, \
82 (unsigned)talloc_total_blocks(ptr), \
84 talloc_report_full(ptr, stdout); \
89 #define CHECK_PARENT(test, ptr, parent) do { \
90 if (talloc_parent(ptr) != (parent)) { \
91 printf("failed: %s:%d [\n'%s' has wrong parent: got %p expected %p\n]\n", \
92 test, __LINE__, #ptr, \
95 talloc_report_full(ptr, stdout); \
96 talloc_report_full(parent, stdout); \
97 talloc_report_full(NULL, stdout); \
102 void talloc_erase_no_owner_context();
103 void* talloc_no_owner_context ();
108 static bool test_ref1(void)
110 void *root, *p1, *p2, *ref, *r1;
112 printf("test: ref1\n# SINGLE REFERENCE FREE\n");
113 talloc_erase_no_owner_context();
115 root = talloc_named_const(NULL, 0, "root");
116 p1 = talloc_named_const(root, 1, "p1");
117 p2 = talloc_named_const(p1, 1, "p2");
118 talloc_named_const(p1, 1, "x1");
119 talloc_named_const(p1, 2, "x2");
120 talloc_named_const(p1, 3, "x3");
122 r1 = talloc_named_const(root, 1, "r1");
123 ref = talloc_reference(r1, p2);
124 talloc_report_full(root, stderr);
126 CHECK_BLOCKS("ref1", p1, 5);
127 CHECK_BLOCKS("ref1", p2, 1);
128 CHECK_BLOCKS("ref1", r1, 2);
130 fprintf(stderr, "Freeing p2\n");
132 talloc_report_full(root, stderr);
134 // CHECK_BLOCKS("ref1", p1, 5);
135 // p2 owner was removed, not reference! p2 now belongs to no_owner_context, not p1
136 CHECK_BLOCKS("ref1", p1, 4);
137 CHECK_BLOCKS("ref1", p2, 1);
138 // r1 reference was not destroyed by free(p2) any more
139 // CHECK_BLOCKS("ref1", r1, 1);
140 CHECK_BLOCKS("ref1", r1, 2);
142 fprintf(stderr, "Freeing p1\n");
144 talloc_report_full(root, stderr);
146 // r1 still has reference to p2
147 // CHECK_BLOCKS("ref1", r1, 1);
148 CHECK_BLOCKS("ref1", r1, 2);
150 fprintf(stderr, "Freeing r1\n");
152 talloc_report_full(NULL, stderr);
154 fprintf(stderr, "Testing NULL\n");
155 if (talloc_reference(root, NULL)) {
159 CHECK_BLOCKS("ref1", root, 1);
161 CHECK_SIZE("ref1", root, 0);
164 printf("success: ref1\n");
171 static bool test_ref2(void)
173 void *root, *p1, *p2, *ref, *r1;
175 printf("test: ref2\n# DOUBLE REFERENCE FREE\n");
176 talloc_erase_no_owner_context();
178 root = talloc_named_const(NULL, 0, "root");
179 p1 = talloc_named_const(root, 1, "p1");
180 talloc_named_const(p1, 1, "x1");
181 talloc_named_const(p1, 1, "x2");
182 talloc_named_const(p1, 1, "x3");
183 p2 = talloc_named_const(p1, 1, "p2");
185 r1 = talloc_named_const(root, 1, "r1");
186 ref = talloc_reference(r1, p2);
187 talloc_report_full(NULL, stderr);
189 CHECK_BLOCKS("ref2", p1, 5);
190 CHECK_BLOCKS("ref2", p2, 1);
191 CHECK_BLOCKS("ref2", r1, 2);
193 fprintf(stderr, "Freeing ref\n");
195 talloc_report_full(NULL, stderr);
197 // CHECK_BLOCKS("ref1", p1, 5);
198 // p2 owner was removed, not reference! p2 now belongs to no_owner_context, not to p1
199 CHECK_BLOCKS("ref1", p1, 4);
200 CHECK_BLOCKS("ref2", p2, 1);
201 // r1 reference was not destroyed by free(p2) any more
202 // CHECK_BLOCKS("ref1", r1, 1);
203 CHECK_BLOCKS("ref1", r1, 2);
205 fprintf(stderr, "Freeing p2\n");
207 talloc_report_full(NULL, stderr);
209 CHECK_BLOCKS("ref2", p1, 4);
210 // p2 hasn't been destroyed because r1 still references it, the reference wasn't
211 // CHECK_BLOCKS("ref2", r1, 1);
212 CHECK_BLOCKS("ref2", r1, 2);
214 fprintf(stderr, "Freeing p1\n");
216 talloc_report_full(NULL, stderr);
218 // r1 still has reference
219 // CHECK_BLOCKS("ref2", r1, 1);
220 CHECK_BLOCKS("ref2", r1, 2);
222 fprintf(stderr, "Freeing r1\n");
224 talloc_report_full(root, stderr);
226 CHECK_SIZE("ref2", root, 0);
229 printf("success: ref2\n");
236 static bool test_ref3(void)
238 void *root, *p1, *p2, *ref, *r1;
240 printf("test: ref3\n# PARENT REFERENCE FREE\n");
241 talloc_erase_no_owner_context();
243 root = talloc_named_const(NULL, 0, "root");
244 p1 = talloc_named_const(root, 1, "p1");
245 p2 = talloc_named_const(root, 1, "p2");
246 r1 = talloc_named_const(p1, 1, "r1");
247 ref = talloc_reference(p2, r1);
248 talloc_report_full(root, stderr);
250 CHECK_BLOCKS("ref3", p1, 2);
251 CHECK_BLOCKS("ref3", p2, 2);
252 CHECK_BLOCKS("ref3", r1, 1);
254 fprintf(stderr, "Freeing p1\n");
256 talloc_report_full(root, stderr);
258 CHECK_BLOCKS("ref3", p2, 2);
259 CHECK_BLOCKS("ref3", r1, 1);
261 fprintf(stderr, "Freeing p2\n");
263 talloc_report_full(root, stderr);
265 CHECK_SIZE("ref3", root, 0);
269 printf("success: ref3\n");
276 static bool test_ref4(void)
278 void *root, *p1, *p2, *ref, *r1;
280 printf("test: ref4\n# REFERRER REFERENCE FREE\n");
281 talloc_erase_no_owner_context();
283 root = talloc_named_const(NULL, 0, "root");
284 p1 = talloc_named_const(root, 1, "p1");
285 talloc_named_const(p1, 1, "x1");
286 talloc_named_const(p1, 1, "x2");
287 talloc_named_const(p1, 1, "x3");
288 p2 = talloc_named_const(p1, 1, "p2");
290 r1 = talloc_named_const(root, 1, "r1");
291 ref = talloc_reference(r1, p2);
292 talloc_report_full(root, stderr);
294 CHECK_BLOCKS("ref4", p1, 5);
295 CHECK_BLOCKS("ref4", p2, 1);
296 CHECK_BLOCKS("ref4", r1, 2);
298 fprintf(stderr, "Freeing r1\n");
300 talloc_report_full(root, stderr);
302 CHECK_BLOCKS("ref4", p1, 5);
303 CHECK_BLOCKS("ref4", p2, 1);
305 fprintf(stderr, "Freeing p2\n");
307 talloc_report_full(root, stderr);
309 CHECK_BLOCKS("ref4", p1, 4);
311 fprintf(stderr, "Freeing p1\n");
313 talloc_report_full(root, stderr);
315 CHECK_SIZE("ref4", root, 0);
319 printf("success: ref4\n");
327 static bool test_unlink1(void)
329 void *root, *p1, *p2, *ref, *r1;
331 printf("test: unlink\n# UNLINK\n");
332 talloc_erase_no_owner_context();
334 root = talloc_named_const(NULL, 0, "root");
335 p1 = talloc_named_const(root, 1, "p1");
336 talloc_named_const(p1, 1, "x1");
337 talloc_named_const(p1, 1, "x2");
338 talloc_named_const(p1, 1, "x3");
339 p2 = talloc_named_const(p1, 1, "p2");
341 r1 = talloc_named_const(p1, 1, "r1");
342 ref = talloc_reference(r1, p2);
343 talloc_report_full(root, stderr);
345 CHECK_BLOCKS("unlink", p1, 7);
346 CHECK_BLOCKS("unlink", p2, 1);
347 CHECK_BLOCKS("unlink", r1, 2);
349 fprintf(stderr, "Unreferencing r1\n");
350 talloc_unlink(r1, p2);
351 talloc_report_full(root, stderr);
353 CHECK_BLOCKS("unlink", p1, 6);
354 CHECK_BLOCKS("unlink", p2, 1);
355 CHECK_BLOCKS("unlink", r1, 1);
357 fprintf(stderr, "Freeing p1\n");
359 talloc_report_full(root, stderr);
361 CHECK_SIZE("unlink", root, 0);
365 printf("success: unlink\n");
369 static int fail_destructor(void *ptr)
375 miscellaneous tests to try to get a higher test coverage percentage
377 static bool test_misc(void)
384 printf("test: misc\n# MISCELLANEOUS\n");
385 talloc_erase_no_owner_context();
387 root = talloc_new(NULL);
389 p1 = talloc_size(root, 0x7fffffff);
390 torture_assert("misc", !p1, "failed: large talloc allowed\n");
392 p1 = talloc_strdup(root, "foo");
393 talloc_increase_ref_count(p1);
394 talloc_increase_ref_count(p1);
395 talloc_increase_ref_count(p1);
396 CHECK_BLOCKS("misc", p1, 1);
397 CHECK_BLOCKS("misc", root, 2);
399 CHECK_BLOCKS("misc", p1, 1);
400 // p1 now has no owner but 3 references still
401 // CHECK_BLOCKS("misc", root, 2);
402 CHECK_BLOCKS("misc", root, 1);
403 talloc_unlink(NULL, p1);
404 CHECK_BLOCKS("misc", p1, 1);
405 // p1 now has no owner but 2 references still
406 // CHECK_BLOCKS("misc", root, 2);
407 CHECK_BLOCKS("misc", root, 1);
408 p2 = talloc_strdup(p1, "foo");
409 torture_assert("misc", talloc_unlink(root, p2) == -1,
410 "failed: talloc_unlink() of non-reference context should return -1\n");
411 torture_assert("misc", talloc_unlink(p1, p2) == 0,
412 "failed: talloc_unlink() of parent should succeed\n");
413 // p1 is already "free" but has one reference
415 talloc_unlink(NULL, p1);
416 CHECK_BLOCKS("misc", p1, 1);
417 // p1 now has no owner but 1 references still
418 // CHECK_BLOCKS("misc", root, 2);
419 CHECK_BLOCKS("misc", root, 1);
421 name = talloc_set_name(p1, "my name is %s", "foo");
422 torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
423 "failed: wrong name after talloc_set_name(my name is foo)");
424 CHECK_BLOCKS("misc", p1, 2);
425 // p1 now has no owner but 1 references still
426 // CHECK_BLOCKS("misc", root, 3);
427 CHECK_BLOCKS("misc", root, 1);
429 talloc_set_name_const(p1, NULL);
430 torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
431 "failed: wrong name after talloc_set_name(NULL)");
432 CHECK_BLOCKS("misc", p1, 2);
433 // p1 now has no owner but 1 references still
434 // CHECK_BLOCKS("misc", root, 3);
435 CHECK_BLOCKS("misc", root, 1);
437 torture_assert("misc", talloc_free(NULL) == -1,
438 "talloc_free(NULL) should give -1\n");
440 // put test back on original track
441 talloc_steal(root, p1);
442 talloc_unlink(NULL, p1);
444 talloc_set_destructor(p1, fail_destructor);
445 torture_assert("misc", talloc_free(p1) == -1,
446 "Failed destructor should cause talloc_free to fail\n");
447 talloc_set_destructor(p1, NULL);
449 p2 = (char *)talloc_zero_size(p1, 20);
450 torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
453 torture_assert("misc", talloc_strdup(root, NULL) == NULL,
454 "failed: strdup on NULL should give NULL\n");
456 p2 = talloc_strndup(p1, "foo", 2);
457 torture_assert("misc", strcmp("fo", p2) == 0,
458 "strndup doesn't work\n");
459 p2 = talloc_asprintf_append_buffer(p2, "o%c", 'd');
460 torture_assert("misc", strcmp("food", p2) == 0,
461 "talloc_asprintf_append_buffer doesn't work\n");
462 CHECK_BLOCKS("misc", p2, 1);
463 CHECK_BLOCKS("misc", p1, 3);
465 p2 = talloc_asprintf_append_buffer(NULL, "hello %s", "world");
466 torture_assert("misc", strcmp("hello world", p2) == 0,
467 "talloc_asprintf_append_buffer doesn't work\n");
468 CHECK_BLOCKS("misc", p2, 1);
469 CHECK_BLOCKS("misc", p1, 3);
472 d = talloc_array(p1, double, 0x20000000);
473 torture_assert("misc", !d, "failed: integer overflow not detected\n");
475 d = talloc_realloc(p1, d, double, 0x20000000);
476 torture_assert("misc", !d, "failed: integer overflow not detected\n");
479 CHECK_BLOCKS("misc", root, 1);
481 p1 = talloc_named(root, 100, "%d bytes", 100);
482 CHECK_BLOCKS("misc", p1, 2);
483 CHECK_BLOCKS("misc", root, 3);
484 talloc_unlink(root, p1);
486 p1 = talloc_init("%d bytes", 200);
487 p2 = talloc_asprintf(p1, "my test '%s'", "string");
488 torture_assert_str_equal("misc", p2, "my test 'string'",
489 "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
490 CHECK_BLOCKS("misc", p1, 3);
491 CHECK_SIZE("misc", p2, 17);
492 CHECK_BLOCKS("misc", root, 1);
493 talloc_unlink(NULL, p1);
495 p1 = talloc_named_const(root, 10, "p1");
496 p2 = (char *)talloc_named_const(root, 20, "p2");
497 (void)talloc_reference(p1, p2);
498 talloc_report_full(root, stderr);
499 talloc_unlink(root, p2);
500 talloc_report_full(root, stderr);
501 CHECK_BLOCKS("misc", p2, 1);
502 CHECK_BLOCKS("misc", p1, 2);
503 CHECK_BLOCKS("misc", root, 3);
504 talloc_unlink(p1, p2);
505 talloc_unlink(root, p1);
507 p1 = talloc_named_const(root, 10, "p1");
508 p2 = (char *)talloc_named_const(root, 20, "p2");
509 (void)talloc_reference(NULL, p2);
510 talloc_report_full(root, stderr);
511 talloc_unlink(root, p2);
512 talloc_report_full(root, stderr);
513 CHECK_BLOCKS("misc", p2, 1);
514 CHECK_BLOCKS("misc", p1, 1);
515 CHECK_BLOCKS("misc", root, 2);
516 talloc_unlink(NULL, p2);
517 talloc_unlink(root, p1);
519 /* Test that talloc_unlink is a no-op */
521 torture_assert("misc", talloc_unlink(root, NULL) == -1,
522 "failed: talloc_unlink(root, NULL) == -1\n");
524 talloc_report(root, stderr);
525 talloc_report(NULL, stderr);
527 CHECK_SIZE("misc", root, 0);
530 talloc_report(NULL, stderr);
532 CHECK_SIZE("misc", NULL, 0);
534 talloc_enable_leak_report();
535 talloc_enable_leak_report_full();
537 printf("success: misc\n");
546 static bool test_realloc(void)
548 void *root, *p1, *p2;
550 printf("test: realloc\n# REALLOC\n");
551 talloc_erase_no_owner_context();
553 root = talloc_new(NULL);
555 p1 = talloc_size(root, 10);
556 CHECK_SIZE("realloc", p1, 10);
558 p1 = talloc_realloc_size(NULL, p1, 20);
559 CHECK_SIZE("realloc", p1, 20);
563 p2 = talloc_realloc_size(p1, NULL, 30);
567 p2 = talloc_realloc_size(p1, p2, 40);
569 CHECK_SIZE("realloc", p2, 40);
570 CHECK_SIZE("realloc", root, 60);
571 CHECK_BLOCKS("realloc", p1, 4);
573 p1 = talloc_realloc_size(NULL, p1, 20);
574 CHECK_SIZE("realloc", p1, 60);
576 talloc_increase_ref_count(p2);
577 torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
578 "failed: talloc_realloc() on a referenced pointer should fail\n");
579 CHECK_BLOCKS("realloc", p1, 4);
581 talloc_realloc_size(NULL, p2, 0);
582 talloc_realloc_size(NULL, p2, 0);
583 CHECK_BLOCKS("realloc", p1, 3);
585 torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
586 "failed: oversize talloc should fail\n");
588 talloc_realloc_size(NULL, p1, 0);
590 CHECK_BLOCKS("realloc", root, 1);
591 CHECK_SIZE("realloc", root, 0);
593 // get rid of next line when loop detection works
594 talloc_unlink(NULL, p2);
597 printf("success: realloc\n");
603 test realloc with a child
605 static bool test_realloc_child(void)
613 struct el2 **list, **list2, **list3;
616 printf("test: REALLOC WITH CHILD\n");
617 talloc_erase_no_owner_context();
619 root = talloc_new(NULL);
621 el1 = talloc(root, struct el1);
622 el1->list = talloc(el1, struct el2 *);
623 el1->list[0] = talloc(el1->list, struct el2);
624 el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
626 el1->list2 = talloc(el1, struct el2 *);
627 el1->list2[0] = talloc(el1->list2, struct el2);
628 el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
630 el1->list3 = talloc(el1, struct el2 *);
631 el1->list3[0] = talloc(el1->list3, struct el2);
632 el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
634 el2 = talloc(el1->list, struct el2);
635 el2 = talloc(el1->list2, struct el2);
636 el2 = talloc(el1->list3, struct el2);
638 el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
639 el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
640 el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
644 printf("success: REALLOC WITH CHILD\n");
651 static bool test_type(void)
662 printf("test: type\n# talloc type checking\n");
663 talloc_erase_no_owner_context();
665 root = talloc_new(NULL);
667 el1 = talloc(root, struct el1);
671 torture_assert("type", talloc_get_type(el1, struct el1) == el1,
672 "type check failed on el1\n");
673 torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
674 "type check failed on el1 with el2\n");
675 talloc_set_type(el1, struct el2);
676 torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
677 "type set failed on el1 with el2\n");
681 printf("success: type\n");
688 static bool test_steal(void)
690 void *root, *p1, *p2;
692 printf("test: steal\n# STEAL\n");
693 talloc_erase_no_owner_context();
694 talloc_report_full(NULL, stderr);
696 root = talloc_new(NULL);
698 p1 = talloc_array(root, char, 10);
699 CHECK_SIZE("steal", p1, 10);
701 p2 = talloc_realloc(root, NULL, char, 20);
702 CHECK_SIZE("steal", p1, 10);
703 CHECK_SIZE("steal", root, 30);
705 torture_assert("steal", talloc_steal(p1, NULL) == NULL,
706 "failed: stealing NULL should give NULL\n");
708 torture_assert("steal", talloc_steal(p1, p1) == p1,
709 "failed: stealing to ourselves is a nop\n");
710 CHECK_BLOCKS("steal", root, 3);
711 CHECK_SIZE("steal", root, 30);
713 talloc_steal(NULL, p1);
714 talloc_steal(NULL, p2);
715 CHECK_BLOCKS("steal", root, 1);
716 CHECK_SIZE("steal", root, 0);
719 talloc_steal(root, p2);
720 CHECK_BLOCKS("steal", root, 2);
721 CHECK_SIZE("steal", root, 20);
725 CHECK_BLOCKS("steal", root, 1);
726 CHECK_SIZE("steal", root, 0);
730 p1 = talloc_size(NULL, 3);
731 talloc_report_full(NULL, stderr);
732 CHECK_SIZE("steal", NULL, 3);
735 printf("success: steal\n");
742 static bool test_move(void)
750 printf("test: move\n# MOVE\n");
751 talloc_erase_no_owner_context();
753 root = talloc_new(NULL);
755 t1 = talloc(root, struct t_move);
756 t2 = talloc(root, struct t_move);
757 t1->p = talloc_strdup(t1, "foo");
758 t1->x = talloc(t1, int);
761 t2->p = talloc_move(t2, &t1->p);
762 t2->x = talloc_move(t2, &t1->x);
763 torture_assert("move", t1->p == NULL && t1->x == NULL &&
764 strcmp(t2->p, "foo") == 0 && *t2->x == 42,
765 "talloc move failed");
769 printf("success: move\n");
775 test talloc_realloc_fn
777 static bool test_realloc_fn(void)
781 printf("test: realloc_fn\n# talloc_realloc_fn\n");
782 talloc_erase_no_owner_context();
784 root = talloc_new(NULL);
786 p1 = talloc_realloc_fn(root, NULL, 10);
787 CHECK_BLOCKS("realloc_fn", root, 2);
788 CHECK_SIZE("realloc_fn", root, 10);
789 p1 = talloc_realloc_fn(root, p1, 20);
790 CHECK_BLOCKS("realloc_fn", root, 2);
791 CHECK_SIZE("realloc_fn", root, 20);
792 p1 = talloc_realloc_fn(root, p1, 0);
793 CHECK_BLOCKS("realloc_fn", root, 1);
794 CHECK_SIZE("realloc_fn", root, 0);
798 printf("success: realloc_fn\n");
803 static bool test_unref_reparent(void)
805 void *root, *p1, *p2, *c1;
807 printf("test: unref_reparent\n# UNREFERENCE AFTER PARENT FREED\n");
808 talloc_erase_no_owner_context();
810 root = talloc_named_const(NULL, 0, "root");
811 p1 = talloc_named_const(root, 1, "orig parent");
812 p2 = talloc_named_const(root, 1, "parent by reference");
814 c1 = talloc_named_const(p1, 1, "child");
815 talloc_reference(p2, c1);
817 CHECK_PARENT("unref_reparent", c1, p1);
821 // parent will not be p2, but no_owner_context
822 // CHECK_PARENT("unref_reparent", c1, p2);
824 talloc_unlink(p2, c1);
826 CHECK_SIZE("unref_reparent", root, 1);
831 printf("success: unref_reparent\n");
835 /* If a referenced allocation is explicitly freed the new owner
836 should be the same as if the same allocation is implicitly freed
837 (because it's owner was freed).
838 Traditionally in talloc an explicit free will free the top non-child reference
839 but an implicit free will move the top (any) reference to be the new owner */
840 static bool test_implicit_explicit_free(void)
842 void *root, *p1, *p2, *p3, *ref, *r1;
845 printf("test: test_implicit_explicit_free\n# SINGLE REFERENCE IMPLICIT FREE\n");
846 talloc_erase_no_owner_context();
848 root = talloc_named_const(NULL, 0, "root");
849 p1 = talloc_named_const(root, 1, "p1");
850 p2 = talloc_named_const(p1, 1, "p2");
851 /* Now root owns p1, and p1 owns p2 */
853 r1 = talloc_named_const(root, 1, "r1");
854 ref = talloc_reference(r1, p2);
855 /* now r1 has ref reference to p2 */
856 talloc_report_full(root, stderr);
858 CHECK_BLOCKS(__FUNCTION__, p1, 2);
859 CHECK_BLOCKS(__FUNCTION__, p2, 1);
860 CHECK_BLOCKS(__FUNCTION__, r1, 2);
862 fprintf(stderr, "Freeing p2\n");
864 /* how many blocks is r1 taking against p2 ? */
865 e=talloc_total_blocks(r1);
867 talloc_report_full(root, stderr);
870 /* now repeat, but this time free p1 */
871 printf("# SINGLE REFERENCE EXPLICIT FREE\n");
873 root = talloc_named_const(NULL, 0, "root");
874 p1 = talloc_named_const(root, 1, "p1");
875 p2 = talloc_named_const(p1, 1, "p2");
876 /* Now root owns p1, and p1 owns p2 */
878 r1 = talloc_named_const(root, 1, "r1");
879 ref = talloc_reference(r1, p2);
880 /* now r1 has ref reference to p2 */
881 talloc_report_full(NULL, stderr);
883 CHECK_BLOCKS(__FUNCTION__, p1, 2);
884 CHECK_BLOCKS(__FUNCTION__, p2, 1);
885 CHECK_BLOCKS(__FUNCTION__, r1, 2);
887 fprintf(stderr, "Freeing p1\n");
889 /* how many blocks is r1 taking against p2 ? */
890 i=talloc_total_blocks(r1);
891 talloc_report_full(root, stderr);
893 CHECK_BLOCKS("Implicit",r1, e);
897 printf("success: ref1\n");
901 /* If take r1 reference to p2 and then free p2's parent
902 p2 should still be around by virtue of the reference.
903 In current talloc r1 will be the parent
904 In proposed talloc r1 will be the reference with no parent */
905 static bool test_ref_free_owner(void)
907 void *root, *p1, *p2, *p3, *ref, *r1;
909 printf("test: ref_free_owner\n# SINGLE REFERENCE FREE OWNER FREE\n");
910 talloc_erase_no_owner_context();
912 root = talloc_named_const(NULL, 0, "root");
913 p1 = talloc_named_const(root, 1, "p1");
914 p2 = talloc_named_const(p1, 1, "p2");
915 p3 = talloc_named_const(root, 1, "p3");
916 /* Now root owns p1 ,and p2 owns p2 */
918 r1 = talloc_named_const(root, 1, "r1");
919 ref = talloc_reference(r1, p2);
920 /* now r1 has ref reference to p2 */
921 talloc_report_full(root, stderr);
923 CHECK_BLOCKS(__FUNCTION__, p1, 2);
924 CHECK_BLOCKS(__FUNCTION__, p2, 1);
925 CHECK_BLOCKS(__FUNCTION__, r1, 2);
927 fprintf(stderr, "Freeing p1\n");
929 /* r1 should have ref reference to p2 still */
930 talloc_report_full(NULL, stderr);
931 CHECK_BLOCKS(__FUNCTION__, r1, 2);
933 /* if we talloc_steal p2 to p3, r1 should still have a reference
934 (unless it had been made the parent like in old talloc */
935 fprintf(stderr, "Stealing p2 to p3\n");
936 talloc_steal(p3, p2);
937 talloc_report_full(NULL, stderr);
938 CHECK_BLOCKS(__FUNCTION__, r1, 2);
940 /* now we free p3 and r1 should still have a reference */
941 fprintf(stderr, "free p3\n");
943 talloc_report_full(NULL, stderr);
944 CHECK_BLOCKS(__FUNCTION__, r1, 2);
946 /* if we free r1 then p2 should vanish */
947 fprintf(stderr, "Freeing r1\n");
950 talloc_report_full(NULL, stderr);
951 CHECK_BLOCKS(__FUNCTION__, root, 1);
954 printf("success: ref1\n");
958 /* If take r1 reference to p2 and then free p2
959 p2 should still be around by virtue of the reference.
960 In current talloc r1 will be the parent
961 In proposed talloc r1 will be the reference with no parent */
962 static bool test_ref_free_self(void)
964 void *root, *p1, *p2, *p3, *ref, *r1;
966 printf("test: ref_free_self\n# SINGLE REFERENCE FREE SELF FREE\n");
967 talloc_erase_no_owner_context();
969 root = talloc_named_const(NULL, 0, "root");
970 p1 = talloc_named_const(root, 1, "p1");
971 p2 = talloc_named_const(p1, 1, "p2");
972 p3 = talloc_named_const(root, 1, "p3");
973 /* Now root owns p1, and p1 owns p2 */
975 r1 = talloc_named_const(root, 1, "r1");
976 ref = talloc_reference(r1, p2);
977 /* now r1 has ref reference to p2 */
978 talloc_report_full(NULL, stderr);
980 CHECK_BLOCKS(__FUNCTION__, p1, 2);
981 CHECK_BLOCKS(__FUNCTION__, p2, 1);
982 CHECK_BLOCKS(__FUNCTION__, p3, 1);
983 CHECK_BLOCKS(__FUNCTION__, r1, 2);
985 fprintf(stderr, "Freeing p2\n");
987 /* r1 should have ref reference to p2 still */
988 talloc_report_full(NULL, stderr);
989 CHECK_BLOCKS(__FUNCTION__, r1, 2);
991 /* if we talloc_steal p2 to p3, r1 should still have a reference
992 (unless it had been made the parent like in old talloc */
993 fprintf(stderr, "Steal p2 to p3\n");
994 talloc_steal(p3, p2);
995 talloc_report_full(NULL, stderr);
996 CHECK_BLOCKS(__FUNCTION__, r1, 2);
998 /* now we free p3 and r1 should still have a reference */
999 fprintf(stderr, "free p3\n");
1001 talloc_report_full(NULL, stderr);
1002 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1004 /* if we free r1 then p2 should also vanish */
1005 fprintf(stderr, "Freeing r1\n");
1008 fprintf(stderr, "Checking that p1 is empty and freeing p1\n");
1009 CHECK_BLOCKS(__FUNCTION__, p1, 1);
1012 talloc_report_full(NULL, stderr);
1013 CHECK_BLOCKS(__FUNCTION__, root, 1);
1016 printf("success: ref1\n");
1020 /* check that an allocation that is freed while also referenced finally goes
1021 away when the reference is released */
1022 static bool test_ref_free(void)
1024 void *root, *p1, *p2, *ref, *r1;
1026 printf("test: test_ref_free\n# FREE ON SINGLE REFERENCE FREE\n");
1027 talloc_erase_no_owner_context();
1029 root = talloc_named_const(NULL, 0, "root");
1030 p1 = talloc_named_const(root, 1, "p1");
1031 p2 = talloc_named_const(p1, 1, "p2");
1032 /* Now root owns p1, and p1 owns p2 */
1034 r1 = talloc_named_const(root, 1, "r1");
1035 ref = talloc_reference(r1, p2);
1036 /* now r1 has ref reference to p2 */
1037 talloc_report_full(root, stderr);
1039 CHECK_BLOCKS(__FUNCTION__, p1, 2);
1040 CHECK_BLOCKS(__FUNCTION__, p2, 1);
1041 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1043 fprintf(stderr, "Freeing p2\n");
1045 /* r1 should have ref reference to p2 still */
1046 talloc_report_full(root, stderr);
1048 CHECK_BLOCKS(__FUNCTION__, p1, 1);
1049 CHECK_BLOCKS(__FUNCTION__, root, 4);
1050 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1052 /* if we free r1 then p2 should also vanish */
1053 fprintf(stderr, "Freeing r1\n");
1055 /* p2 should have gone away */
1056 talloc_report_full(NULL, stderr);
1057 CHECK_BLOCKS(__FUNCTION__, root, 2);
1058 CHECK_BLOCKS(__FUNCTION__, p1, 1);
1061 printf("success: ref1\n");
1065 /* If an object having references from children that are also referenced is
1066 freed, the child reference will be removed, but the child will survive
1067 (because of it's reference) and the object will still be freed leaving
1068 a dangling reference */
1069 static bool test_dangling_loop(void)
1071 void *root, *p1, *p2, *ref, *r1, *r2;
1073 printf("test: %s\n# FREE ON SINGLE REFERENCE FREE\n",__FUNCTION__);
1074 talloc_erase_no_owner_context();
1076 root = talloc_named_const(NULL, 0, "root");
1077 p1 = talloc_named_const(root, 1, "p1");
1078 p2 = talloc_named_const(p1, 1, "p2");
1079 /* Now root owns p1, and p1 owns p2 */
1081 /* someone takes a ref on p2 */
1082 r1 = talloc_named_const(root, 1, "r1");
1083 ref = talloc_reference(r1, p2);
1085 /* p2 takes a ref on p1 */
1086 talloc_reference(p2, p1);
1088 talloc_report_full(NULL, stderr);
1090 CHECK_BLOCKS(__FUNCTION__, root, 6);
1091 CHECK_BLOCKS(__FUNCTION__, p1, 3);
1092 CHECK_BLOCKS(__FUNCTION__, p2, 2);
1093 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1095 /* talloc will wrongly spot a loop and free p2's ref, and then p1
1096 leaving a dangling pointer */
1097 fprintf(stderr, "Freeing p1\n");
1099 /* p1 should not get freed as it is referenced from something (a child) that won't free */
1100 /* r1 should have ref reference to p2 still */
1101 talloc_report_full(NULL, stderr);
1103 CHECK_BLOCKS(__FUNCTION__, root, 3);
1104 /* The ugly talloc de-child-looping code will delete p2's reference
1105 leaving p2 having a dangling pointer. p2's reference should remain */
1106 CHECK_BLOCKS(__FUNCTION__, p2, 2);
1107 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1109 /* if we free r1 then p2 should also vanish as it is owned by something that
1110 is not owned, but we can't track that yet. Once p2 vanishes it's reference
1111 to p1 should vanish letting p1 vanish.
1112 We can often make sub-tree's from no-owner-context, by checking when references
1113 of things child-of no-owner-context die
1115 fprintf(stderr, "Freeing r1\n");
1117 talloc_report_full(NULL, stderr);
1118 CHECK_BLOCKS(__FUNCTION__, root, 1);
1121 printf("success: ref1\n");
1123 talloc_erase_no_owner_context();
1124 talloc_report_full(NULL, stderr);
1128 /* If take r1 reference to p2 and then free p2's owner p1
1129 p2 should still be around by virtue of the reference.
1130 steal p2 to p3 and free p3.
1131 In current talloc p2 will be freed despite the reference.
1132 In proposed talloc r1 will be the reference with no parent for p2*/
1133 static bool test_ref_free_steal(void)
1135 void *root, *p1, *p2, *p3, *ref, *r1;
1137 printf("test: ref_free_self\n# SINGLE REFERENCE FREE SELF FREE\n");
1138 talloc_erase_no_owner_context();
1140 root = talloc_named_const(NULL, 0, "root");
1141 p1 = talloc_named_const(root, 1, "p1");
1142 p2 = talloc_named_const(p1, 1, "p2");
1143 p3 = talloc_named_const(root, 1, "p3");
1144 /* Now root owns p1, and p1 owns p2 */
1146 r1 = talloc_named_const(root, 1, "r1");
1147 ref = talloc_reference(r1, p2);
1148 /* now r1 has ref reference to p2 */
1149 talloc_report_full(NULL, stderr);
1151 CHECK_BLOCKS(__FUNCTION__, p1, 2);
1152 CHECK_BLOCKS(__FUNCTION__, p2, 1);
1153 CHECK_BLOCKS(__FUNCTION__, p3, 1);
1154 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1156 fprintf(stderr, "Freeing p1\n");
1158 /* r1 should have ref reference to p2 still */
1159 talloc_report_full(NULL, stderr);
1160 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1162 /* if we talloc_steal p2 to p3, r1 should still have a reference
1163 (unless it had been made the parent like in old talloc */
1164 fprintf(stderr, "Steal p2 to p3\n");
1165 talloc_steal(p3, p2);
1166 talloc_report_full(NULL, stderr);
1167 //CHECK_BLOCKS(__FUNCTION__, r1, 2);
1169 /* now we free p3 and r1 should still have a reference */
1170 fprintf(stderr, "free p3\n");
1172 talloc_report_full(NULL, stderr);
1173 CHECK_BLOCKS(__FUNCTION__, p2, 1);
1174 CHECK_BLOCKS(__FUNCTION__, r1, 2);
1176 /* if we free r1 then p2 should also vanish */
1177 fprintf(stderr, "Freeing r1\n");
1180 talloc_report_full(NULL, stderr);
1181 CHECK_BLOCKS(__FUNCTION__, root, 1);
1184 printf("success: ref1\n");
1189 measure the speed of talloc versus malloc
1191 static bool test_speed(void)
1193 void *ctx = talloc_new(NULL);
1195 const int loop = 1000;
1199 printf("test: speed\n# TALLOC VS MALLOC SPEED\n");
1200 talloc_erase_no_owner_context();
1202 tv = timeval_current();
1206 for (i=0;i<loop;i++) {
1207 p1 = talloc_size(ctx, loop % 100);
1208 p2 = talloc_strdup(p1, "foo bar");
1209 p3 = talloc_size(p1, 300);
1213 } while (timeval_elapsed(&tv) < 5.0);
1215 fprintf(stderr, "talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
1219 ctx = talloc_pool(NULL, 1024);
1221 tv = timeval_current();
1225 for (i=0;i<loop;i++) {
1226 p1 = talloc_size(ctx, loop % 100);
1227 p2 = talloc_strdup(p1, "foo bar");
1228 p3 = talloc_size(p1, 300);
1229 talloc_free_children(ctx);
1232 } while (timeval_elapsed(&tv) < 5.0);
1236 fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/timeval_elapsed(&tv));
1238 tv = timeval_current();
1242 for (i=0;i<loop;i++) {
1243 p1 = malloc(loop % 100);
1244 p2 = strdup("foo bar");
1251 } while (timeval_elapsed(&tv) < 5.0);
1252 fprintf(stderr, "malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
1254 printf("success: speed\n");
1259 static bool test_lifeless(void)
1261 void *top = talloc_new(NULL);
1262 char *parent, *child;
1263 void *child_owner = talloc_new(NULL);
1265 printf("test: lifeless\n# TALLOC_UNLINK LOOP\n");
1266 talloc_erase_no_owner_context();
1268 parent = talloc_strdup(top, "parent");
1269 child = talloc_strdup(parent, "child");
1270 (void)talloc_reference(child, parent);
1271 (void)talloc_reference(child_owner, child);
1272 talloc_report_full(NULL, stderr);
1273 talloc_unlink(top, parent);
1274 /* parent is now owner by no_owner_context */
1275 talloc_report_full(NULL, stderr);
1277 /* child also has no owner, but is still referenced */
1278 talloc_report_full(NULL, stderr);
1279 /* top owns nothing anyway */
1281 /* child_owner has reference to child which is un-owned */
1282 talloc_free(child_owner);
1283 // child will already be free
1284 // talloc_free(child);
1286 /* prove that parent and child have been freed */
1287 talloc_report_full(NULL, stderr);
1288 CHECK_BLOCKS("lifeless", talloc_no_owner_context (), 1);
1290 printf("success: lifeless\n");
1294 static int loop_destructor_count;
1296 static int test_loop_destructor(char *ptr)
1298 loop_destructor_count++;
1302 static bool test_loop(void)
1304 void *top = talloc_new(NULL);
1310 printf("test: loop\n# TALLOC LOOP DESTRUCTION\n");
1311 talloc_erase_no_owner_context();
1313 parent = talloc_strdup(top, "parent");
1314 req1 = talloc(parent, struct req1);
1315 req1->req2 = talloc_strdup(req1, "req2");
1316 talloc_set_destructor(req1->req2, test_loop_destructor);
1317 req1->req3 = talloc_strdup(req1, "req3");
1318 (void)talloc_reference(req1->req3, req1);
1319 talloc_report_full(top, stderr);
1320 talloc_free(parent);
1321 talloc_report_full(top, stderr);
1322 talloc_report_full(NULL, stderr);
1325 torture_assert("loop", loop_destructor_count == 1,
1326 "FAILED TO FIRE LOOP DESTRUCTOR\n");
1327 loop_destructor_count = 0;
1329 printf("success: loop\n");
1333 static int fail_destructor_str(char *ptr)
1338 static bool test_free_parent_deny_child(void)
1340 void *top = talloc_new(NULL);
1345 printf("test: free_parent_deny_child\n# TALLOC FREE PARENT DENY CHILD\n");
1346 talloc_erase_no_owner_context();
1348 level1 = talloc_strdup(top, "level1");
1349 level2 = talloc_strdup(level1, "level2");
1350 level3 = talloc_strdup(level2, "level3");
1352 fprintf(stderr,"level1 %p\nlevel2 %p\nlevel3 %p\n", level1, level2, level3);
1353 talloc_set_destructor(level3, fail_destructor_str);
1354 talloc_free(level1);
1355 talloc_set_destructor(level3, NULL);
1357 // should it be owned by no_owner_context or by top given that the destructor held it back?
1358 // we might want another chance at destructing...
1359 // CHECK_PARENT("free_parent_deny_child", level3, top);
1360 CHECK_PARENT("free_parent_deny_child", level3, talloc_no_owner_context ());
1364 printf("success: free_parent_deny_child\n");
1368 static bool test_talloc_ptrtype(void)
1370 void *top = talloc_new(NULL);
1374 } *s1, *s2, **s3, ***s4;
1375 const char *location1;
1376 const char *location2;
1377 const char *location3;
1378 const char *location4;
1380 printf("test: ptrtype\n# TALLOC PTRTYPE\n");
1381 talloc_erase_no_owner_context();
1383 s1 = talloc_ptrtype(top, s1);location1 = __location__;
1385 if (talloc_get_size(s1) != sizeof(struct struct1)) {
1386 printf("failure: ptrtype [\n"
1387 "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n"
1388 "]\n", (unsigned long)talloc_get_size(s1),
1389 (unsigned long)sizeof(struct struct1));
1393 if (strcmp(location1, talloc_get_name(s1)) != 0) {
1394 printf("failure: ptrtype [\n"
1395 "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
1396 talloc_get_name(s1), location1);
1400 s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
1402 if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) {
1403 printf("failure: ptrtype [\n"
1404 "talloc_array_ptrtype() allocated the wrong size "
1405 "%lu (should be %lu)\n]\n",
1406 (unsigned long)talloc_get_size(s2),
1407 (unsigned long)(sizeof(struct struct1)*10));
1411 if (strcmp(location2, talloc_get_name(s2)) != 0) {
1412 printf("failure: ptrtype [\n"
1413 "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
1414 talloc_get_name(s2), location2);
1418 s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
1420 if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) {
1421 printf("failure: ptrtype [\n"
1422 "talloc_array_ptrtype() allocated the wrong size "
1423 "%lu (should be %lu)\n]\n",
1424 (unsigned long)talloc_get_size(s3),
1425 (unsigned long)(sizeof(struct struct1 *)*10));
1429 torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
1430 "talloc_array_ptrtype() sets the wrong name");
1432 s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
1434 if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) {
1435 printf("failure: ptrtype [\n"
1436 "talloc_array_ptrtype() allocated the wrong size "
1437 "%lu (should be %lu)\n]\n",
1438 (unsigned long)talloc_get_size(s4),
1439 (unsigned long)(sizeof(struct struct1 **)*10));
1443 torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
1444 "talloc_array_ptrtype() sets the wrong name");
1448 printf("success: ptrtype\n");
1452 static int _test_talloc_free_in_destructor(void **ptr)
1458 static bool test_talloc_free_in_destructor(void)
1467 printf("test: free_in_destructor\n# TALLOC FREE IN DESTRUCTOR\n");
1468 talloc_erase_no_owner_context();
1470 level0 = talloc_new(NULL);
1471 level1 = talloc_new(level0);
1472 level2 = talloc_new(level1);
1473 level3 = talloc_new(level2);
1474 level4 = talloc_new(level3);
1475 level5 = talloc(level4, void *);
1478 (void)talloc_reference(level0, level3);
1479 (void)talloc_reference(level3, level3);
1480 (void)talloc_reference(level5, level3);
1482 talloc_set_destructor(level5, _test_talloc_free_in_destructor);
1484 talloc_free(level1);
1486 talloc_free(level0);
1488 printf("success: free_in_destructor\n");
1492 static bool test_autofree(void)
1494 #if _SAMBA_BUILD_ < 4
1495 /* autofree test would kill smbtorture */
1497 printf("test: autofree\n# TALLOC AUTOFREE CONTEXT\n");
1498 talloc_erase_no_owner_context();
1500 p = talloc_autofree_context();
1503 p = talloc_autofree_context();
1506 printf("success: autofree\n");
1511 static bool test_pool(void)
1514 void *p1, *p2, *p3, *p4;
1516 pool = talloc_pool(NULL, 1024);
1518 p1 = talloc_size(pool, 80);
1519 p2 = talloc_size(pool, 20);
1520 p3 = talloc_size(p1, 50);
1521 p4 = talloc_size(p3, 1000);
1528 struct torture_context;
1529 bool torture_local_talloc(struct torture_context *tctx)
1535 talloc_disable_null_tracking();
1536 talloc_enable_null_tracking();
1542 ret &= test_unlink1();
1544 ret &= test_realloc();
1545 ret &= test_realloc_child();
1546 ret &= test_steal();
1548 ret &= test_unref_reparent();
1549 ret &= test_realloc_fn();
1551 ret &= test_lifeless();
1553 ret &= test_free_parent_deny_child();
1554 ret &= test_talloc_ptrtype();
1555 ret &= test_talloc_free_in_destructor();
1556 ret &= test_implicit_explicit_free();
1557 ret &= test_dangling_loop();
1558 ret &= test_ref_free_steal();
1559 ret &= test_ref_free_owner();
1560 ret &= test_ref_free_self();
1561 ret &= test_ref_free();
1565 ret &= test_speed();
1567 ret &= test_autofree();