r4549: got rid of a lot more uses of plain talloc(), instead using
[samba.git] / source / lib / talloc / testsuite.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    local testing of talloc routines.
5
6    Copyright (C) Andrew Tridgell 2004
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef _SAMBA_BUILD_
24 #include "includes.h"
25 #else
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <sys/time.h>
31 #include <time.h>
32 #include "talloc.h"
33 #endif
34
35 /* the test suite can be built standalone, or as part of Samba */
36 #ifndef _SAMBA_BUILD_
37 typedef enum {False=0,True=1} BOOL;
38
39 static struct timeval timeval_current(void)
40 {
41         struct timeval tv;
42         gettimeofday(&tv, NULL);
43         return tv;
44 }
45
46 static double timeval_elapsed(struct timeval *tv)
47 {
48         struct timeval tv2 = timeval_current();
49         return (tv2.tv_sec - tv->tv_sec) + 
50                (tv2.tv_usec - tv->tv_usec)*1.0e-6;
51 }
52 #endif /* _SAMBA_BUILD_ */
53
54
55 #define CHECK_SIZE(ptr, tsize) do { \
56         if (talloc_total_size(ptr) != (tsize)) { \
57                 printf(__location__ " failed: wrong '%s' tree size: got %u  expected %u\n", \
58                        #ptr, \
59                        (unsigned)talloc_total_size(ptr), \
60                        (unsigned)tsize); \
61                 talloc_report_full(ptr, stdout); \
62                 return False; \
63         } \
64 } while (0)
65
66 #define CHECK_BLOCKS(ptr, tblocks) do { \
67         if (talloc_total_blocks(ptr) != (tblocks)) { \
68                 printf(__location__ " failed: wrong '%s' tree blocks: got %u  expected %u\n", \
69                        #ptr, \
70                        (unsigned)talloc_total_blocks(ptr), \
71                        (unsigned)tblocks); \
72                 talloc_report_full(ptr, stdout); \
73                 return False; \
74         } \
75 } while (0)
76
77
78 /*
79   test references 
80 */
81 static BOOL test_ref1(void)
82 {
83         void *root, *p1, *p2, *ref, *r1;
84
85         printf("TESTING SINGLE REFERENCE FREE\n");
86
87         root = talloc_named_const(NULL, 0, "root");
88         p1 = talloc_named_const(root, 1, "p1");
89         p2 = talloc_named_const(p1, 1, "p2");
90         talloc_named_const(p1, 1, "x1");
91         talloc_named_const(p1, 2, "x2");
92         talloc_named_const(p1, 3, "x3");
93
94         r1 = talloc_named_const(root, 1, "r1"); 
95         ref = talloc_reference(r1, p2);
96         talloc_report_full(root, stdout);
97
98         CHECK_BLOCKS(p1, 5);
99         CHECK_BLOCKS(p2, 1);
100         CHECK_BLOCKS(r1, 2);
101
102         printf("Freeing p2\n");
103         talloc_free(p2);
104         talloc_report_full(root, stdout);
105
106         CHECK_BLOCKS(p1, 5);
107         CHECK_BLOCKS(p2, 1);
108         CHECK_BLOCKS(r1, 1);
109
110         printf("Freeing p1\n");
111         talloc_free(p1);
112         talloc_report_full(root, stdout);
113
114         CHECK_BLOCKS(r1, 1);
115
116         printf("Freeing r1\n");
117         talloc_free(r1);
118         talloc_report_full(NULL, stdout);
119
120         printf("Testing NULL\n");
121         if (talloc_reference(root, NULL)) {
122                 return False;
123         }
124
125         CHECK_BLOCKS(root, 1);
126
127         CHECK_SIZE(root, 0);
128
129         talloc_free(root);
130
131         return True;
132 }
133
134 /*
135   test references 
136 */
137 static BOOL test_ref2(void)
138 {
139         void *root, *p1, *p2, *ref, *r1;
140
141         printf("TESTING DOUBLE REFERENCE FREE\n");
142
143         root = talloc_named_const(NULL, 0, "root");
144         p1 = talloc_named_const(root, 1, "p1");
145         talloc_named_const(p1, 1, "x1");
146         talloc_named_const(p1, 1, "x2");
147         talloc_named_const(p1, 1, "x3");
148         p2 = talloc_named_const(p1, 1, "p2");
149
150         r1 = talloc_named_const(root, 1, "r1"); 
151         ref = talloc_reference(r1, p2);
152         talloc_report_full(root, stdout);
153
154         CHECK_BLOCKS(p1, 5);
155         CHECK_BLOCKS(p2, 1);
156         CHECK_BLOCKS(r1, 2);
157
158         printf("Freeing ref\n");
159         talloc_free(ref);
160         talloc_report_full(root, stdout);
161
162         CHECK_BLOCKS(p1, 5);
163         CHECK_BLOCKS(p2, 1);
164         CHECK_BLOCKS(r1, 1);
165
166         printf("Freeing p2\n");
167         talloc_free(p2);
168         talloc_report_full(root, stdout);
169
170         CHECK_BLOCKS(p1, 4);
171         CHECK_BLOCKS(r1, 1);
172
173         printf("Freeing p1\n");
174         talloc_free(p1);
175         talloc_report_full(root, stdout);
176
177         CHECK_BLOCKS(r1, 1);
178
179         printf("Freeing r1\n");
180         talloc_free(r1);
181         talloc_report_full(root, stdout);
182
183         CHECK_SIZE(root, 0);
184
185         talloc_free(root);
186
187         return True;
188 }
189
190 /*
191   test references 
192 */
193 static BOOL test_ref3(void)
194 {
195         void *root, *p1, *p2, *ref, *r1;
196
197         printf("TESTING PARENT REFERENCE FREE\n");
198
199         root = talloc_named_const(NULL, 0, "root");
200         p1 = talloc_named_const(root, 1, "p1");
201         p2 = talloc_named_const(root, 1, "p2");
202         r1 = talloc_named_const(p1, 1, "r1");
203         ref = talloc_reference(p2, r1);
204         talloc_report_full(root, stdout);
205
206         CHECK_BLOCKS(p1, 2);
207         CHECK_BLOCKS(p2, 2);
208         CHECK_BLOCKS(r1, 1);
209
210         printf("Freeing p1\n");
211         talloc_free(p1);
212         talloc_report_full(root, stdout);
213
214         CHECK_BLOCKS(p2, 2);
215         CHECK_BLOCKS(r1, 1);
216
217         printf("Freeing p2\n");
218         talloc_free(p2);
219         talloc_report_full(root, stdout);
220
221         CHECK_SIZE(root, 0);
222
223         talloc_free(root);
224
225         return True;
226 }
227
228 /*
229   test references 
230 */
231 static BOOL test_ref4(void)
232 {
233         void *root, *p1, *p2, *ref, *r1;
234
235         printf("TESTING REFERRER REFERENCE FREE\n");
236
237         root = talloc_named_const(NULL, 0, "root");
238         p1 = talloc_named_const(root, 1, "p1");
239         talloc_named_const(p1, 1, "x1");
240         talloc_named_const(p1, 1, "x2");
241         talloc_named_const(p1, 1, "x3");
242         p2 = talloc_named_const(p1, 1, "p2");
243
244         r1 = talloc_named_const(root, 1, "r1"); 
245         ref = talloc_reference(r1, p2);
246         talloc_report_full(root, stdout);
247
248         CHECK_BLOCKS(p1, 5);
249         CHECK_BLOCKS(p2, 1);
250         CHECK_BLOCKS(r1, 2);
251
252         printf("Freeing r1\n");
253         talloc_free(r1);
254         talloc_report_full(root, stdout);
255
256         CHECK_BLOCKS(p1, 5);
257         CHECK_BLOCKS(p2, 1);
258
259         printf("Freeing p2\n");
260         talloc_free(p2);
261         talloc_report_full(root, stdout);
262
263         CHECK_BLOCKS(p1, 4);
264
265         printf("Freeing p1\n");
266         talloc_free(p1);
267         talloc_report_full(root, stdout);
268
269         CHECK_SIZE(root, 0);
270
271         talloc_free(root);
272
273         return True;
274 }
275
276
277 /*
278   test references 
279 */
280 static BOOL test_unlink1(void)
281 {
282         void *root, *p1, *p2, *ref, *r1;
283
284         printf("TESTING UNLINK\n");
285
286         root = talloc_named_const(NULL, 0, "root");
287         p1 = talloc_named_const(root, 1, "p1");
288         talloc_named_const(p1, 1, "x1");
289         talloc_named_const(p1, 1, "x2");
290         talloc_named_const(p1, 1, "x3");
291         p2 = talloc_named_const(p1, 1, "p2");
292
293         r1 = talloc_named_const(p1, 1, "r1");   
294         ref = talloc_reference(r1, p2);
295         talloc_report_full(root, stdout);
296
297         CHECK_BLOCKS(p1, 7);
298         CHECK_BLOCKS(p2, 1);
299         CHECK_BLOCKS(r1, 2);
300
301         printf("Unreferencing r1\n");
302         talloc_unlink(r1, p2);
303         talloc_report_full(root, stdout);
304
305         CHECK_BLOCKS(p1, 6);
306         CHECK_BLOCKS(p2, 1);
307         CHECK_BLOCKS(r1, 1);
308
309         printf("Freeing p1\n");
310         talloc_free(p1);
311         talloc_report_full(root, stdout);
312
313         CHECK_SIZE(root, 0);
314
315         talloc_free(root);
316
317         return True;
318 }
319
320 static int fail_destructor(void *ptr)
321 {
322         return -1;
323 }
324
325 /*
326   miscellaneous tests to try to get a higher test coverage percentage
327 */
328 static BOOL test_misc(void)
329 {
330         void *root, *p1;
331         char *p2;
332         double *d;
333
334         printf("TESTING MISCELLANEOUS\n");
335
336         root = talloc_new(NULL);
337
338         p1 = talloc_size(root, 0x7fffffff);
339         if (p1) {
340                 printf("failed: large talloc allowed\n");
341                 return False;
342         }
343
344         p1 = talloc_strdup(root, "foo");
345         talloc_increase_ref_count(p1);
346         talloc_increase_ref_count(p1);
347         talloc_increase_ref_count(p1);
348         CHECK_BLOCKS(p1, 1);
349         CHECK_BLOCKS(root, 2);
350         talloc_free(p1);
351         CHECK_BLOCKS(p1, 1);
352         CHECK_BLOCKS(root, 2);
353         talloc_unlink(NULL, p1);
354         CHECK_BLOCKS(p1, 1);
355         CHECK_BLOCKS(root, 2);
356         p2 = talloc_strdup(p1, "foo");
357         if (talloc_unlink(root, p2) != -1) {
358                 printf("failed: talloc_unlink() of non-reference context should return -1\n");
359                 return False;
360         }
361         if (talloc_unlink(p1, p2) != 0) {
362                 printf("failed: talloc_unlink() of parent should succeed\n");
363                 return False;
364         }
365         talloc_free(p1);
366         CHECK_BLOCKS(p1, 1);
367         CHECK_BLOCKS(root, 2);
368
369         talloc_set_name(p1, "my name is %s", "foo");
370         if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
371                 printf("failed: wrong name after talloc_set_name\n");
372                 return False;
373         }
374         CHECK_BLOCKS(p1, 2);
375         CHECK_BLOCKS(root, 3);
376
377         talloc_set_name_const(p1, NULL);
378         if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
379                 printf("failed: wrong name after talloc_set_name(NULL)\n");
380                 return False;
381         }
382         CHECK_BLOCKS(p1, 2);
383         CHECK_BLOCKS(root, 3);
384         
385
386         if (talloc_free(NULL) != -1) {
387                 printf("talloc_free(NULL) should give -1\n");
388                 return False;
389         }
390
391         talloc_set_destructor(p1, fail_destructor);
392         if (talloc_free(p1) != -1) {
393                 printf("Failed destructor should cause talloc_free to fail\n");
394                 return False;
395         }
396         talloc_set_destructor(p1, NULL);
397
398         talloc_report(root, stdout);
399
400
401         p2 = talloc_zero(p1, 20);
402         if (p2[19] != 0) {
403                 printf("Failed to give zero memory\n");
404                 return False;
405         }
406         talloc_free(p2);
407
408         if (talloc_strdup(root, NULL) != NULL) {
409                 printf("failed: strdup on NULL should give NULL\n");
410                 return False;
411         }
412
413         p2 = talloc_strndup(p1, "foo", 2);
414         if (strcmp("fo", p2) != 0) {
415                 printf("failed: strndup doesn't work\n");
416                 return False;
417         }
418         p2 = talloc_asprintf_append(p2, "o%c", 'd');
419         if (strcmp("food", p2) != 0) {
420                 printf("failed: talloc_asprintf_append doesn't work\n");
421                 return False;
422         }
423         CHECK_BLOCKS(p2, 1);
424         CHECK_BLOCKS(p1, 3);
425
426         p2 = talloc_asprintf_append(NULL, "hello %s", "world");
427         if (strcmp("hello world", p2) != 0) {
428                 printf("failed: talloc_asprintf_append doesn't work\n");
429                 return False;
430         }
431         CHECK_BLOCKS(p2, 1);
432         CHECK_BLOCKS(p1, 3);
433         talloc_free(p2);
434
435         d = talloc_array_p(p1, double, 0x20000000);
436         if (d) {
437                 printf("failed: integer overflow not detected\n");
438                 return False;
439         }
440
441         d = talloc_realloc_p(p1, d, double, 0x20000000);
442         if (d) {
443                 printf("failed: integer overflow not detected\n");
444                 return False;
445         }
446
447         talloc_free(p1);
448         CHECK_BLOCKS(root, 1);
449
450         p1 = talloc_named(root, 100, "%d bytes", 100);
451         CHECK_BLOCKS(p1, 2);
452         CHECK_BLOCKS(root, 3);
453         talloc_unlink(root, p1);
454
455         p1 = talloc_init("%d bytes", 200);
456         p2 = talloc_asprintf(p1, "my test '%s'", "string");
457         CHECK_BLOCKS(p1, 3);
458         CHECK_SIZE(p2, 17);
459         CHECK_BLOCKS(root, 1);
460         talloc_unlink(NULL, p1);
461
462         p1 = talloc_named_const(root, 10, "p1");
463         p2 = talloc_named_const(root, 20, "p2");
464         talloc_reference(p1, p2);
465         talloc_report_full(root, stdout);
466         talloc_unlink(root, p2);
467         talloc_report_full(root, stdout);
468         CHECK_BLOCKS(p2, 1);
469         CHECK_BLOCKS(p1, 2);
470         CHECK_BLOCKS(root, 3);
471         talloc_unlink(p1, p2);
472         talloc_unlink(root, p1);
473
474         p1 = talloc_named_const(root, 10, "p1");
475         p2 = talloc_named_const(root, 20, "p2");
476         talloc_reference(NULL, p2);
477         talloc_report_full(root, stdout);
478         talloc_unlink(root, p2);
479         talloc_report_full(root, stdout);
480         CHECK_BLOCKS(p2, 1);
481         CHECK_BLOCKS(p1, 1);
482         CHECK_BLOCKS(root, 2);
483         talloc_unlink(NULL, p2);
484         talloc_unlink(root, p1);
485
486         /* Test that talloc_unlink is a no-op */
487
488         if (talloc_unlink(root, NULL) != -1) {
489                 printf("failed: talloc_unlink(root, NULL) == -1\n");
490                 return False;
491         }
492
493         talloc_report(root, stdout);
494         talloc_report(NULL, stdout);
495
496         CHECK_SIZE(root, 0);
497
498         talloc_free(root);
499
500         CHECK_SIZE(NULL, 0);
501
502         talloc_enable_leak_report();
503         talloc_enable_leak_report_full();
504
505         return True;
506 }
507
508
509 /*
510   test realloc
511 */
512 static BOOL test_realloc(void)
513 {
514         void *root, *p1, *p2;
515
516         printf("TESTING REALLOC\n");
517
518         root = talloc_new(NULL);
519
520         p1 = talloc_size(root, 10);
521         CHECK_SIZE(p1, 10);
522
523         p1 = talloc_realloc(NULL, p1, 20);
524         CHECK_SIZE(p1, 20);
525
526         talloc(p1, 0);
527
528         p2 = talloc_realloc(p1, NULL, 30);
529
530         talloc(p1, 0);
531
532         p2 = talloc_realloc(p1, p2, 40);
533
534         CHECK_SIZE(p2, 40);
535         CHECK_SIZE(root, 60);
536         CHECK_BLOCKS(p1, 4);
537
538         p1 = talloc_realloc(NULL, p1, 20);
539         CHECK_SIZE(p1, 60);
540
541         talloc_increase_ref_count(p2);
542         if (talloc_realloc(NULL, p2, 5) != NULL) {
543                 printf("failed: talloc_realloc() on a referenced pointer should fail\n");
544                 return False;
545         }
546         CHECK_BLOCKS(p1, 4);
547
548         talloc_realloc(NULL, p2, 0);
549         talloc_realloc(NULL, p2, 0);
550         CHECK_BLOCKS(p1, 3);
551
552         if (talloc_realloc(NULL, p1, 0x7fffffff) != NULL) {
553                 printf("failed: oversize talloc should fail\n");
554                 return False;
555         }
556
557         talloc_realloc(NULL, p1, 0);
558
559         CHECK_BLOCKS(root, 1);
560         CHECK_SIZE(root, 0);
561
562         talloc_free(root);
563
564         return True;
565 }
566
567
568 /*
569   test realloc with a child
570 */
571 static BOOL test_realloc_child(void)
572 {
573         void *root;
574         struct el1 {
575                 int count;
576                 struct el2 {
577                         const char *name;
578                 } **list;
579         } *el1;
580         struct el2 *el2;
581
582         printf("TESTING REALLOC WITH CHILD\n");
583
584         root = talloc_new(NULL);
585
586         el1 = talloc_p(root, struct el1);
587         el1->list = talloc_p(el1, struct el2 *);
588         el1->list[0] = talloc_p(el1->list, struct el2);
589         el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
590         
591         el2 = talloc_p(el1->list, struct el2);
592
593         el1->list = talloc_realloc_p(el1, el1->list, struct el2 *, 2);
594         el1->list[1] = el2;
595
596         talloc_free(root);
597
598         return True;
599 }
600
601 /*
602   test steal
603 */
604 static BOOL test_steal(void)
605 {
606         void *root, *p1, *p2;
607
608         printf("TESTING STEAL\n");
609
610         root = talloc_new(NULL);
611
612         p1 = talloc_array_p(root, char, 10);
613         CHECK_SIZE(p1, 10);
614
615         p2 = talloc_realloc_p(root, NULL, char, 20);
616         CHECK_SIZE(p1, 10);
617         CHECK_SIZE(root, 30);
618
619         if (talloc_steal(p1, NULL) != NULL) {
620                 printf("failed: stealing NULL should give NULL\n");
621                 return False;
622         }
623
624         if (talloc_steal(p1, p1) != p1) {
625                 printf("failed: stealing to ourselves is a nop\n");
626                 return False;
627         }
628         CHECK_BLOCKS(root, 3);
629         CHECK_SIZE(root, 30);
630
631         talloc_steal(NULL, p1);
632         talloc_steal(NULL, p2);
633         CHECK_BLOCKS(root, 1);
634         CHECK_SIZE(root, 0);
635
636         talloc_free(p1);
637         talloc_steal(root, p2);
638         CHECK_BLOCKS(root, 2);
639         CHECK_SIZE(root, 20);
640         
641         talloc_free(p2);
642
643         CHECK_BLOCKS(root, 1);
644         CHECK_SIZE(root, 0);
645
646         talloc_free(root);
647
648         p1 = talloc_new(NULL);
649         CHECK_SIZE(NULL, 3);
650         talloc_free(p1);
651
652         return True;
653 }
654
655 /*
656   test ldb alloc fn
657 */
658 static BOOL test_ldb(void)
659 {
660         void *root, *p1;
661
662         printf("TESTING LDB\n");
663
664         root = talloc_new(NULL);
665
666         p1 = talloc_realloc_fn(root, NULL, 10);
667         CHECK_BLOCKS(root, 2);
668         CHECK_SIZE(root, 10);
669         p1 = talloc_realloc_fn(root, p1, 20);
670         CHECK_BLOCKS(root, 2);
671         CHECK_SIZE(root, 20);
672         p1 = talloc_realloc_fn(root, p1, 0);
673         CHECK_BLOCKS(root, 1);
674         CHECK_SIZE(root, 0);
675
676         talloc_free(root);
677
678
679         return True;
680 }
681
682
683 static BOOL test_unref_reparent(void)
684 {
685         void *root, *p1, *p2, *c1;
686
687         printf("TESTING UNREFERENCE AFTER PARENT FREED\n");
688
689         root = talloc_named_const(NULL, 0, "root");
690         p1 = talloc_named_const(root, 1, "orig parent");
691         p2 = talloc_named_const(root, 1, "parent by reference");
692
693         c1 = talloc_named_const(p1, 1, "child");
694         talloc_reference(p2, c1);
695
696         talloc_free(p1);
697         talloc_unlink(p2, c1);
698
699         CHECK_SIZE(root, 1);
700
701         talloc_free(p2);
702         talloc_free(root);
703
704         return True;
705 }
706
707 /*
708   measure the speed of talloc versus malloc
709 */
710 static BOOL test_speed(void)
711 {
712         void *ctx = talloc_new(NULL);
713         unsigned count;
714         struct timeval tv;
715
716         printf("MEASURING TALLOC VS MALLOC SPEED\n");
717
718         tv = timeval_current();
719         count = 0;
720         do {
721                 void *p1, *p2, *p3;
722                 p1 = talloc_size(ctx, count);
723                 p2 = talloc_strdup(p1, "foo bar");
724                 p3 = talloc_size(p1, 300);
725                 talloc_free(p1);
726                 count += 3;
727         } while (timeval_elapsed(&tv) < 5.0);
728
729         printf("talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
730
731         talloc_free(ctx);
732
733         tv = timeval_current();
734         count = 0;
735         do {
736                 void *p1, *p2, *p3;
737                 p1 = malloc(count);
738                 p2 = strdup("foo bar");
739                 p3 = malloc(300);
740                 free(p1);
741                 free(p2);
742                 free(p3);
743                 count += 3;
744         } while (timeval_elapsed(&tv) < 5.0);
745
746         printf("malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
747
748         return True;    
749 }
750
751
752 BOOL torture_local_talloc(void) 
753 {
754         BOOL ret = True;
755
756         ret &= test_ref1();
757         ret &= test_ref2();
758         ret &= test_ref3();
759         ret &= test_ref4();
760         ret &= test_unlink1();
761         ret &= test_misc();
762         ret &= test_realloc();
763         ret &= test_realloc_child();
764         ret &= test_steal();
765         ret &= test_unref_reparent();
766         ret &= test_ldb();
767         if (ret) {
768                 ret &= test_speed();
769         }
770
771         return ret;
772 }
773
774
775
776 #ifndef _SAMBA_BUILD_
777  int main(void)
778 {
779         if (!torture_local_talloc()) {
780                 printf("ERROR: TESTSUIE FAILED\n");
781                 return -1;
782         }
783         return 0;
784 }
785 #endif