r2744: ben elliston taught me about gcov today, which allows you to measure
[bbaumbach/samba-autobuild/.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 #include "includes.h"
24
25 #define CHECK_BLOCKS(ptr, tblocks) do { \
26         if (talloc_total_blocks(ptr) != (tblocks)) { \
27                 printf(__location__ " failed: wrong '%s' tree blocks: got %u  expected %u\n", \
28                        #ptr, \
29                        (unsigned)talloc_total_blocks(ptr), \
30                        (unsigned)tblocks); \
31                 talloc_report_full(ptr, stdout); \
32                 return False; \
33         } \
34 } while (0)
35
36 #define CHECK_SIZE(ptr, tsize) do { \
37         if (talloc_total_size(ptr) != (tsize)) { \
38                 printf(__location__ " failed: wrong '%s' tree size: got %u  expected %u\n", \
39                        #ptr, \
40                        (unsigned)talloc_total_size(ptr), \
41                        (unsigned)tsize); \
42                 talloc_report_full(ptr, stdout); \
43                 return False; \
44         } \
45 } while (0)
46
47 /*
48   test references 
49 */
50 static BOOL test_ref1(void)
51 {
52         void *root, *p1, *p2, *ref, *r1;
53
54         printf("TESTING SINGLE REFERENCE FREE\n");
55
56         root = talloc_named_const(NULL, 0, "root");
57         p1 = talloc_named_const(root, 1, "p1");
58         p2 = talloc_named_const(p1, 1, "p2");
59         talloc_named_const(p1, 1, "x1");
60         talloc_named_const(p1, 2, "x2");
61         talloc_named_const(p1, 3, "x3");
62
63         r1 = talloc_named_const(root, 1, "r1"); 
64         ref = talloc_reference(r1, p2);
65         talloc_report_full(root, stdout);
66
67         CHECK_BLOCKS(p1, 5);
68         CHECK_BLOCKS(p2, 1);
69         CHECK_BLOCKS(r1, 2);
70
71         printf("Freeing p2\n");
72         talloc_free(p2);
73         talloc_report_full(root, stdout);
74
75         CHECK_BLOCKS(p1, 5);
76         CHECK_BLOCKS(p2, 1);
77         CHECK_BLOCKS(r1, 1);
78
79         printf("Freeing p1\n");
80         talloc_free(p1);
81         talloc_report_full(root, stdout);
82
83         CHECK_BLOCKS(r1, 1);
84
85         printf("Freeing r1\n");
86         talloc_free(r1);
87         talloc_report_full(NULL, stdout);
88
89         CHECK_BLOCKS(root, 1);
90
91         CHECK_SIZE(root, 0);
92
93         talloc_free(root);
94
95         return True;
96 }
97
98 /*
99   test references 
100 */
101 static BOOL test_ref2(void)
102 {
103         void *root, *p1, *p2, *ref, *r1;
104
105         printf("TESTING DOUBLE REFERENCE FREE\n");
106
107         root = talloc_named_const(NULL, 0, "root");
108         p1 = talloc_named_const(root, 1, "p1");
109         talloc_named_const(p1, 1, "x1");
110         talloc_named_const(p1, 1, "x2");
111         talloc_named_const(p1, 1, "x3");
112         p2 = talloc_named_const(p1, 1, "p2");
113
114         r1 = talloc_named_const(root, 1, "r1"); 
115         ref = talloc_reference(r1, p2);
116         talloc_report_full(root, stdout);
117
118         CHECK_BLOCKS(p1, 5);
119         CHECK_BLOCKS(p2, 1);
120         CHECK_BLOCKS(r1, 2);
121
122         printf("Freeing ref\n");
123         talloc_free(ref);
124         talloc_report_full(root, stdout);
125
126         CHECK_BLOCKS(p1, 5);
127         CHECK_BLOCKS(p2, 1);
128         CHECK_BLOCKS(r1, 1);
129
130         printf("Freeing p2\n");
131         talloc_free(p2);
132         talloc_report_full(root, stdout);
133
134         CHECK_BLOCKS(p1, 4);
135         CHECK_BLOCKS(r1, 1);
136
137         printf("Freeing p1\n");
138         talloc_free(p1);
139         talloc_report_full(root, stdout);
140
141         CHECK_BLOCKS(r1, 1);
142
143         printf("Freeing r1\n");
144         talloc_free(r1);
145         talloc_report_full(root, stdout);
146
147         CHECK_SIZE(root, 0);
148
149         talloc_free(root);
150
151         return True;
152 }
153
154 /*
155   test references 
156 */
157 static BOOL test_ref3(void)
158 {
159         void *root, *p1, *p2, *ref, *r1;
160
161         printf("TESTING PARENT REFERENCE FREE\n");
162
163         root = talloc_named_const(NULL, 0, "root");
164         p1 = talloc_named_const(root, 1, "p1");
165         p2 = talloc_named_const(root, 1, "p2");
166         r1 = talloc_named_const(p1, 1, "r1");
167         ref = talloc_reference(p2, r1);
168         talloc_report_full(root, stdout);
169
170         CHECK_BLOCKS(p1, 2);
171         CHECK_BLOCKS(p2, 2);
172         CHECK_BLOCKS(r1, 1);
173
174         printf("Freeing p1\n");
175         talloc_free(p1);
176         talloc_report_full(root, stdout);
177
178         CHECK_BLOCKS(p2, 2);
179         CHECK_BLOCKS(r1, 1);
180
181         printf("Freeing p2\n");
182         talloc_free(p2);
183         talloc_report_full(root, stdout);
184
185         CHECK_SIZE(root, 0);
186
187         talloc_free(root);
188
189         return True;
190 }
191
192 /*
193   test references 
194 */
195 static BOOL test_ref4(void)
196 {
197         void *root, *p1, *p2, *ref, *r1;
198
199         printf("TESTING REFERRER REFERENCE FREE\n");
200
201         root = talloc_named_const(NULL, 0, "root");
202         p1 = talloc_named_const(root, 1, "p1");
203         talloc_named_const(p1, 1, "x1");
204         talloc_named_const(p1, 1, "x2");
205         talloc_named_const(p1, 1, "x3");
206         p2 = talloc_named_const(p1, 1, "p2");
207
208         r1 = talloc_named_const(root, 1, "r1"); 
209         ref = talloc_reference(r1, p2);
210         talloc_report_full(root, stdout);
211
212         CHECK_BLOCKS(p1, 5);
213         CHECK_BLOCKS(p2, 1);
214         CHECK_BLOCKS(r1, 2);
215
216         printf("Freeing r1\n");
217         talloc_free(r1);
218         talloc_report_full(root, stdout);
219
220         CHECK_BLOCKS(p1, 5);
221         CHECK_BLOCKS(p2, 1);
222
223         printf("Freeing p2\n");
224         talloc_free(p2);
225         talloc_report_full(root, stdout);
226
227         CHECK_BLOCKS(p1, 4);
228
229         printf("Freeing p1\n");
230         talloc_free(p1);
231         talloc_report_full(root, stdout);
232
233         CHECK_SIZE(root, 0);
234
235         talloc_free(root);
236
237         return True;
238 }
239
240
241 /*
242   test references 
243 */
244 static BOOL test_unref1(void)
245 {
246         void *root, *p1, *p2, *ref, *r1;
247
248         printf("TESTING UNREFERENCE\n");
249
250         root = talloc_named_const(NULL, 0, "root");
251         p1 = talloc_named_const(root, 1, "p1");
252         talloc_named_const(p1, 1, "x1");
253         talloc_named_const(p1, 1, "x2");
254         talloc_named_const(p1, 1, "x3");
255         p2 = talloc_named_const(p1, 1, "p2");
256
257         r1 = talloc_named_const(p1, 1, "r1");   
258         ref = talloc_reference(r1, p2);
259         talloc_report_full(root, stdout);
260
261         CHECK_BLOCKS(p1, 7);
262         CHECK_BLOCKS(p2, 1);
263         CHECK_BLOCKS(r1, 2);
264
265         printf("Unreferencing r1\n");
266         talloc_unreference(r1, p2);
267         talloc_report_full(root, stdout);
268
269         CHECK_BLOCKS(p1, 6);
270         CHECK_BLOCKS(p2, 1);
271         CHECK_BLOCKS(r1, 1);
272
273         printf("Freeing p1\n");
274         talloc_free(p1);
275         talloc_report_full(root, stdout);
276
277         CHECK_SIZE(root, 0);
278
279         talloc_free(root);
280
281         return True;
282 }
283
284 static int fail_destructor(void *ptr)
285 {
286         return -1;
287 }
288
289 /*
290   miscellaneous tests to try to get a higher test coverage percentage
291 */
292 static BOOL test_misc(void)
293 {
294         void *root, *p1;
295         char *p2;
296         double *d;
297
298         printf("TESTING MISCELLANEOUS\n");
299
300         root = talloc(NULL, 0);
301
302         p1 = talloc(root, 0x7fffffff);
303         if (p1) {
304                 printf("failed: large talloc allowed\n");
305                 return False;
306         }
307
308         p1 = talloc_strdup(root, "foo");
309         talloc_increase_ref_count(p1);
310         talloc_increase_ref_count(p1);
311         talloc_increase_ref_count(p1);
312         CHECK_BLOCKS(p1, 1);
313         CHECK_BLOCKS(root, 2);
314         talloc_free(p1);
315         CHECK_BLOCKS(p1, 1);
316         CHECK_BLOCKS(root, 2);
317         talloc_unreference(NULL, p1);
318         CHECK_BLOCKS(p1, 1);
319         CHECK_BLOCKS(root, 2);
320         if (talloc_unreference(root, p1) != NULL) {
321                 printf("failed: talloc_unreference() of non-reference context should return NULL\n");
322                 return False;
323         }
324         talloc_free(p1);
325         CHECK_BLOCKS(p1, 1);
326         CHECK_BLOCKS(root, 2);
327
328         talloc_set_name(p1, "my name is %s", "foo");
329         if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
330                 printf("failed: wrong name after talloc_set_name\n");
331                 return False;
332         }
333         CHECK_BLOCKS(p1, 2);
334         CHECK_BLOCKS(root, 3);
335
336         talloc_set_name_const(p1, NULL);
337         if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
338                 printf("failed: wrong name after talloc_set_name(NULL)\n");
339                 return False;
340         }
341         CHECK_BLOCKS(p1, 2);
342         CHECK_BLOCKS(root, 3);
343         
344
345         if (talloc_free(NULL) != -1) {
346                 printf("talloc_free(NULL) should give -1\n");
347                 return False;
348         }
349
350         talloc_set_destructor(p1, fail_destructor);
351         if (talloc_free(p1) != -1) {
352                 printf("Failed destructor should cause talloc_free to fail\n");
353                 return False;
354         }
355         talloc_set_destructor(p1, NULL);
356
357         talloc_report(root, stdout);
358
359
360         p2 = talloc_zero(p1, 20);
361         if (p2[19] != 0) {
362                 printf("Failed to give zero memory\n");
363                 return False;
364         }
365         talloc_free(p2);
366
367         if (talloc_strdup(root, NULL) != NULL) {
368                 printf("failed: strdup on NULL should give NULL\n");
369                 return False;
370         }
371
372         p2 = talloc_strndup(p1, "foo", 2);
373         if (strcmp("fo", p2) != 0) {
374                 printf("failed: strndup doesn't work\n");
375                 return False;
376         }
377         p2 = talloc_asprintf_append(p2, "o%c", 'd');
378         if (strcmp("food", p2) != 0) {
379                 printf("failed: talloc_asprintf_append doesn't work\n");
380                 return False;
381         }
382         CHECK_BLOCKS(p2, 1);
383         CHECK_BLOCKS(p1, 3);
384
385         p2 = talloc_asprintf_append(NULL, "hello %s", "world");
386         if (strcmp("hello world", p2) != 0) {
387                 printf("failed: talloc_asprintf_append doesn't work\n");
388                 return False;
389         }
390         CHECK_BLOCKS(p2, 1);
391         CHECK_BLOCKS(p1, 3);
392         talloc_free(p2);
393
394         d = talloc_array_p(p1, double, 0x20000000);
395         if (d) {
396                 printf("failed: integer overflow not detected\n");
397                 return False;
398         }
399
400         d = talloc_realloc_p(p1, d, double, 0x20000000);
401         if (d) {
402                 printf("failed: integer overflow not detected\n");
403                 return False;
404         }
405
406         talloc_free(p1);
407         CHECK_BLOCKS(root, 1);
408
409         talloc_report(root, stdout);
410         talloc_report(NULL, stdout);
411
412         CHECK_SIZE(root, 0);
413
414         talloc_free(root);
415
416         CHECK_SIZE(NULL, 0);
417
418         talloc_enable_leak_report();
419         talloc_enable_leak_report_full();
420
421         return True;
422 }
423
424
425 /*
426   test realloc
427 */
428 static BOOL test_realloc(void)
429 {
430         void *root, *p1, *p2;
431
432         printf("TESTING REALLOC\n");
433
434         root = talloc(NULL, 0);
435
436         p1 = talloc(root, 10);
437         CHECK_SIZE(p1, 10);
438
439         p1 = talloc_realloc(NULL, p1, 20);
440         CHECK_SIZE(p1, 20);
441
442         talloc(p1, 0);
443
444         p2 = talloc_realloc(p1, NULL, 30);
445
446         talloc(p1, 0);
447
448         p2 = talloc_realloc(p1, p2, 40);
449
450         CHECK_SIZE(p2, 40);
451         CHECK_SIZE(root, 60);
452         CHECK_BLOCKS(p1, 4);
453
454         p1 = talloc_realloc(NULL, p1, 20);
455         CHECK_SIZE(p1, 60);
456
457         talloc_increase_ref_count(p2);
458         if (talloc_realloc(NULL, p2, 5) != NULL) {
459                 printf("failed: talloc_realloc() on a referenced pointer should fail\n");
460                 return False;
461         }
462         CHECK_BLOCKS(p1, 4);
463
464         talloc_realloc(NULL, p2, 0);
465         talloc_realloc(NULL, p2, 0);
466         CHECK_BLOCKS(p1, 3);
467
468         if (talloc_realloc(NULL, p1, 0x7fffffff) != NULL) {
469                 printf("failed: oversize talloc should fail\n");
470                 return False;
471         }
472
473         talloc_realloc(NULL, p1, 0);
474
475         CHECK_BLOCKS(root, 1);
476         CHECK_SIZE(root, 0);
477
478         talloc_free(root);
479
480         return True;
481 }
482
483 /*
484   test steal
485 */
486 static BOOL test_steal(void)
487 {
488         void *root, *p1, *p2;
489
490         printf("TESTING STEAL\n");
491
492         root = talloc(NULL, 0);
493
494         p1 = talloc_array_p(root, char, 10);
495         CHECK_SIZE(p1, 10);
496
497         p2 = talloc_realloc_p(root, NULL, char, 20);
498         CHECK_SIZE(p1, 10);
499         CHECK_SIZE(root, 30);
500
501         if (talloc_steal(p1, NULL) != NULL) {
502                 printf("failed: stealing NULL should give NULL\n");
503                 return False;
504         }
505
506         if (talloc_steal(p1, p1) != p1) {
507                 printf("failed: stealing to ourselves is a nop\n");
508                 return False;
509         }
510         CHECK_BLOCKS(root, 3);
511         CHECK_SIZE(root, 30);
512
513         talloc_steal(NULL, p1);
514         talloc_steal(NULL, p2);
515         CHECK_BLOCKS(root, 1);
516         CHECK_SIZE(root, 0);
517
518         talloc_free(p1);
519         talloc_steal(root, p2);
520         CHECK_BLOCKS(root, 2);
521         CHECK_SIZE(root, 20);
522         
523         talloc_free(p2);
524
525         CHECK_BLOCKS(root, 1);
526         CHECK_SIZE(root, 0);
527
528         talloc_free(root);
529
530         p1 = talloc(NULL, 3);
531         CHECK_SIZE(NULL, 3);
532         talloc_free(p1);
533
534         return True;
535 }
536
537 /*
538   test ldb alloc fn
539 */
540 static BOOL test_ldb(void)
541 {
542         void *root, *p1;
543
544         printf("TESTING LDB\n");
545
546         root = talloc(NULL, 0);
547
548         p1 = talloc_ldb_alloc(root, NULL, 10);
549         CHECK_BLOCKS(root, 2);
550         CHECK_SIZE(root, 10);
551         p1 = talloc_ldb_alloc(root, p1, 20);
552         CHECK_BLOCKS(root, 2);
553         CHECK_SIZE(root, 20);
554         p1 = talloc_ldb_alloc(root, p1, 0);
555         CHECK_BLOCKS(root, 1);
556         CHECK_SIZE(root, 0);
557
558         talloc_free(root);
559
560
561         return True;
562 }
563
564 /*
565   measure the speed of talloc versus malloc
566 */
567 static BOOL test_speed(void)
568 {
569         void *ctx = talloc(NULL, 0);
570         uint_t count;
571
572         printf("MEASURING TALLOC VS MALLOC SPEED\n");
573
574         start_timer();
575         count = 0;
576         do {
577                 void *p1, *p2, *p3;
578                 p1 = talloc(ctx, count);
579                 p2 = talloc_strdup(p1, "foo bar");
580                 p3 = talloc(p1, 300);
581                 talloc_free(p1);
582                 count += 3;
583         } while (end_timer() < 5.0);
584
585         printf("talloc: %.0f ops/sec\n", count/end_timer());
586
587         talloc_free(ctx);
588
589         start_timer();
590         count = 0;
591         do {
592                 void *p1, *p2, *p3;
593                 p1 = malloc(count);
594                 p2 = strdup("foo bar");
595                 p3 = malloc(300);
596                 free(p1);
597                 free(p2);
598                 free(p3);
599                 count += 3;
600         } while (end_timer() < 5.0);
601
602         printf("malloc: %.0f ops/sec\n", count/end_timer());
603
604         return True;    
605 }
606
607
608 BOOL torture_local_talloc(int dummy) 
609 {
610         BOOL ret = True;
611
612         init_iconv();
613
614         ret &= test_ref1();
615         ret &= test_ref2();
616         ret &= test_ref3();
617         ret &= test_ref4();
618         ret &= test_unref1();
619         ret &= test_misc();
620         ret &= test_realloc();
621         ret &= test_steal();
622         ret &= test_ldb();
623         ret &= test_speed();
624
625         return ret;
626 }