348b037753adb200557659ada5a38e5faf3f4366
[samba.git] / source4 / torture / local / talloc.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 _STANDALONE_
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include "talloc.h"
31 #else
32 #include "includes.h"
33 #endif
34
35 /* the test suite can be built standalone, or as part of Samba */
36 #ifdef _STANDALONE_
37 typedef enum {False=0,True=1} BOOL;
38
39 static struct timeval current_time(void)
40 {
41         struct timeval tv;
42         GetTimeOfDay(&tv);
43         return tv;
44 }
45
46 static double elapsed_time(struct timeval *tv)
47 {
48         struct timeval tv2 = current_time();
49         return (tv2.tv_sec - tv->tv_sec) + 
50                (tv2.tv_usec - tv->tv_usec)*1.0e-6;
51 }
52 #endif /* _STANDALONE_ */
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         CHECK_BLOCKS(root, 1);
121
122         CHECK_SIZE(root, 0);
123
124         talloc_free(root);
125
126         return True;
127 }
128
129 /*
130   test references 
131 */
132 static BOOL test_ref2(void)
133 {
134         void *root, *p1, *p2, *ref, *r1;
135
136         printf("TESTING DOUBLE REFERENCE FREE\n");
137
138         root = talloc_named_const(NULL, 0, "root");
139         p1 = talloc_named_const(root, 1, "p1");
140         talloc_named_const(p1, 1, "x1");
141         talloc_named_const(p1, 1, "x2");
142         talloc_named_const(p1, 1, "x3");
143         p2 = talloc_named_const(p1, 1, "p2");
144
145         r1 = talloc_named_const(root, 1, "r1"); 
146         ref = talloc_reference(r1, p2);
147         talloc_report_full(root, stdout);
148
149         CHECK_BLOCKS(p1, 5);
150         CHECK_BLOCKS(p2, 1);
151         CHECK_BLOCKS(r1, 2);
152
153         printf("Freeing ref\n");
154         talloc_free(ref);
155         talloc_report_full(root, stdout);
156
157         CHECK_BLOCKS(p1, 5);
158         CHECK_BLOCKS(p2, 1);
159         CHECK_BLOCKS(r1, 1);
160
161         printf("Freeing p2\n");
162         talloc_free(p2);
163         talloc_report_full(root, stdout);
164
165         CHECK_BLOCKS(p1, 4);
166         CHECK_BLOCKS(r1, 1);
167
168         printf("Freeing p1\n");
169         talloc_free(p1);
170         talloc_report_full(root, stdout);
171
172         CHECK_BLOCKS(r1, 1);
173
174         printf("Freeing r1\n");
175         talloc_free(r1);
176         talloc_report_full(root, stdout);
177
178         CHECK_SIZE(root, 0);
179
180         talloc_free(root);
181
182         return True;
183 }
184
185 /*
186   test references 
187 */
188 static BOOL test_ref3(void)
189 {
190         void *root, *p1, *p2, *ref, *r1;
191
192         printf("TESTING PARENT REFERENCE FREE\n");
193
194         root = talloc_named_const(NULL, 0, "root");
195         p1 = talloc_named_const(root, 1, "p1");
196         p2 = talloc_named_const(root, 1, "p2");
197         r1 = talloc_named_const(p1, 1, "r1");
198         ref = talloc_reference(p2, r1);
199         talloc_report_full(root, stdout);
200
201         CHECK_BLOCKS(p1, 2);
202         CHECK_BLOCKS(p2, 2);
203         CHECK_BLOCKS(r1, 1);
204
205         printf("Freeing p1\n");
206         talloc_free(p1);
207         talloc_report_full(root, stdout);
208
209         CHECK_BLOCKS(p2, 2);
210         CHECK_BLOCKS(r1, 1);
211
212         printf("Freeing p2\n");
213         talloc_free(p2);
214         talloc_report_full(root, stdout);
215
216         CHECK_SIZE(root, 0);
217
218         talloc_free(root);
219
220         return True;
221 }
222
223 /*
224   test references 
225 */
226 static BOOL test_ref4(void)
227 {
228         void *root, *p1, *p2, *ref, *r1;
229
230         printf("TESTING REFERRER REFERENCE FREE\n");
231
232         root = talloc_named_const(NULL, 0, "root");
233         p1 = talloc_named_const(root, 1, "p1");
234         talloc_named_const(p1, 1, "x1");
235         talloc_named_const(p1, 1, "x2");
236         talloc_named_const(p1, 1, "x3");
237         p2 = talloc_named_const(p1, 1, "p2");
238
239         r1 = talloc_named_const(root, 1, "r1"); 
240         ref = talloc_reference(r1, p2);
241         talloc_report_full(root, stdout);
242
243         CHECK_BLOCKS(p1, 5);
244         CHECK_BLOCKS(p2, 1);
245         CHECK_BLOCKS(r1, 2);
246
247         printf("Freeing r1\n");
248         talloc_free(r1);
249         talloc_report_full(root, stdout);
250
251         CHECK_BLOCKS(p1, 5);
252         CHECK_BLOCKS(p2, 1);
253
254         printf("Freeing p2\n");
255         talloc_free(p2);
256         talloc_report_full(root, stdout);
257
258         CHECK_BLOCKS(p1, 4);
259
260         printf("Freeing p1\n");
261         talloc_free(p1);
262         talloc_report_full(root, stdout);
263
264         CHECK_SIZE(root, 0);
265
266         talloc_free(root);
267
268         return True;
269 }
270
271
272 /*
273   test references 
274 */
275 static BOOL test_unlink1(void)
276 {
277         void *root, *p1, *p2, *ref, *r1;
278
279         printf("TESTING UNLINK\n");
280
281         root = talloc_named_const(NULL, 0, "root");
282         p1 = talloc_named_const(root, 1, "p1");
283         talloc_named_const(p1, 1, "x1");
284         talloc_named_const(p1, 1, "x2");
285         talloc_named_const(p1, 1, "x3");
286         p2 = talloc_named_const(p1, 1, "p2");
287
288         r1 = talloc_named_const(p1, 1, "r1");   
289         ref = talloc_reference(r1, p2);
290         talloc_report_full(root, stdout);
291
292         CHECK_BLOCKS(p1, 7);
293         CHECK_BLOCKS(p2, 1);
294         CHECK_BLOCKS(r1, 2);
295
296         printf("Unreferencing r1\n");
297         talloc_unlink(r1, p2);
298         talloc_report_full(root, stdout);
299
300         CHECK_BLOCKS(p1, 6);
301         CHECK_BLOCKS(p2, 1);
302         CHECK_BLOCKS(r1, 1);
303
304         printf("Freeing p1\n");
305         talloc_free(p1);
306         talloc_report_full(root, stdout);
307
308         CHECK_SIZE(root, 0);
309
310         talloc_free(root);
311
312         return True;
313 }
314
315 static int fail_destructor(void *ptr)
316 {
317         return -1;
318 }
319
320 /*
321   miscellaneous tests to try to get a higher test coverage percentage
322 */
323 static BOOL test_misc(void)
324 {
325         void *root, *p1;
326         char *p2;
327         double *d;
328
329         printf("TESTING MISCELLANEOUS\n");
330
331         root = talloc(NULL, 0);
332
333         p1 = talloc(root, 0x7fffffff);
334         if (p1) {
335                 printf("failed: large talloc allowed\n");
336                 return False;
337         }
338
339         p1 = talloc_strdup(root, "foo");
340         talloc_increase_ref_count(p1);
341         talloc_increase_ref_count(p1);
342         talloc_increase_ref_count(p1);
343         CHECK_BLOCKS(p1, 1);
344         CHECK_BLOCKS(root, 2);
345         talloc_free(p1);
346         CHECK_BLOCKS(p1, 1);
347         CHECK_BLOCKS(root, 2);
348         talloc_unlink(NULL, p1);
349         CHECK_BLOCKS(p1, 1);
350         CHECK_BLOCKS(root, 2);
351         p2 = talloc_strdup(p1, "foo");
352         if (talloc_unlink(root, p2) != -1) {
353                 printf("failed: talloc_unlink() of non-reference context should return -1\n");
354                 return False;
355         }
356         if (talloc_unlink(p1, p2) != 0) {
357                 printf("failed: talloc_unlink() of parent should succeed\n");
358                 return False;
359         }
360         talloc_free(p1);
361         CHECK_BLOCKS(p1, 1);
362         CHECK_BLOCKS(root, 2);
363
364         talloc_set_name(p1, "my name is %s", "foo");
365         if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
366                 printf("failed: wrong name after talloc_set_name\n");
367                 return False;
368         }
369         CHECK_BLOCKS(p1, 2);
370         CHECK_BLOCKS(root, 3);
371
372         talloc_set_name_const(p1, NULL);
373         if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
374                 printf("failed: wrong name after talloc_set_name(NULL)\n");
375                 return False;
376         }
377         CHECK_BLOCKS(p1, 2);
378         CHECK_BLOCKS(root, 3);
379         
380
381         if (talloc_free(NULL) != -1) {
382                 printf("talloc_free(NULL) should give -1\n");
383                 return False;
384         }
385
386         talloc_set_destructor(p1, fail_destructor);
387         if (talloc_free(p1) != -1) {
388                 printf("Failed destructor should cause talloc_free to fail\n");
389                 return False;
390         }
391         talloc_set_destructor(p1, NULL);
392
393         talloc_report(root, stdout);
394
395
396         p2 = talloc_zero(p1, 20);
397         if (p2[19] != 0) {
398                 printf("Failed to give zero memory\n");
399                 return False;
400         }
401         talloc_free(p2);
402
403         if (talloc_strdup(root, NULL) != NULL) {
404                 printf("failed: strdup on NULL should give NULL\n");
405                 return False;
406         }
407
408         p2 = talloc_strndup(p1, "foo", 2);
409         if (strcmp("fo", p2) != 0) {
410                 printf("failed: strndup doesn't work\n");
411                 return False;
412         }
413         p2 = talloc_asprintf_append(p2, "o%c", 'd');
414         if (strcmp("food", p2) != 0) {
415                 printf("failed: talloc_asprintf_append doesn't work\n");
416                 return False;
417         }
418         CHECK_BLOCKS(p2, 1);
419         CHECK_BLOCKS(p1, 3);
420
421         p2 = talloc_asprintf_append(NULL, "hello %s", "world");
422         if (strcmp("hello world", p2) != 0) {
423                 printf("failed: talloc_asprintf_append doesn't work\n");
424                 return False;
425         }
426         CHECK_BLOCKS(p2, 1);
427         CHECK_BLOCKS(p1, 3);
428         talloc_free(p2);
429
430         d = talloc_array_p(p1, double, 0x20000000);
431         if (d) {
432                 printf("failed: integer overflow not detected\n");
433                 return False;
434         }
435
436         d = talloc_realloc_p(p1, d, double, 0x20000000);
437         if (d) {
438                 printf("failed: integer overflow not detected\n");
439                 return False;
440         }
441
442         talloc_free(p1);
443         CHECK_BLOCKS(root, 1);
444
445         p1 = talloc_named(root, 100, "%d bytes", 100);
446         CHECK_BLOCKS(p1, 2);
447         CHECK_BLOCKS(root, 3);
448         talloc_unlink(root, p1);
449
450         p1 = talloc_init("%d bytes", 200);
451         p2 = talloc_asprintf(p1, "my test '%s'", "string");
452         CHECK_BLOCKS(p1, 3);
453         CHECK_SIZE(p2, 17);
454         CHECK_BLOCKS(root, 1);
455         talloc_unlink(NULL, p1);
456
457         p1 = talloc_named_const(root, 10, "p1");
458         p2 = talloc_named_const(root, 20, "p2");
459         talloc_reference(p1, p2);
460         talloc_report_full(root, stdout);
461         talloc_unlink(root, p2);
462         talloc_report_full(root, stdout);
463         CHECK_BLOCKS(p2, 1);
464         CHECK_BLOCKS(p1, 2);
465         CHECK_BLOCKS(root, 3);
466         talloc_unlink(p1, p2);
467         talloc_unlink(root, p1);
468
469         p1 = talloc_named_const(root, 10, "p1");
470         p2 = talloc_named_const(root, 20, "p2");
471         talloc_reference(NULL, p2);
472         talloc_report_full(root, stdout);
473         talloc_unlink(root, p2);
474         talloc_report_full(root, stdout);
475         CHECK_BLOCKS(p2, 1);
476         CHECK_BLOCKS(p1, 1);
477         CHECK_BLOCKS(root, 2);
478         talloc_unlink(NULL, p2);
479         talloc_unlink(root, p1);
480
481         
482
483         talloc_report(root, stdout);
484         talloc_report(NULL, stdout);
485
486         CHECK_SIZE(root, 0);
487
488         talloc_free(root);
489
490         CHECK_SIZE(NULL, 0);
491
492         talloc_enable_leak_report();
493         talloc_enable_leak_report_full();
494
495         return True;
496 }
497
498
499 /*
500   test realloc
501 */
502 static BOOL test_realloc(void)
503 {
504         void *root, *p1, *p2;
505
506         printf("TESTING REALLOC\n");
507
508         root = talloc(NULL, 0);
509
510         p1 = talloc(root, 10);
511         CHECK_SIZE(p1, 10);
512
513         p1 = talloc_realloc(NULL, p1, 20);
514         CHECK_SIZE(p1, 20);
515
516         talloc(p1, 0);
517
518         p2 = talloc_realloc(p1, NULL, 30);
519
520         talloc(p1, 0);
521
522         p2 = talloc_realloc(p1, p2, 40);
523
524         CHECK_SIZE(p2, 40);
525         CHECK_SIZE(root, 60);
526         CHECK_BLOCKS(p1, 4);
527
528         p1 = talloc_realloc(NULL, p1, 20);
529         CHECK_SIZE(p1, 60);
530
531         talloc_increase_ref_count(p2);
532         if (talloc_realloc(NULL, p2, 5) != NULL) {
533                 printf("failed: talloc_realloc() on a referenced pointer should fail\n");
534                 return False;
535         }
536         CHECK_BLOCKS(p1, 4);
537
538         talloc_realloc(NULL, p2, 0);
539         talloc_realloc(NULL, p2, 0);
540         CHECK_BLOCKS(p1, 3);
541
542         if (talloc_realloc(NULL, p1, 0x7fffffff) != NULL) {
543                 printf("failed: oversize talloc should fail\n");
544                 return False;
545         }
546
547         talloc_realloc(NULL, p1, 0);
548
549         CHECK_BLOCKS(root, 1);
550         CHECK_SIZE(root, 0);
551
552         talloc_free(root);
553
554         return True;
555 }
556
557 /*
558   test steal
559 */
560 static BOOL test_steal(void)
561 {
562         void *root, *p1, *p2;
563
564         printf("TESTING STEAL\n");
565
566         root = talloc(NULL, 0);
567
568         p1 = talloc_array_p(root, char, 10);
569         CHECK_SIZE(p1, 10);
570
571         p2 = talloc_realloc_p(root, NULL, char, 20);
572         CHECK_SIZE(p1, 10);
573         CHECK_SIZE(root, 30);
574
575         if (talloc_steal(p1, NULL) != NULL) {
576                 printf("failed: stealing NULL should give NULL\n");
577                 return False;
578         }
579
580         if (talloc_steal(p1, p1) != p1) {
581                 printf("failed: stealing to ourselves is a nop\n");
582                 return False;
583         }
584         CHECK_BLOCKS(root, 3);
585         CHECK_SIZE(root, 30);
586
587         talloc_steal(NULL, p1);
588         talloc_steal(NULL, p2);
589         CHECK_BLOCKS(root, 1);
590         CHECK_SIZE(root, 0);
591
592         talloc_free(p1);
593         talloc_steal(root, p2);
594         CHECK_BLOCKS(root, 2);
595         CHECK_SIZE(root, 20);
596         
597         talloc_free(p2);
598
599         CHECK_BLOCKS(root, 1);
600         CHECK_SIZE(root, 0);
601
602         talloc_free(root);
603
604         p1 = talloc(NULL, 3);
605         CHECK_SIZE(NULL, 3);
606         talloc_free(p1);
607
608         return True;
609 }
610
611 /*
612   test ldb alloc fn
613 */
614 static BOOL test_ldb(void)
615 {
616         void *root, *p1;
617
618         printf("TESTING LDB\n");
619
620         root = talloc(NULL, 0);
621
622         p1 = talloc_realloc_fn(root, NULL, 10);
623         CHECK_BLOCKS(root, 2);
624         CHECK_SIZE(root, 10);
625         p1 = talloc_realloc_fn(root, p1, 20);
626         CHECK_BLOCKS(root, 2);
627         CHECK_SIZE(root, 20);
628         p1 = talloc_realloc_fn(root, p1, 0);
629         CHECK_BLOCKS(root, 1);
630         CHECK_SIZE(root, 0);
631
632         talloc_free(root);
633
634
635         return True;
636 }
637
638 /*
639   measure the speed of talloc versus malloc
640 */
641 static BOOL test_speed(void)
642 {
643         void *ctx = talloc(NULL, 0);
644         unsigned count;
645         struct timeval tv;
646
647         printf("MEASURING TALLOC VS MALLOC SPEED\n");
648
649         tv = timeval_current();
650         count = 0;
651         do {
652                 void *p1, *p2, *p3;
653                 p1 = talloc(ctx, count);
654                 p2 = talloc_strdup(p1, "foo bar");
655                 p3 = talloc(p1, 300);
656                 talloc_free(p1);
657                 count += 3;
658         } while (timeval_elapsed(&tv) < 5.0);
659
660         printf("talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
661
662         talloc_free(ctx);
663
664         tv = timeval_current();
665         count = 0;
666         do {
667                 void *p1, *p2, *p3;
668                 p1 = malloc(count);
669                 p2 = strdup("foo bar");
670                 p3 = malloc(300);
671                 free(p1);
672                 free(p2);
673                 free(p3);
674                 count += 3;
675         } while (timeval_elapsed(&tv) < 5.0);
676
677         printf("malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
678
679         return True;    
680 }
681
682
683 BOOL torture_local_talloc(void) 
684 {
685         BOOL ret = True;
686
687         ret &= test_ref1();
688         ret &= test_ref2();
689         ret &= test_ref3();
690         ret &= test_ref4();
691         ret &= test_unlink1();
692         ret &= test_misc();
693         ret &= test_realloc();
694         ret &= test_steal();
695         ret &= test_ldb();
696         if (ret) {
697                 ret &= test_speed();
698         }
699
700         return ret;
701 }
702
703
704
705 #ifdef _STANDALONE_
706 int main(void)
707 {
708         if (!torture_local_talloc(0)) {
709                 printf("ERROR: TESTSUIE FAILED\n");
710                 return -1;
711         }
712         return 0;
713 }
714 #endif
715