2 Unix SMB/CIFS implementation.
4 local testing of talloc routines.
6 Copyright (C) Andrew Tridgell 2004
7 Converted to ccan tests by Rusty Russell 2008
9 ** NOTE! The following LGPL license applies to the talloc
10 ** library. This does NOT imply that all of Samba is released
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2 of the License, or (at your option) any later version.
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "talloc/talloc.c"
32 #define torture_assert(test, expr, str) \
33 ok(expr, "failure: %s [\n%s: Expression %s failed: %s\n]\n", \
34 test, __location__, #expr, str)
36 #define torture_assert_str_equal(test, arg1, arg2, desc) \
37 ok(strcmp(arg1, arg2) == 0, \
38 "failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
39 test, __location__, arg1, arg2, desc)
41 #define CHECK_SIZE(test, ptr, tsize) \
42 ok(talloc_total_size(ptr) == (tsize), \
43 "failed: %s [\nwrong '%s' tree size: got %u expected %u\n]\n", \
45 (unsigned)talloc_total_size(ptr), \
48 #define CHECK_BLOCKS(test, ptr, tblocks) \
49 ok(talloc_total_blocks(ptr) == (tblocks), \
50 "failed: %s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
52 (unsigned)talloc_total_blocks(ptr), \
55 #define CHECK_PARENT(test, ptr, parent) \
56 ok(talloc_parent(ptr) == (parent), \
57 "failed: %s [\n'%s' has wrong parent: got %p expected %p\n]\n", \
65 static bool test_ref1(void)
67 void *root, *p1, *p2, *ref, *r1;
69 root = talloc_named_const(NULL, 0, "root");
70 p1 = talloc_named_const(root, 1, "p1");
71 p2 = talloc_named_const(p1, 1, "p2");
72 talloc_named_const(p1, 1, "x1");
73 talloc_named_const(p1, 2, "x2");
74 talloc_named_const(p1, 3, "x3");
76 r1 = talloc_named_const(root, 1, "r1");
77 ref = talloc_reference(r1, p2);
79 CHECK_BLOCKS("ref1", p1, 5);
80 CHECK_BLOCKS("ref1", p2, 1);
81 CHECK_BLOCKS("ref1", r1, 2);
85 CHECK_BLOCKS("ref1", p1, 5);
86 CHECK_BLOCKS("ref1", p2, 1);
87 CHECK_BLOCKS("ref1", r1, 1);
91 CHECK_BLOCKS("ref1", r1, 1);
95 if (talloc_reference(root, NULL)) {
99 CHECK_BLOCKS("ref1", root, 1);
101 CHECK_SIZE("ref1", root, 0);
110 static bool test_ref2(void)
112 void *root, *p1, *p2, *ref, *r1;
114 root = talloc_named_const(NULL, 0, "root");
115 p1 = talloc_named_const(root, 1, "p1");
116 talloc_named_const(p1, 1, "x1");
117 talloc_named_const(p1, 1, "x2");
118 talloc_named_const(p1, 1, "x3");
119 p2 = talloc_named_const(p1, 1, "p2");
121 r1 = talloc_named_const(root, 1, "r1");
122 ref = talloc_reference(r1, p2);
124 CHECK_BLOCKS("ref2", p1, 5);
125 CHECK_BLOCKS("ref2", p2, 1);
126 CHECK_BLOCKS("ref2", r1, 2);
130 CHECK_BLOCKS("ref2", p1, 5);
131 CHECK_BLOCKS("ref2", p2, 1);
132 CHECK_BLOCKS("ref2", r1, 1);
136 CHECK_BLOCKS("ref2", p1, 4);
137 CHECK_BLOCKS("ref2", r1, 1);
141 CHECK_BLOCKS("ref2", r1, 1);
145 CHECK_SIZE("ref2", root, 0);
154 static bool test_ref3(void)
156 void *root, *p1, *p2, *ref, *r1;
158 root = talloc_named_const(NULL, 0, "root");
159 p1 = talloc_named_const(root, 1, "p1");
160 p2 = talloc_named_const(root, 1, "p2");
161 r1 = talloc_named_const(p1, 1, "r1");
162 ref = talloc_reference(p2, r1);
164 CHECK_BLOCKS("ref3", p1, 2);
165 CHECK_BLOCKS("ref3", p2, 2);
166 CHECK_BLOCKS("ref3", r1, 1);
170 CHECK_BLOCKS("ref3", p2, 2);
171 CHECK_BLOCKS("ref3", r1, 1);
175 CHECK_SIZE("ref3", root, 0);
185 static bool test_ref4(void)
187 void *root, *p1, *p2, *ref, *r1;
189 root = talloc_named_const(NULL, 0, "root");
190 p1 = talloc_named_const(root, 1, "p1");
191 talloc_named_const(p1, 1, "x1");
192 talloc_named_const(p1, 1, "x2");
193 talloc_named_const(p1, 1, "x3");
194 p2 = talloc_named_const(p1, 1, "p2");
196 r1 = talloc_named_const(root, 1, "r1");
197 ref = talloc_reference(r1, p2);
199 CHECK_BLOCKS("ref4", p1, 5);
200 CHECK_BLOCKS("ref4", p2, 1);
201 CHECK_BLOCKS("ref4", r1, 2);
205 CHECK_BLOCKS("ref4", p1, 5);
206 CHECK_BLOCKS("ref4", p2, 1);
210 CHECK_BLOCKS("ref4", p1, 4);
214 CHECK_SIZE("ref4", root, 0);
225 static bool test_unlink1(void)
227 void *root, *p1, *p2, *ref, *r1;
229 root = talloc_named_const(NULL, 0, "root");
230 p1 = talloc_named_const(root, 1, "p1");
231 talloc_named_const(p1, 1, "x1");
232 talloc_named_const(p1, 1, "x2");
233 talloc_named_const(p1, 1, "x3");
234 p2 = talloc_named_const(p1, 1, "p2");
236 r1 = talloc_named_const(p1, 1, "r1");
237 ref = talloc_reference(r1, p2);
239 CHECK_BLOCKS("unlink", p1, 7);
240 CHECK_BLOCKS("unlink", p2, 1);
241 CHECK_BLOCKS("unlink", r1, 2);
243 talloc_unlink(r1, p2);
245 CHECK_BLOCKS("unlink", p1, 6);
246 CHECK_BLOCKS("unlink", p2, 1);
247 CHECK_BLOCKS("unlink", r1, 1);
251 CHECK_SIZE("unlink", root, 0);
258 static int fail_destructor(void *ptr)
264 miscellaneous tests to try to get a higher test coverage percentage
266 static bool test_misc(void)
273 root = talloc_new(NULL);
275 p1 = talloc_size(root, 0x7fffffff);
276 torture_assert("misc", !p1, "failed: large talloc allowed\n");
278 p1 = talloc_strdup(root, "foo");
279 talloc_increase_ref_count(p1);
280 talloc_increase_ref_count(p1);
281 talloc_increase_ref_count(p1);
282 CHECK_BLOCKS("misc", p1, 1);
283 CHECK_BLOCKS("misc", root, 2);
285 CHECK_BLOCKS("misc", p1, 1);
286 CHECK_BLOCKS("misc", root, 2);
287 talloc_unlink(NULL, p1);
288 CHECK_BLOCKS("misc", p1, 1);
289 CHECK_BLOCKS("misc", root, 2);
290 p2 = talloc_strdup(p1, "foo");
291 torture_assert("misc", talloc_unlink(root, p2) == -1,
292 "failed: talloc_unlink() of non-reference context should return -1\n");
293 torture_assert("misc", talloc_unlink(p1, p2) == 0,
294 "failed: talloc_unlink() of parent should succeed\n");
296 CHECK_BLOCKS("misc", p1, 1);
297 CHECK_BLOCKS("misc", root, 2);
299 name = talloc_set_name(p1, "my name is %s", "foo");
300 torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
301 "failed: wrong name after talloc_set_name(my name is foo)");
302 CHECK_BLOCKS("misc", p1, 2);
303 CHECK_BLOCKS("misc", root, 3);
305 talloc_set_name_const(p1, NULL);
306 torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
307 "failed: wrong name after talloc_set_name(NULL)");
308 CHECK_BLOCKS("misc", p1, 2);
309 CHECK_BLOCKS("misc", root, 3);
311 torture_assert("misc", talloc_free(NULL) == -1,
312 "talloc_free(NULL) should give -1\n");
314 talloc_set_destructor(p1, fail_destructor);
315 torture_assert("misc", talloc_free(p1) == -1,
316 "Failed destructor should cause talloc_free to fail\n");
317 talloc_set_destructor(p1, NULL);
320 p2 = (char *)talloc_zero_size(p1, 20);
321 torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
324 torture_assert("misc", talloc_strdup(root, NULL) == NULL,
325 "failed: strdup on NULL should give NULL\n");
327 p2 = talloc_strndup(p1, "foo", 2);
328 torture_assert("misc", strcmp("fo", p2) == 0,
329 "strndup doesn't work\n");
330 p2 = talloc_asprintf_append(p2, "o%c", 'd');
331 torture_assert("misc", strcmp("food", p2) == 0,
332 "talloc_asprintf_append doesn't work\n");
333 CHECK_BLOCKS("misc", p2, 1);
334 CHECK_BLOCKS("misc", p1, 3);
336 p2 = talloc_asprintf_append(NULL, "hello %s", "world");
337 torture_assert("misc", strcmp("hello world", p2) == 0,
338 "talloc_asprintf_append doesn't work\n");
339 CHECK_BLOCKS("misc", p2, 1);
340 CHECK_BLOCKS("misc", p1, 3);
343 d = talloc_array(p1, double, 0x20000000);
344 torture_assert("misc", !d, "failed: integer overflow not detected\n");
346 d = talloc_realloc(p1, d, double, 0x20000000);
347 torture_assert("misc", !d, "failed: integer overflow not detected\n");
350 CHECK_BLOCKS("misc", root, 1);
352 p1 = talloc_named(root, 100, "%d bytes", 100);
353 CHECK_BLOCKS("misc", p1, 2);
354 CHECK_BLOCKS("misc", root, 3);
355 talloc_unlink(root, p1);
357 p1 = talloc_init("%d bytes", 200);
358 p2 = talloc_asprintf(p1, "my test '%s'", "string");
359 torture_assert_str_equal("misc", p2, "my test 'string'",
360 "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
361 CHECK_BLOCKS("misc", p1, 3);
362 CHECK_SIZE("misc", p2, 17);
363 CHECK_BLOCKS("misc", root, 1);
364 talloc_unlink(NULL, p1);
366 p1 = talloc_named_const(root, 10, "p1");
367 p2 = (char *)talloc_named_const(root, 20, "p2");
368 (void)talloc_reference(p1, p2);
369 talloc_unlink(root, p2);
370 CHECK_BLOCKS("misc", p2, 1);
371 CHECK_BLOCKS("misc", p1, 2);
372 CHECK_BLOCKS("misc", root, 3);
373 talloc_unlink(p1, p2);
374 talloc_unlink(root, p1);
376 p1 = talloc_named_const(root, 10, "p1");
377 p2 = (char *)talloc_named_const(root, 20, "p2");
378 (void)talloc_reference(NULL, p2);
379 talloc_unlink(root, p2);
380 CHECK_BLOCKS("misc", p2, 1);
381 CHECK_BLOCKS("misc", p1, 1);
382 CHECK_BLOCKS("misc", root, 2);
383 talloc_unlink(NULL, p2);
384 talloc_unlink(root, p1);
386 /* Test that talloc_unlink is a no-op */
388 torture_assert("misc", talloc_unlink(root, NULL) == -1,
389 "failed: talloc_unlink(root, NULL) == -1\n");
391 CHECK_SIZE("misc", root, 0);
395 CHECK_SIZE("misc", NULL, 0);
397 talloc_enable_leak_report();
398 talloc_enable_leak_report_full();
407 static bool test_realloc(void)
409 void *root, *p1, *p2;
411 root = talloc_new(NULL);
413 p1 = talloc_size(root, 10);
414 CHECK_SIZE("realloc", p1, 10);
416 p1 = talloc_realloc_size(NULL, p1, 20);
417 CHECK_SIZE("realloc", p1, 20);
421 p2 = talloc_realloc_size(p1, NULL, 30);
425 p2 = talloc_realloc_size(p1, p2, 40);
427 CHECK_SIZE("realloc", p2, 40);
428 CHECK_SIZE("realloc", root, 60);
429 CHECK_BLOCKS("realloc", p1, 4);
431 p1 = talloc_realloc_size(NULL, p1, 20);
432 CHECK_SIZE("realloc", p1, 60);
434 talloc_increase_ref_count(p2);
435 torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
436 "failed: talloc_realloc() on a referenced pointer should fail\n");
437 CHECK_BLOCKS("realloc", p1, 4);
439 talloc_realloc_size(NULL, p2, 0);
440 talloc_realloc_size(NULL, p2, 0);
441 CHECK_BLOCKS("realloc", p1, 3);
443 torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
444 "failed: oversize talloc should fail\n");
446 talloc_realloc_size(NULL, p1, 0);
448 CHECK_BLOCKS("realloc", root, 1);
449 CHECK_SIZE("realloc", root, 0);
457 test realloc with a child
459 static bool test_realloc_child(void)
467 struct el2 **list, **list2, **list3;
470 root = talloc_new(NULL);
472 el1 = talloc(root, struct el1);
473 el1->list = talloc(el1, struct el2 *);
474 el1->list[0] = talloc(el1->list, struct el2);
475 el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
477 el1->list2 = talloc(el1, struct el2 *);
478 el1->list2[0] = talloc(el1->list2, struct el2);
479 el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
481 el1->list3 = talloc(el1, struct el2 *);
482 el1->list3[0] = talloc(el1->list3, struct el2);
483 el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
485 el2 = talloc(el1->list, struct el2);
486 el2 = talloc(el1->list2, struct el2);
487 el2 = talloc(el1->list3, struct el2);
489 el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
490 el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
491 el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
501 static bool test_type(void)
512 root = talloc_new(NULL);
514 el1 = talloc(root, struct el1);
518 torture_assert("type", talloc_get_type(el1, struct el1) == el1,
519 "type check failed on el1\n");
520 torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
521 "type check failed on el1 with el2\n");
522 talloc_set_type(el1, struct el2);
523 torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
524 "type set failed on el1 with el2\n");
534 static bool test_steal(void)
536 void *root, *p1, *p2;
538 root = talloc_new(NULL);
540 p1 = talloc_array(root, char, 10);
541 CHECK_SIZE("steal", p1, 10);
543 p2 = talloc_realloc(root, NULL, char, 20);
544 CHECK_SIZE("steal", p1, 10);
545 CHECK_SIZE("steal", root, 30);
547 torture_assert("steal", talloc_steal(p1, NULL) == NULL,
548 "failed: stealing NULL should give NULL\n");
550 torture_assert("steal", talloc_steal(p1, p1) == p1,
551 "failed: stealing to ourselves is a nop\n");
552 CHECK_BLOCKS("steal", root, 3);
553 CHECK_SIZE("steal", root, 30);
555 talloc_steal(NULL, p1);
556 talloc_steal(NULL, p2);
557 CHECK_BLOCKS("steal", root, 1);
558 CHECK_SIZE("steal", root, 0);
561 talloc_steal(root, p2);
562 CHECK_BLOCKS("steal", root, 2);
563 CHECK_SIZE("steal", root, 20);
567 CHECK_BLOCKS("steal", root, 1);
568 CHECK_SIZE("steal", root, 0);
572 p1 = talloc_size(NULL, 3);
573 CHECK_SIZE("steal", NULL, 3);
582 static bool test_move(void)
590 root = talloc_new(NULL);
592 t1 = talloc(root, struct t_move);
593 t2 = talloc(root, struct t_move);
594 t1->p = talloc_strdup(t1, "foo");
595 t1->x = talloc(t1, int);
598 t2->p = talloc_move(t2, &t1->p);
599 t2->x = talloc_move(t2, &t1->x);
600 torture_assert("move", t1->p == NULL && t1->x == NULL &&
601 strcmp(t2->p, "foo") == 0 && *t2->x == 42,
602 "talloc move failed");
610 test talloc_realloc_fn
612 static bool test_realloc_fn(void)
616 root = talloc_new(NULL);
618 p1 = talloc_realloc_fn(root, NULL, 10);
619 CHECK_BLOCKS("realloc_fn", root, 2);
620 CHECK_SIZE("realloc_fn", root, 10);
621 p1 = talloc_realloc_fn(root, p1, 20);
622 CHECK_BLOCKS("realloc_fn", root, 2);
623 CHECK_SIZE("realloc_fn", root, 20);
624 p1 = talloc_realloc_fn(root, p1, 0);
625 CHECK_BLOCKS("realloc_fn", root, 1);
626 CHECK_SIZE("realloc_fn", root, 0);
634 static bool test_unref_reparent(void)
636 void *root, *p1, *p2, *c1;
638 root = talloc_named_const(NULL, 0, "root");
639 p1 = talloc_named_const(root, 1, "orig parent");
640 p2 = talloc_named_const(root, 1, "parent by reference");
642 c1 = talloc_named_const(p1, 1, "child");
643 talloc_reference(p2, c1);
645 CHECK_PARENT("unref_reparent", c1, p1);
649 CHECK_PARENT("unref_reparent", c1, p2);
651 talloc_unlink(p2, c1);
653 CHECK_SIZE("unref_reparent", root, 1);
661 static bool test_lifeless(void)
663 void *top = talloc_new(NULL);
664 char *parent, *child;
665 void *child_owner = talloc_new(NULL);
667 parent = talloc_strdup(top, "parent");
668 child = talloc_strdup(parent, "child");
669 (void)talloc_reference(child, parent);
670 (void)talloc_reference(child_owner, child);
671 talloc_unlink(top, parent);
674 talloc_free(child_owner);
680 static int loop_destructor_count;
682 static int test_loop_destructor(char *ptr)
684 loop_destructor_count++;
688 static bool test_loop(void)
690 void *top = talloc_new(NULL);
696 parent = talloc_strdup(top, "parent");
697 req1 = talloc(parent, struct req1);
698 req1->req2 = talloc_strdup(req1, "req2");
699 talloc_set_destructor(req1->req2, test_loop_destructor);
700 req1->req3 = talloc_strdup(req1, "req3");
701 (void)talloc_reference(req1->req3, req1);
705 torture_assert("loop", loop_destructor_count == 1,
706 "FAILED TO FIRE LOOP DESTRUCTOR\n");
707 loop_destructor_count = 0;
712 static int fail_destructor_str(char *ptr)
717 static bool test_free_parent_deny_child(void)
719 void *top = talloc_new(NULL);
724 level1 = talloc_strdup(top, "level1");
725 level2 = talloc_strdup(level1, "level2");
726 level3 = talloc_strdup(level2, "level3");
728 talloc_set_destructor(level3, fail_destructor_str);
730 talloc_set_destructor(level3, NULL);
732 CHECK_PARENT("free_parent_deny_child", level3, top);
739 static bool test_talloc_ptrtype(void)
741 void *top = talloc_new(NULL);
745 } *s1, *s2, **s3, ***s4;
746 const char *location1;
747 const char *location2;
748 const char *location3;
749 const char *location4;
751 s1 = talloc_ptrtype(top, s1);location1 = __location__;
753 ok1(talloc_get_size(s1) == sizeof(struct struct1));
755 ok1(strcmp(location1, talloc_get_name(s1)) == 0);
757 s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
759 ok1(talloc_get_size(s2) == (sizeof(struct struct1) * 10));
761 ok1(strcmp(location2, talloc_get_name(s2)) == 0);
763 s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
765 ok1(talloc_get_size(s3) == (sizeof(struct struct1 *) * 10));
767 torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
768 "talloc_array_ptrtype() sets the wrong name");
770 s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
772 ok1(talloc_get_size(s4) == (sizeof(struct struct1 **) * 10));
774 torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
775 "talloc_array_ptrtype() sets the wrong name");
782 static int _test_talloc_free_in_destructor(void **ptr)
788 static bool test_talloc_free_in_destructor(void)
797 level0 = talloc_new(NULL);
798 level1 = talloc_new(level0);
799 level2 = talloc_new(level1);
800 level3 = talloc_new(level2);
801 level4 = talloc_new(level3);
802 level5 = talloc(level4, void *);
805 (void)talloc_reference(level0, level3);
806 (void)talloc_reference(level3, level3);
807 (void)talloc_reference(level5, level3);
809 talloc_set_destructor(level5, _test_talloc_free_in_destructor);
818 static bool test_autofree(void)
820 /* autofree test would kill smbtorture */
822 p = talloc_autofree_context();
825 p = talloc_autofree_context();
831 struct torture_context;
832 static bool torture_local_talloc(struct torture_context *tctx)
838 talloc_disable_null_tracking();
839 talloc_enable_null_tracking();
845 ret &= test_unlink1();
847 ret &= test_realloc();
848 ret &= test_realloc_child();
851 ret &= test_unref_reparent();
852 ret &= test_realloc_fn();
854 ret &= test_lifeless();
856 ret &= test_free_parent_deny_child();
857 ret &= test_talloc_ptrtype();
858 ret &= test_talloc_free_in_destructor();
859 ret &= test_autofree();
864 static int lock_failed = 0, unlock_failed = 0;
865 static void test_lock(int *locked)
872 static void test_unlock(int *locked)
884 talloc_locksafe(test_lock, test_unlock, &locked);
886 torture_local_talloc(NULL);
887 ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
888 ok(!unlock_failed, "unlock_failed count %u should be zero", unlock_failed);
889 return exit_status();