talloc: use failtest to test failure paths.
[ccan] / ccan / talloc / test / run.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    local testing of talloc routines.
5
6    Copyright (C) Andrew Tridgell 2004
7    Converted to ccan tests by Rusty Russell 2008
8    
9      ** NOTE! The following LGPL license applies to the talloc
10      ** library. This does NOT imply that all of Samba is released
11      ** under the LGPL
12    
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.
17
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.
22
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
26 */
27
28 #include <ccan/talloc/talloc.c>
29 #include <stdbool.h>
30 #include <ccan/tap/tap.h>
31
32 #define torture_assert(test, expr, str)                                 \
33         ok(expr, "%s [\n%s: Expression %s failed: %s\n]\n",             \
34            test, __location__, #expr, str)
35
36 #define torture_assert_str_equal(test, arg1, arg2, desc)        \
37         ok(strcmp(arg1, arg2) == 0,                             \
38            "%s [\n%s: Expected %s, got %s: %s\n]\n",            \
39            test, __location__, arg1, arg2, desc)
40
41 #define CHECK_SIZE(test, ptr, tsize)                                    \
42         ok(talloc_total_size(ptr) == (tsize),                           \
43            "%s [\nwrong '%s' tree size: got %u  expected %u\n]\n",      \
44            test, #ptr,                                                  \
45            (unsigned)talloc_total_size(ptr),                            \
46            (unsigned)tsize)
47
48 #define CHECK_BLOCKS(test, ptr, tblocks)                                \
49         ok(talloc_total_blocks(ptr) == (tblocks),                       \
50            "%s [\nwrong '%s' tree blocks: got %u  expected %u\n]\n",    \
51            test, #ptr,                                                  \
52            (unsigned)talloc_total_blocks(ptr),                          \
53            (unsigned)tblocks)
54
55 #define CHECK_PARENT(test, ptr, parent)                                 \
56         ok(talloc_parent(ptr) == (parent),                              \
57            "%s [\n'%s' has wrong parent: got %p  expected %p\n]\n",     \
58            test, #ptr,                                                  \
59            talloc_parent(ptr),                                          \
60            (parent))
61
62 struct torture_context;
63
64 /*
65   test references 
66 */
67 static bool test_ref1(const struct torture_context *ctx)
68 {
69         void *root, *p1, *p2, *ref, *r1;
70
71         root = talloc_named_const(ctx, 0, "root");
72         p1 = talloc_named_const(root, 1, "p1");
73         p2 = talloc_named_const(p1, 1, "p2");
74         talloc_named_const(p1, 1, "x1");
75         talloc_named_const(p1, 2, "x2");
76         talloc_named_const(p1, 3, "x3");
77
78         r1 = talloc_named_const(root, 1, "r1"); 
79         ref = talloc_reference(r1, p2);
80
81         CHECK_BLOCKS("ref1", p1, 5);
82         CHECK_BLOCKS("ref1", p2, 1);
83         CHECK_BLOCKS("ref1", r1, 2);
84
85         talloc_free(p2);
86
87         CHECK_BLOCKS("ref1", p1, 5);
88         CHECK_BLOCKS("ref1", p2, 1);
89         CHECK_BLOCKS("ref1", r1, 1);
90
91         talloc_free(p1);
92
93         CHECK_BLOCKS("ref1", r1, 1);
94
95         talloc_free(r1);
96
97         if (talloc_reference(root, NULL)) {
98                 return false;
99         }
100
101         CHECK_BLOCKS("ref1", root, 1);
102
103         CHECK_SIZE("ref1", root, 0);
104
105         talloc_free(root);
106         return true;
107 }
108
109 /*
110   test references 
111 */
112 static bool test_ref2(const struct torture_context *ctx)
113 {
114         void *root, *p1, *p2, *ref, *r1;
115
116         root = talloc_named_const(ctx, 0, "root");
117         p1 = talloc_named_const(root, 1, "p1");
118         talloc_named_const(p1, 1, "x1");
119         talloc_named_const(p1, 1, "x2");
120         talloc_named_const(p1, 1, "x3");
121         p2 = talloc_named_const(p1, 1, "p2");
122
123         r1 = talloc_named_const(root, 1, "r1"); 
124         ref = talloc_reference(r1, p2);
125
126         CHECK_BLOCKS("ref2", p1, 5);
127         CHECK_BLOCKS("ref2", p2, 1);
128         CHECK_BLOCKS("ref2", r1, 2);
129
130         talloc_free(ref);
131
132         CHECK_BLOCKS("ref2", p1, 5);
133         CHECK_BLOCKS("ref2", p2, 1);
134         CHECK_BLOCKS("ref2", r1, 1);
135
136         talloc_free(p2);
137
138         CHECK_BLOCKS("ref2", p1, 4);
139         CHECK_BLOCKS("ref2", r1, 1);
140
141         talloc_free(p1);
142
143         CHECK_BLOCKS("ref2", r1, 1);
144
145         talloc_free(r1);
146
147         CHECK_SIZE("ref2", root, 0);
148
149         talloc_free(root);
150         return true;
151 }
152
153 /*
154   test references 
155 */
156 static bool test_ref3(const struct torture_context *ctx)
157 {
158         void *root, *p1, *p2, *ref, *r1;
159
160         root = talloc_named_const(ctx, 0, "root");
161         p1 = talloc_named_const(root, 1, "p1");
162         p2 = talloc_named_const(root, 1, "p2");
163         r1 = talloc_named_const(p1, 1, "r1");
164         ref = talloc_reference(p2, r1);
165
166         CHECK_BLOCKS("ref3", p1, 2);
167         CHECK_BLOCKS("ref3", p2, 2);
168         CHECK_BLOCKS("ref3", r1, 1);
169
170         talloc_free(p1);
171
172         CHECK_BLOCKS("ref3", p2, 2);
173         CHECK_BLOCKS("ref3", r1, 1);
174
175         talloc_free(p2);
176
177         CHECK_SIZE("ref3", root, 0);
178
179         talloc_free(root);
180
181         return true;
182 }
183
184 /*
185   test references 
186 */
187 static bool test_ref4(const struct torture_context *ctx)
188 {
189         void *root, *p1, *p2, *ref, *r1;
190
191         root = talloc_named_const(ctx, 0, "root");
192         p1 = talloc_named_const(root, 1, "p1");
193         talloc_named_const(p1, 1, "x1");
194         talloc_named_const(p1, 1, "x2");
195         talloc_named_const(p1, 1, "x3");
196         p2 = talloc_named_const(p1, 1, "p2");
197
198         r1 = talloc_named_const(root, 1, "r1"); 
199         ref = talloc_reference(r1, p2);
200
201         CHECK_BLOCKS("ref4", p1, 5);
202         CHECK_BLOCKS("ref4", p2, 1);
203         CHECK_BLOCKS("ref4", r1, 2);
204
205         talloc_free(r1);
206
207         CHECK_BLOCKS("ref4", p1, 5);
208         CHECK_BLOCKS("ref4", p2, 1);
209
210         talloc_free(p2);
211
212         CHECK_BLOCKS("ref4", p1, 4);
213
214         talloc_free(p1);
215
216         CHECK_SIZE("ref4", root, 0);
217
218         talloc_free(root);
219
220         return true;
221 }
222
223
224 /*
225   test references 
226 */
227 static bool test_unlink1(const struct torture_context *ctx)
228 {
229         void *root, *p1, *p2, *ref, *r1;
230
231         root = talloc_named_const(ctx, 0, "root");
232         p1 = talloc_named_const(root, 1, "p1");
233         talloc_named_const(p1, 1, "x1");
234         talloc_named_const(p1, 1, "x2");
235         talloc_named_const(p1, 1, "x3");
236         p2 = talloc_named_const(p1, 1, "p2");
237
238         r1 = talloc_named_const(p1, 1, "r1");   
239         ref = talloc_reference(r1, p2);
240
241         CHECK_BLOCKS("unlink", p1, 7);
242         CHECK_BLOCKS("unlink", p2, 1);
243         CHECK_BLOCKS("unlink", r1, 2);
244
245         talloc_unlink(r1, p2);
246
247         CHECK_BLOCKS("unlink", p1, 6);
248         CHECK_BLOCKS("unlink", p2, 1);
249         CHECK_BLOCKS("unlink", r1, 1);
250
251         talloc_free(p1);
252
253         CHECK_SIZE("unlink", root, 0);
254
255         talloc_free(root);
256
257         return true;
258 }
259
260 static int fail_destructor(void *ptr)
261 {
262         return -1;
263 }
264
265 /*
266   miscellaneous tests to try to get a higher test coverage percentage
267 */
268 static bool test_misc(const struct torture_context *ctx)
269 {
270         void *root, *p1;
271         char *p2;
272         double *d;
273         const char *name;
274
275         root = talloc_new(ctx);
276
277         p1 = talloc_size(root, 0x7fffffff);
278         torture_assert("misc", !p1, "failed: large talloc allowed\n");
279
280         p1 = talloc_strdup(root, "foo");
281         talloc_increase_ref_count(p1);
282         talloc_increase_ref_count(p1);
283         talloc_increase_ref_count(p1);
284         CHECK_BLOCKS("misc", p1, 1);
285         CHECK_BLOCKS("misc", root, 2);
286         talloc_free(p1);
287         CHECK_BLOCKS("misc", p1, 1);
288         CHECK_BLOCKS("misc", root, 2);
289         talloc_unlink(NULL, p1);
290         CHECK_BLOCKS("misc", p1, 1);
291         CHECK_BLOCKS("misc", root, 2);
292         p2 = talloc_strdup(p1, "foo");
293         torture_assert("misc", talloc_unlink(root, p2) == -1,
294                                    "failed: talloc_unlink() of non-reference context should return -1\n");
295         torture_assert("misc", talloc_unlink(p1, p2) == 0,
296                 "failed: talloc_unlink() of parent should succeed\n");
297         talloc_free(p1);
298         CHECK_BLOCKS("misc", p1, 1);
299         CHECK_BLOCKS("misc", root, 2);
300
301         name = talloc_set_name(p1, "my name is %s", "foo");
302         torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
303                 "failed: wrong name after talloc_set_name(my name is foo)");
304         CHECK_BLOCKS("misc", p1, 2);
305         CHECK_BLOCKS("misc", root, 3);
306
307         talloc_set_name_const(p1, NULL);
308         torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
309                 "failed: wrong name after talloc_set_name(NULL)");
310         CHECK_BLOCKS("misc", p1, 2);
311         CHECK_BLOCKS("misc", root, 3);
312
313         torture_assert("misc", talloc_free(NULL) == -1, 
314                                    "talloc_free(NULL) should give -1\n");
315
316         talloc_set_destructor(p1, fail_destructor);
317         torture_assert("misc", talloc_free(p1) == -1, 
318                 "Failed destructor should cause talloc_free to fail\n");
319         talloc_set_destructor(p1, NULL);
320
321
322         p2 = (char *)talloc_zero_size(p1, 20);
323         torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
324         talloc_free(p2);
325
326         torture_assert("misc", talloc_strdup(root, NULL) == NULL,
327                 "failed: strdup on NULL should give NULL\n");
328
329         p2 = talloc_strndup(p1, "foo", 2);
330         torture_assert("misc", strcmp("fo", p2) == 0, 
331                                    "strndup doesn't work\n");
332         p2 = talloc_asprintf_append(p2, "o%c", 'd');
333         torture_assert("misc", strcmp("food", p2) == 0, 
334                                    "talloc_asprintf_append doesn't work\n");
335         CHECK_BLOCKS("misc", p2, 1);
336         CHECK_BLOCKS("misc", p1, 3);
337
338         p2 = talloc_asprintf_append(NULL, "hello %s", "world");
339         torture_assert("misc", strcmp("hello world", p2) == 0,
340                 "talloc_asprintf_append doesn't work\n");
341         CHECK_BLOCKS("misc", p2, 1);
342         CHECK_BLOCKS("misc", p1, 3);
343         talloc_free(p2);
344
345         d = talloc_array(p1, double, 0x20000000);
346         torture_assert("misc", !d, "failed: integer overflow not detected\n");
347
348         d = talloc_realloc(p1, d, double, 0x20000000);
349         torture_assert("misc", !d, "failed: integer overflow not detected\n");
350
351         talloc_free(p1);
352         CHECK_BLOCKS("misc", root, 1);
353
354         p1 = talloc_named(root, 100, "%d bytes", 100);
355         CHECK_BLOCKS("misc", p1, 2);
356         CHECK_BLOCKS("misc", root, 3);
357         talloc_unlink(root, p1);
358
359         p1 = talloc_init("%d bytes", 200);
360         p2 = talloc_asprintf(p1, "my test '%s'", "string");
361         torture_assert_str_equal("misc", p2, "my test 'string'",
362                 "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
363         CHECK_BLOCKS("misc", p1, 3);
364         CHECK_SIZE("misc", p2, 17);
365         CHECK_BLOCKS("misc", root, 1);
366         talloc_unlink(NULL, p1);
367
368         p1 = talloc_named_const(root, 10, "p1");
369         p2 = (char *)talloc_named_const(root, 20, "p2");
370         (void)talloc_reference(p1, p2);
371         talloc_unlink(root, p2);
372         CHECK_BLOCKS("misc", p2, 1);
373         CHECK_BLOCKS("misc", p1, 2);
374         CHECK_BLOCKS("misc", root, 3);
375         talloc_unlink(p1, p2);
376         talloc_unlink(root, p1);
377
378         p1 = talloc_named_const(root, 10, "p1");
379         p2 = (char *)talloc_named_const(root, 20, "p2");
380         (void)talloc_reference(NULL, p2);
381         talloc_unlink(root, p2);
382         CHECK_BLOCKS("misc", p2, 1);
383         CHECK_BLOCKS("misc", p1, 1);
384         CHECK_BLOCKS("misc", root, 2);
385         talloc_unlink(NULL, p2);
386         talloc_unlink(root, p1);
387
388         /* Test that talloc_unlink is a no-op */
389
390         torture_assert("misc", talloc_unlink(root, NULL) == -1,
391                 "failed: talloc_unlink(root, NULL) == -1\n");
392
393         CHECK_SIZE("misc", root, 0);
394
395         talloc_free(root);
396
397         CHECK_SIZE("misc", NULL, 0);
398
399         talloc_enable_leak_report();
400         talloc_enable_leak_report_full();
401
402         return true;
403 }
404
405
406 /*
407   test realloc
408 */
409 static bool test_realloc(const struct torture_context *ctx)
410 {
411         void *root, *p1, *p2;
412
413         root = talloc_new(ctx);
414
415         p1 = talloc_size(root, 10);
416         CHECK_SIZE("realloc", p1, 10);
417
418         p1 = talloc_realloc_size(NULL, p1, 20);
419         CHECK_SIZE("realloc", p1, 20);
420
421         talloc_new(p1);
422
423         p2 = talloc_realloc_size(p1, NULL, 30);
424
425         talloc_new(p1);
426
427         p2 = talloc_realloc_size(p1, p2, 40);
428
429         CHECK_SIZE("realloc", p2, 40);
430         CHECK_SIZE("realloc", root, 60);
431         CHECK_BLOCKS("realloc", p1, 4);
432
433         p1 = talloc_realloc_size(NULL, p1, 20);
434         CHECK_SIZE("realloc", p1, 60);
435
436         talloc_increase_ref_count(p2);
437         torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
438                 "failed: talloc_realloc() on a referenced pointer should fail\n");
439         CHECK_BLOCKS("realloc", p1, 4);
440
441         ok1(talloc_realloc_size(NULL, p2, 0) == NULL);
442         ok1(talloc_realloc_size(NULL, p2, 0) == NULL);
443         CHECK_BLOCKS("realloc", p1, 3);
444
445         torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
446                 "failed: oversize talloc should fail\n");
447
448         p1 = talloc_realloc_size(NULL, p1, 0);
449
450         CHECK_BLOCKS("realloc", root, 1);
451         CHECK_SIZE("realloc", root, 0);
452
453         talloc_free(root);
454
455         return true;
456 }
457
458 /*
459   test realloc with a child
460 */
461 static bool test_realloc_child(const struct torture_context *ctx)
462 {
463         void *root;
464         struct el2 {
465                 const char *name;
466         } *el2; 
467         struct el1 {
468                 int count;
469                 struct el2 **list, **list2, **list3;
470         } *el1;
471
472         root = talloc_new(ctx);
473
474         el1 = talloc(root, struct el1);
475         el1->list = talloc(el1, struct el2 *);
476         el1->list[0] = talloc(el1->list, struct el2);
477         el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
478
479         el1->list2 = talloc(el1, struct el2 *);
480         el1->list2[0] = talloc(el1->list2, struct el2);
481         el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
482
483         el1->list3 = talloc(el1, struct el2 *);
484         el1->list3[0] = talloc(el1->list3, struct el2);
485         el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
486         
487         el2 = talloc(el1->list, struct el2);
488         el2 = talloc(el1->list2, struct el2);
489         el2 = talloc(el1->list3, struct el2);
490
491         el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
492         el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
493         el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
494
495         talloc_free(root);
496
497         return true;
498 }
499
500 /*
501   test type checking
502 */
503 static bool test_type(const struct torture_context *ctx)
504 {
505         void *root;
506         struct el1 {
507                 int count;
508         };
509         struct el2 {
510                 int count;
511         };
512         struct el1 *el1;
513
514         root = talloc_new(ctx);
515
516         el1 = talloc(root, struct el1);
517
518         el1->count = 1;
519
520         torture_assert("type", talloc_get_type(el1, struct el1) == el1,
521                 "type check failed on el1\n");
522         torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
523                 "type check failed on el1 with el2\n");
524         talloc_set_type(el1, struct el2);
525         torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
526                 "type set failed on el1 with el2\n");
527
528         talloc_free(root);
529
530         return true;
531 }
532
533 /*
534   test steal
535 */
536 static bool test_steal(const struct torture_context *ctx)
537 {
538         void *root, *p1, *p2;
539
540         root = talloc_new(ctx);
541
542         p1 = talloc_array(root, char, 10);
543         CHECK_SIZE("steal", p1, 10);
544
545         p2 = talloc_realloc(root, NULL, char, 20);
546         CHECK_SIZE("steal", p1, 10);
547         CHECK_SIZE("steal", root, 30);
548
549         torture_assert("steal", talloc_steal(p1, NULL) == NULL,
550                 "failed: stealing NULL should give NULL\n");
551
552         torture_assert("steal", talloc_steal(p1, p1) == p1,
553                 "failed: stealing to ourselves is a nop\n");
554         CHECK_BLOCKS("steal", root, 3);
555         CHECK_SIZE("steal", root, 30);
556
557         talloc_steal(NULL, p1);
558         talloc_steal(NULL, p2);
559         CHECK_BLOCKS("steal", root, 1);
560         CHECK_SIZE("steal", root, 0);
561
562         talloc_free(p1);
563         talloc_steal(root, p2);
564         CHECK_BLOCKS("steal", root, 2);
565         CHECK_SIZE("steal", root, 20);
566         
567         talloc_free(p2);
568
569         CHECK_BLOCKS("steal", root, 1);
570         CHECK_SIZE("steal", root, 0);
571
572         talloc_free(root);
573
574         p1 = talloc_size(NULL, 3);
575         CHECK_SIZE("steal", NULL, 3);
576         talloc_free(p1);
577
578         return true;
579 }
580
581 /*
582   test move
583 */
584 static bool test_move(const struct torture_context *ctx)
585 {
586         void *root;
587         struct t_move {
588                 char *p;
589                 int *x;
590         } *t1, *t2;
591
592         root = talloc_new(ctx);
593
594         t1 = talloc(root, struct t_move);
595         t2 = talloc(root, struct t_move);
596         t1->p = talloc_strdup(t1, "foo");
597         t1->x = talloc(t1, int);
598         *t1->x = 42;
599
600         t2->p = talloc_move(t2, &t1->p);
601         t2->x = talloc_move(t2, &t1->x);
602         torture_assert("move", t1->p == NULL && t1->x == NULL &&
603             strcmp(t2->p, "foo") == 0 && *t2->x == 42,
604                 "talloc move failed");
605
606         talloc_free(root);
607
608         return true;
609 }
610
611 /*
612   test talloc_realloc_fn
613 */
614 static bool test_realloc_fn(const struct torture_context *ctx)
615 {
616         void *root, *p1;
617
618         root = talloc_new(ctx);
619
620         p1 = talloc_realloc_fn(root, NULL, 10);
621         CHECK_BLOCKS("realloc_fn", root, 2);
622         CHECK_SIZE("realloc_fn", root, 10);
623         p1 = talloc_realloc_fn(root, p1, 20);
624         CHECK_BLOCKS("realloc_fn", root, 2);
625         CHECK_SIZE("realloc_fn", root, 20);
626         p1 = talloc_realloc_fn(root, p1, 0);
627         CHECK_BLOCKS("realloc_fn", root, 1);
628         CHECK_SIZE("realloc_fn", root, 0);
629
630         talloc_free(root);
631
632         return true;
633 }
634
635
636 static bool test_unref_reparent(const struct torture_context *ctx)
637 {
638         void *root, *p1, *p2, *c1;
639
640         root = talloc_named_const(ctx, 0, "root");
641         p1 = talloc_named_const(root, 1, "orig parent");
642         p2 = talloc_named_const(root, 1, "parent by reference");
643
644         c1 = talloc_named_const(p1, 1, "child");
645         talloc_reference(p2, c1);
646
647         CHECK_PARENT("unref_reparent", c1, p1);
648
649         talloc_free(p1);
650
651         CHECK_PARENT("unref_reparent", c1, p2);
652
653         talloc_unlink(p2, c1);
654
655         CHECK_SIZE("unref_reparent", root, 1);
656
657         talloc_free(p2);
658         talloc_free(root);
659
660         return true;
661 }
662
663 static bool test_lifeless(const struct torture_context *ctx)
664 {
665         void *top = talloc_new(ctx);
666         char *parent, *child; 
667         void *child_owner = talloc_new(ctx);
668
669         parent = talloc_strdup(top, "parent");
670         child = talloc_strdup(parent, "child");  
671         (void)talloc_reference(child, parent);
672         (void)talloc_reference(child_owner, child); 
673         talloc_unlink(top, parent);
674         talloc_free(child);
675         talloc_free(top);
676         talloc_free(child_owner);
677         talloc_free(child);
678
679         return true;
680 }
681
682 static int loop_destructor_count;
683
684 static int test_loop_destructor(char *ptr)
685 {
686         loop_destructor_count++;
687         return 0;
688 }
689
690 static bool test_loop(const struct torture_context *ctx)
691 {
692         void *top = talloc_new(ctx);
693         char *parent;
694         struct req1 {
695                 char *req2, *req3;
696         } *req1;
697
698         parent = talloc_strdup(top, "parent");
699         req1 = talloc(parent, struct req1);
700         req1->req2 = talloc_strdup(req1, "req2");  
701         talloc_set_destructor(req1->req2, test_loop_destructor);
702         req1->req3 = talloc_strdup(req1, "req3");
703         (void)talloc_reference(req1->req3, req1);
704         talloc_free(parent);
705         talloc_free(top);
706
707         torture_assert("loop", loop_destructor_count == 1, 
708                                    "FAILED TO FIRE LOOP DESTRUCTOR\n");
709         loop_destructor_count = 0;
710
711         return true;
712 }
713
714 static int fail_destructor_str(char *ptr)
715 {
716         return -1;
717 }
718
719 static bool test_free_parent_deny_child(const struct torture_context *ctx)
720 {
721         void *top = talloc_new(ctx);
722         char *level1;
723         char *level2;
724         char *level3;
725
726         level1 = talloc_strdup(top, "level1");
727         level2 = talloc_strdup(level1, "level2");
728         level3 = talloc_strdup(level2, "level3");
729
730         talloc_set_destructor(level3, fail_destructor_str);
731         talloc_free(level1);
732         talloc_set_destructor(level3, NULL);
733
734         CHECK_PARENT("free_parent_deny_child", level3, top);
735
736         talloc_free(top);
737
738         return true;
739 }
740
741 static bool test_talloc_ptrtype(const struct torture_context *ctx)
742 {
743         void *top = talloc_new(ctx);
744         struct struct1 {
745                 int foo;
746                 int bar;
747         } *s1, *s2, **s3, ***s4;
748         const char *location1;
749         const char *location2;
750         const char *location3;
751         const char *location4;
752
753         s1 = talloc_ptrtype(top, s1);location1 = __location__;
754
755         ok1(talloc_get_size(s1) == sizeof(struct struct1));
756
757         ok1(strcmp(location1, talloc_get_name(s1)) == 0);
758
759         s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
760
761         ok1(talloc_get_size(s2) == (sizeof(struct struct1) * 10));
762
763         ok1(strcmp(location2, talloc_get_name(s2)) == 0);
764
765         s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
766
767         ok1(talloc_get_size(s3) == (sizeof(struct struct1 *) * 10));
768
769         torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
770                 "talloc_array_ptrtype() sets the wrong name");
771
772         s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
773
774         ok1(talloc_get_size(s4) == (sizeof(struct struct1 **) * 10));
775
776         torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
777                 "talloc_array_ptrtype() sets the wrong name");
778
779         talloc_free(top);
780
781         return true;
782 }
783
784 static bool test_talloc_free_in_destructor_run;
785 static int _test_talloc_free_in_destructor(void **ptr)
786 {
787         talloc_free(*ptr);
788         test_talloc_free_in_destructor_run = true;
789         return 0;
790 }
791
792 static bool test_talloc_free_in_destructor(const struct torture_context *ctx)
793 {
794         void *level0;
795         void *level1;
796         void *level2;
797         void *level3;
798         void *level4;
799         void **level5;
800
801         /* FIXME: Can't do nested destruction with locking, sorry. */
802         if (ctx)
803                 return true;
804
805         level0 = talloc_new(ctx);
806         level1 = talloc_new(level0);
807         level2 = talloc_new(level1);
808         level3 = talloc_new(level2);
809         level4 = talloc_new(level3);
810         level5 = talloc(level4, void *);
811
812         *level5 = talloc_reference(NULL, level3);
813
814         test_talloc_free_in_destructor_run = false;
815         talloc_set_destructor(level5, _test_talloc_free_in_destructor);
816
817         talloc_free(level1);
818
819         talloc_free(level0);
820
821         ok1(test_talloc_free_in_destructor_run);
822
823         return true;
824 }
825
826 static bool test_autofree(const struct torture_context *ctx)
827 {
828         /* autofree test would kill smbtorture */
829         void *p;
830         p = talloc_autofree_context();
831         talloc_free(p);
832
833         p = talloc_autofree_context();
834         talloc_free(p);
835
836         return true;
837 }
838
839 static bool torture_local_talloc(const struct torture_context *tctx)
840 {
841         bool ret = true;
842
843         setlinebuf(stdout);
844
845         talloc_disable_null_tracking();
846         talloc_enable_null_tracking();
847
848         ret &= test_ref1(tctx);
849         ret &= test_ref2(tctx);
850         ret &= test_ref3(tctx);
851         ret &= test_ref4(tctx);
852         ret &= test_unlink1(tctx); 
853         ret &= test_misc(tctx);
854         ret &= test_realloc(tctx);
855         ret &= test_realloc_child(tctx); 
856         ret &= test_steal(tctx);
857         ret &= test_move(tctx);
858         ret &= test_unref_reparent(tctx);
859         ret &= test_realloc_fn(tctx);
860         ret &= test_type(tctx);
861         ret &= test_lifeless(tctx);
862         ret &= test_loop(tctx);
863         ret &= test_free_parent_deny_child(tctx);
864         ret &= test_talloc_ptrtype(tctx);
865         ret &= test_talloc_free_in_destructor(tctx);
866         ret &= test_autofree(tctx);
867
868         return ret;
869 }
870
871 static int lock_failed = 0, unlock_failed = 0, lock_bad = 0;
872 static int locked;
873
874 #define MAX_ALLOCATIONS 100
875 static void *allocations[MAX_ALLOCATIONS];
876 static int num_allocs, num_frees, num_reallocs;
877
878 static unsigned int find_ptr(const void *p)
879 {
880         unsigned int i;
881
882         for (i = 0; i < MAX_ALLOCATIONS; i++)
883                 if (allocations[i] == p)
884                         break;
885         return i;
886 }
887
888 static unsigned int allocations_used(void)
889 {
890         unsigned int i, ret = 0;
891
892         for (i = 0; i < MAX_ALLOCATIONS; i++)
893                 if (allocations[i])
894                         ret++;
895         return ret;
896 }
897
898 static void test_lock(const void *ctx)
899 {
900         if (find_ptr(ctx) == MAX_ALLOCATIONS)
901                 lock_bad++;
902
903         if (locked)
904                 lock_failed++;
905         locked = 1;
906 }
907
908 static void test_unlock(void)
909 {
910         if (!locked)
911                 unlock_failed++;
912         locked = 0;
913 }
914
915 static int realloc_called, realloc_bad;
916
917 static void *normal_realloc(const void *parent, void *ptr, size_t size)
918 {
919         unsigned int i = find_ptr(ptr);
920
921         realloc_called++;
922         if (ptr && size)
923                 num_reallocs++;
924         else if (ptr)
925                 num_frees++;
926         else if (size)
927                 num_allocs++;
928         else
929                 abort();
930
931         if (i == MAX_ALLOCATIONS) {
932                 if (ptr) {
933                         realloc_bad++;
934                         i = find_ptr(NULL);
935                 } else
936                         abort();
937         }
938
939         allocations[i] = realloc(ptr, size);
940         /* Not guarenteed by realloc. */
941         if (!size)
942                 allocations[i] = NULL;
943
944         return allocations[i];
945 }
946
947 int main(void)
948 {
949         struct torture_context *ctx;
950
951         plan_tests(289);
952         ctx = talloc_add_external(NULL, normal_realloc, test_lock, test_unlock);
953
954         torture_local_talloc(NULL);
955         ok(!lock_bad, "%u locks on bad pointer", lock_bad);
956         ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
957         ok(!unlock_failed, "unlock_failed count %u should be zero",
958            unlock_failed);
959         ok(realloc_called == 1, "our realloc should not be called again");
960
961         torture_local_talloc(ctx);
962         ok(!lock_bad, "%u locks on bad pointer", lock_bad);
963         ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
964         ok(!unlock_failed, "unlock_failed count %u should be zero",
965            unlock_failed);
966         ok(realloc_called, "our realloc should be called");
967         ok(!realloc_bad, "our realloc given unknown pointer %u times",
968            realloc_bad);
969
970         talloc_free(ctx);
971         ok(!lock_bad, "%u locks on bad pointer", lock_bad);
972         ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
973         ok(!unlock_failed, "unlock_failed count %u should be zero",
974            unlock_failed);
975         ok(realloc_called, "our realloc should be called");
976         ok(!realloc_bad, "our realloc given unknown pointer %u times",
977            realloc_bad);
978
979         ok(allocations_used() == 0, "%u allocations still used?",
980            allocations_used());
981
982         /* This closes the leak, but make sure we're not freeing unexpected. */
983         ok1(!talloc_chunk_from_ptr(null_context)->child);
984         talloc_disable_null_tracking();
985         
986         return exit_status();
987 }
988