Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : local testing of talloc routines.
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : ** NOTE! The following LGPL license applies to the talloc
9 : ** library. This does NOT imply that all of Samba is released
10 : ** under the LGPL
11 :
12 : This library is free software; you can redistribute it and/or
13 : modify it under the terms of the GNU Lesser General Public
14 : License as published by the Free Software Foundation; either
15 : version 3 of the License, or (at your option) any later version.
16 :
17 : This library is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 : Lesser General Public License for more details.
21 :
22 : You should have received a copy of the GNU Lesser General Public
23 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include "replace.h"
27 : #include "system/time.h"
28 : #include <talloc.h>
29 :
30 : #ifdef HAVE_PTHREAD
31 : #include <pthread.h>
32 : #endif
33 :
34 : #include <unistd.h>
35 : #include <sys/wait.h>
36 :
37 : #ifdef NDEBUG
38 : #undef NDEBUG
39 : #endif
40 :
41 : #include <assert.h>
42 :
43 : #include "talloc_testsuite.h"
44 :
45 196997 : static struct timeval private_timeval_current(void)
46 : {
47 : struct timeval tv;
48 196997 : gettimeofday(&tv, NULL);
49 196997 : return tv;
50 : }
51 :
52 196994 : static double private_timeval_elapsed(struct timeval *tv)
53 : {
54 196994 : struct timeval tv2 = private_timeval_current();
55 393988 : return (tv2.tv_sec - tv->tv_sec) +
56 196994 : (tv2.tv_usec - tv->tv_usec)*1.0e-6;
57 : }
58 :
59 : #define torture_assert(test, expr, str) if (!(expr)) { \
60 : printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \
61 : test, __location__, #expr, str); \
62 : return false; \
63 : }
64 :
65 : #define torture_assert_str_equal(test, arg1, arg2, desc) \
66 : if (arg1 == NULL && arg2 == NULL) { /* OK, both NULL == equal */ \
67 : } else if (arg1 == NULL || arg2 == NULL) { \
68 : return false; \
69 : } else if (strcmp(arg1, arg2)) { \
70 : printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
71 : test, __location__, arg1, arg2, desc); \
72 : return false; \
73 : }
74 :
75 : #define CHECK_SIZE(test, ptr, tsize) do { \
76 : if (talloc_total_size(ptr) != (tsize)) { \
77 : printf("failed: %s [\n%s: wrong '%s' tree size: got %u expected %u\n]\n", \
78 : test, __location__, #ptr, \
79 : (unsigned)talloc_total_size(ptr), \
80 : (unsigned)tsize); \
81 : talloc_report_full(ptr, stdout); \
82 : return false; \
83 : } \
84 : } while (0)
85 :
86 : #define CHECK_BLOCKS(test, ptr, tblocks) do { \
87 : if (talloc_total_blocks(ptr) != (tblocks)) { \
88 : printf("failed: %s [\n%s: wrong '%s' tree blocks: got %u expected %u\n]\n", \
89 : test, __location__, #ptr, \
90 : (unsigned)talloc_total_blocks(ptr), \
91 : (unsigned)tblocks); \
92 : talloc_report_full(ptr, stdout); \
93 : return false; \
94 : } \
95 : } while (0)
96 :
97 : #define CHECK_PARENT(test, ptr, parent) do { \
98 : if (talloc_parent(ptr) != (parent)) { \
99 : printf("failed: %s [\n%s: '%s' has wrong parent: got %p expected %p\n]\n", \
100 : test, __location__, #ptr, \
101 : talloc_parent(ptr), \
102 : (parent)); \
103 : talloc_report_full(ptr, stdout); \
104 : talloc_report_full(parent, stdout); \
105 : talloc_report_full(NULL, stdout); \
106 : return false; \
107 : } \
108 : } while (0)
109 :
110 : static unsigned int test_abort_count;
111 :
112 : #if 0
113 : static void test_abort_fn(const char *reason)
114 : {
115 : printf("# test_abort_fn(%s)\n", reason);
116 : test_abort_count++;
117 : }
118 :
119 : static void test_abort_start(void)
120 : {
121 : test_abort_count = 0;
122 : talloc_set_abort_fn(test_abort_fn);
123 : }
124 : #endif
125 :
126 35 : static void test_abort_stop(void)
127 : {
128 35 : test_abort_count = 0;
129 35 : talloc_set_abort_fn(NULL);
130 35 : }
131 :
132 0 : static void test_log_stdout(const char *message)
133 : {
134 0 : fprintf(stdout, "%s", message);
135 0 : }
136 :
137 : /*
138 : test references
139 : */
140 1 : static bool test_ref1(void)
141 : {
142 : void *root, *p1, *p2, *ref, *r1;
143 :
144 1 : printf("test: ref1\n# SINGLE REFERENCE FREE\n");
145 :
146 1 : root = talloc_named_const(NULL, 0, "root");
147 1 : p1 = talloc_named_const(root, 1, "p1");
148 1 : p2 = talloc_named_const(p1, 1, "p2");
149 1 : talloc_named_const(p1, 1, "x1");
150 1 : talloc_named_const(p1, 2, "x2");
151 1 : talloc_named_const(p1, 3, "x3");
152 :
153 1 : r1 = talloc_named_const(root, 1, "r1");
154 1 : ref = talloc_reference(r1, p2);
155 1 : talloc_report_full(root, stderr);
156 :
157 1 : CHECK_BLOCKS("ref1", p1, 5);
158 1 : CHECK_BLOCKS("ref1", p2, 1);
159 1 : CHECK_BLOCKS("ref1", ref, 1);
160 1 : CHECK_BLOCKS("ref1", r1, 2);
161 :
162 1 : fprintf(stderr, "Freeing p2\n");
163 1 : talloc_unlink(r1, p2);
164 1 : talloc_report_full(root, stderr);
165 :
166 1 : CHECK_BLOCKS("ref1", p1, 5);
167 1 : CHECK_BLOCKS("ref1", p2, 1);
168 1 : CHECK_BLOCKS("ref1", r1, 1);
169 :
170 1 : fprintf(stderr, "Freeing p1\n");
171 1 : talloc_free(p1);
172 1 : talloc_report_full(root, stderr);
173 :
174 1 : CHECK_BLOCKS("ref1", r1, 1);
175 :
176 1 : fprintf(stderr, "Freeing r1\n");
177 1 : talloc_free(r1);
178 1 : talloc_report_full(NULL, stderr);
179 :
180 1 : fprintf(stderr, "Testing NULL\n");
181 1 : if (talloc_reference(root, NULL)) {
182 0 : return false;
183 : }
184 :
185 1 : CHECK_BLOCKS("ref1", root, 1);
186 :
187 1 : CHECK_SIZE("ref1", root, 0);
188 :
189 1 : talloc_free(root);
190 1 : printf("success: ref1\n");
191 1 : return true;
192 : }
193 :
194 : /*
195 : test references
196 : */
197 1 : static bool test_ref2(void)
198 : {
199 : void *root, *p1, *p2, *ref, *r1;
200 :
201 1 : printf("test: ref2\n# DOUBLE REFERENCE FREE\n");
202 1 : root = talloc_named_const(NULL, 0, "root");
203 1 : p1 = talloc_named_const(root, 1, "p1");
204 1 : talloc_named_const(p1, 1, "x1");
205 1 : talloc_named_const(p1, 1, "x2");
206 1 : talloc_named_const(p1, 1, "x3");
207 1 : p2 = talloc_named_const(p1, 1, "p2");
208 :
209 1 : r1 = talloc_named_const(root, 1, "r1");
210 1 : ref = talloc_reference(r1, p2);
211 1 : talloc_report_full(root, stderr);
212 :
213 1 : CHECK_BLOCKS("ref2", p1, 5);
214 1 : CHECK_BLOCKS("ref2", p2, 1);
215 1 : CHECK_BLOCKS("ref2", r1, 2);
216 :
217 1 : fprintf(stderr, "Freeing ref\n");
218 1 : talloc_unlink(r1, ref);
219 1 : talloc_report_full(root, stderr);
220 :
221 1 : CHECK_BLOCKS("ref2", p1, 5);
222 1 : CHECK_BLOCKS("ref2", p2, 1);
223 1 : CHECK_BLOCKS("ref2", r1, 1);
224 :
225 1 : fprintf(stderr, "Freeing p2\n");
226 1 : talloc_free(p2);
227 1 : talloc_report_full(root, stderr);
228 :
229 1 : CHECK_BLOCKS("ref2", p1, 4);
230 1 : CHECK_BLOCKS("ref2", r1, 1);
231 :
232 1 : fprintf(stderr, "Freeing p1\n");
233 1 : talloc_free(p1);
234 1 : talloc_report_full(root, stderr);
235 :
236 1 : CHECK_BLOCKS("ref2", r1, 1);
237 :
238 1 : fprintf(stderr, "Freeing r1\n");
239 1 : talloc_free(r1);
240 1 : talloc_report_full(root, stderr);
241 :
242 1 : CHECK_SIZE("ref2", root, 0);
243 :
244 1 : talloc_free(root);
245 1 : printf("success: ref2\n");
246 1 : return true;
247 : }
248 :
249 : /*
250 : test references
251 : */
252 1 : static bool test_ref3(void)
253 : {
254 : void *root, *p1, *p2, *ref, *r1;
255 :
256 1 : printf("test: ref3\n# PARENT REFERENCE FREE\n");
257 :
258 1 : root = talloc_named_const(NULL, 0, "root");
259 1 : p1 = talloc_named_const(root, 1, "p1");
260 1 : p2 = talloc_named_const(root, 1, "p2");
261 1 : r1 = talloc_named_const(p1, 1, "r1");
262 1 : ref = talloc_reference(p2, r1);
263 1 : talloc_report_full(root, stderr);
264 :
265 1 : CHECK_BLOCKS("ref3", p1, 2);
266 1 : CHECK_BLOCKS("ref3", p2, 2);
267 1 : CHECK_BLOCKS("ref3", r1, 1);
268 1 : CHECK_BLOCKS("ref3", ref, 1);
269 :
270 1 : fprintf(stderr, "Freeing p1\n");
271 1 : talloc_free(p1);
272 1 : talloc_report_full(root, stderr);
273 :
274 1 : CHECK_BLOCKS("ref3", p2, 2);
275 1 : CHECK_BLOCKS("ref3", r1, 1);
276 :
277 1 : fprintf(stderr, "Freeing p2\n");
278 1 : talloc_free(p2);
279 1 : talloc_report_full(root, stderr);
280 :
281 1 : CHECK_SIZE("ref3", root, 0);
282 :
283 1 : talloc_free(root);
284 :
285 1 : printf("success: ref3\n");
286 1 : return true;
287 : }
288 :
289 : /*
290 : test references
291 : */
292 1 : static bool test_ref4(void)
293 : {
294 : void *root, *p1, *p2, *ref, *r1;
295 :
296 1 : printf("test: ref4\n# REFERRER REFERENCE FREE\n");
297 :
298 1 : root = talloc_named_const(NULL, 0, "root");
299 1 : p1 = talloc_named_const(root, 1, "p1");
300 1 : talloc_named_const(p1, 1, "x1");
301 1 : talloc_named_const(p1, 1, "x2");
302 1 : talloc_named_const(p1, 1, "x3");
303 1 : p2 = talloc_named_const(p1, 1, "p2");
304 :
305 1 : r1 = talloc_named_const(root, 1, "r1");
306 1 : ref = talloc_reference(r1, p2);
307 1 : talloc_report_full(root, stderr);
308 :
309 1 : CHECK_BLOCKS("ref4", p1, 5);
310 1 : CHECK_BLOCKS("ref4", p2, 1);
311 1 : CHECK_BLOCKS("ref4", ref, 1);
312 1 : CHECK_BLOCKS("ref4", r1, 2);
313 :
314 1 : fprintf(stderr, "Freeing r1\n");
315 1 : talloc_free(r1);
316 1 : talloc_report_full(root, stderr);
317 :
318 1 : CHECK_BLOCKS("ref4", p1, 5);
319 1 : CHECK_BLOCKS("ref4", p2, 1);
320 :
321 1 : fprintf(stderr, "Freeing p2\n");
322 1 : talloc_free(p2);
323 1 : talloc_report_full(root, stderr);
324 :
325 1 : CHECK_BLOCKS("ref4", p1, 4);
326 :
327 1 : fprintf(stderr, "Freeing p1\n");
328 1 : talloc_free(p1);
329 1 : talloc_report_full(root, stderr);
330 :
331 1 : CHECK_SIZE("ref4", root, 0);
332 :
333 1 : talloc_free(root);
334 :
335 1 : printf("success: ref4\n");
336 1 : return true;
337 : }
338 :
339 :
340 : /*
341 : test references
342 : */
343 1 : static bool test_unlink1(void)
344 : {
345 : void *root, *p1, *p2, *ref, *r1;
346 :
347 1 : printf("test: unlink\n# UNLINK\n");
348 :
349 1 : root = talloc_named_const(NULL, 0, "root");
350 1 : p1 = talloc_named_const(root, 1, "p1");
351 1 : talloc_named_const(p1, 1, "x1");
352 1 : talloc_named_const(p1, 1, "x2");
353 1 : talloc_named_const(p1, 1, "x3");
354 1 : p2 = talloc_named_const(p1, 1, "p2");
355 :
356 1 : r1 = talloc_named_const(p1, 1, "r1");
357 1 : ref = talloc_reference(r1, p2);
358 1 : talloc_report_full(root, stderr);
359 :
360 1 : CHECK_BLOCKS("unlink", p1, 7);
361 1 : CHECK_BLOCKS("unlink", p2, 1);
362 1 : CHECK_BLOCKS("unlink", ref, 1);
363 1 : CHECK_BLOCKS("unlink", r1, 2);
364 :
365 1 : fprintf(stderr, "Unreferencing r1\n");
366 1 : talloc_unlink(r1, p2);
367 1 : talloc_report_full(root, stderr);
368 :
369 1 : CHECK_BLOCKS("unlink", p1, 6);
370 1 : CHECK_BLOCKS("unlink", p2, 1);
371 1 : CHECK_BLOCKS("unlink", r1, 1);
372 :
373 1 : fprintf(stderr, "Freeing p1\n");
374 1 : talloc_free(p1);
375 1 : talloc_report_full(root, stderr);
376 :
377 1 : CHECK_SIZE("unlink", root, 0);
378 :
379 1 : talloc_free(root);
380 :
381 1 : printf("success: unlink\n");
382 1 : return true;
383 : }
384 :
385 1 : static int fail_destructor(void *ptr)
386 : {
387 1 : return -1;
388 : }
389 :
390 : /*
391 : miscellaneous tests to try to get a higher test coverage percentage
392 : */
393 1 : static bool test_misc(void)
394 : {
395 : void *root, *p1;
396 : char *p2;
397 : double *d;
398 : const char *name;
399 :
400 1 : printf("test: misc\n# MISCELLANEOUS\n");
401 :
402 1 : root = talloc_new(NULL);
403 :
404 1 : p1 = talloc_size(root, 0x7fffffff);
405 1 : torture_assert("misc", !p1, "failed: large talloc allowed\n");
406 :
407 1 : p1 = talloc_strdup(root, "foo");
408 1 : talloc_increase_ref_count(p1);
409 1 : talloc_increase_ref_count(p1);
410 1 : talloc_increase_ref_count(p1);
411 1 : CHECK_BLOCKS("misc", p1, 1);
412 1 : CHECK_BLOCKS("misc", root, 2);
413 1 : talloc_unlink(NULL, p1);
414 1 : CHECK_BLOCKS("misc", p1, 1);
415 1 : CHECK_BLOCKS("misc", root, 2);
416 1 : talloc_unlink(NULL, p1);
417 1 : CHECK_BLOCKS("misc", p1, 1);
418 1 : CHECK_BLOCKS("misc", root, 2);
419 1 : p2 = talloc_strdup(p1, "foo");
420 1 : torture_assert("misc", talloc_unlink(root, p2) == -1,
421 : "failed: talloc_unlink() of non-reference context should return -1\n");
422 1 : torture_assert("misc", talloc_unlink(p1, p2) == 0,
423 : "failed: talloc_unlink() of parent should succeed\n");
424 1 : talloc_unlink(NULL, p1);
425 1 : CHECK_BLOCKS("misc", p1, 1);
426 1 : CHECK_BLOCKS("misc", root, 2);
427 :
428 1 : name = talloc_set_name(p1, "my name is %s", "foo");
429 1 : torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
430 : "failed: wrong name after talloc_set_name(my name is foo)");
431 1 : torture_assert_str_equal("misc", talloc_get_name(p1), name,
432 : "failed: wrong name after talloc_set_name(my name is foo)");
433 1 : CHECK_BLOCKS("misc", p1, 2);
434 1 : CHECK_BLOCKS("misc", root, 3);
435 :
436 1 : talloc_set_name_const(p1, NULL);
437 1 : torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
438 : "failed: wrong name after talloc_set_name(NULL)");
439 1 : CHECK_BLOCKS("misc", p1, 2);
440 1 : CHECK_BLOCKS("misc", root, 3);
441 :
442 1 : torture_assert("misc", talloc_free(NULL) == -1,
443 : "talloc_free(NULL) should give -1\n");
444 :
445 1 : talloc_set_destructor(p1, fail_destructor);
446 1 : torture_assert("misc", talloc_free(p1) == -1,
447 : "Failed destructor should cause talloc_free to fail\n");
448 1 : talloc_set_destructor(p1, NULL);
449 :
450 1 : talloc_report(root, stderr);
451 :
452 :
453 1 : p2 = (char *)talloc_zero_size(p1, 20);
454 1 : torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
455 1 : talloc_free(p2);
456 :
457 1 : torture_assert("misc", talloc_strdup(root, NULL) == NULL,
458 : "failed: strdup on NULL should give NULL\n");
459 :
460 1 : p2 = talloc_strndup(p1, "foo", 2);
461 1 : torture_assert("misc", strcmp("fo", p2) == 0,
462 : "strndup doesn't work\n");
463 1 : p2 = talloc_asprintf_append_buffer(p2, "o%c", 'd');
464 1 : torture_assert("misc", strcmp("food", p2) == 0,
465 : "talloc_asprintf_append_buffer doesn't work\n");
466 1 : CHECK_BLOCKS("misc", p2, 1);
467 1 : CHECK_BLOCKS("misc", p1, 3);
468 :
469 1 : p2 = talloc_asprintf_append_buffer(NULL, "hello %s", "world");
470 1 : torture_assert("misc", strcmp("hello world", p2) == 0,
471 : "talloc_asprintf_append_buffer doesn't work\n");
472 1 : CHECK_BLOCKS("misc", p2, 1);
473 1 : CHECK_BLOCKS("misc", p1, 3);
474 1 : talloc_free(p2);
475 :
476 1 : d = talloc_array(p1, double, 0x20000000);
477 1 : torture_assert("misc", !d, "failed: integer overflow not detected\n");
478 :
479 1 : d = talloc_realloc(p1, d, double, 0x20000000);
480 1 : torture_assert("misc", !d, "failed: integer overflow not detected\n");
481 :
482 1 : talloc_free(p1);
483 1 : CHECK_BLOCKS("misc", root, 1);
484 :
485 1 : p1 = talloc_named(root, 100, "%d bytes", 100);
486 1 : CHECK_BLOCKS("misc", p1, 2);
487 1 : CHECK_BLOCKS("misc", root, 3);
488 1 : talloc_unlink(root, p1);
489 :
490 1 : p1 = talloc_init("%d bytes", 200);
491 1 : p2 = talloc_asprintf(p1, "my test '%s'", "string");
492 1 : torture_assert_str_equal("misc", p2, "my test 'string'",
493 : "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
494 1 : CHECK_BLOCKS("misc", p1, 3);
495 1 : CHECK_SIZE("misc", p2, 17);
496 1 : CHECK_BLOCKS("misc", root, 1);
497 1 : talloc_unlink(NULL, p1);
498 :
499 1 : p1 = talloc_named_const(root, 10, "p1");
500 1 : p2 = (char *)talloc_named_const(root, 20, "p2");
501 1 : (void)talloc_reference(p1, p2);
502 1 : talloc_report_full(root, stderr);
503 1 : talloc_unlink(root, p2);
504 1 : talloc_report_full(root, stderr);
505 1 : CHECK_BLOCKS("misc", p2, 1);
506 1 : CHECK_BLOCKS("misc", p1, 2);
507 1 : CHECK_BLOCKS("misc", root, 3);
508 1 : talloc_unlink(p1, p2);
509 1 : talloc_unlink(root, p1);
510 :
511 1 : p1 = talloc_named_const(root, 10, "p1");
512 1 : p2 = (char *)talloc_named_const(root, 20, "p2");
513 1 : (void)talloc_reference(NULL, p2);
514 1 : talloc_report_full(root, stderr);
515 1 : talloc_unlink(root, p2);
516 1 : talloc_report_full(root, stderr);
517 1 : CHECK_BLOCKS("misc", p2, 1);
518 1 : CHECK_BLOCKS("misc", p1, 1);
519 1 : CHECK_BLOCKS("misc", root, 2);
520 1 : talloc_unlink(NULL, p2);
521 1 : talloc_unlink(root, p1);
522 :
523 : /* Test that talloc_unlink is a no-op */
524 :
525 1 : torture_assert("misc", talloc_unlink(root, NULL) == -1,
526 : "failed: talloc_unlink(root, NULL) == -1\n");
527 :
528 1 : talloc_report(root, stderr);
529 1 : talloc_report(NULL, stderr);
530 :
531 1 : CHECK_SIZE("misc", root, 0);
532 :
533 1 : talloc_free(root);
534 :
535 1 : CHECK_SIZE("misc", NULL, 0);
536 :
537 1 : talloc_enable_null_tracking_no_autofree();
538 1 : talloc_enable_leak_report();
539 1 : talloc_enable_leak_report_full();
540 :
541 1 : printf("success: misc\n");
542 :
543 1 : return true;
544 : }
545 :
546 :
547 : /*
548 : test realloc
549 : */
550 1 : static bool test_realloc(void)
551 : {
552 : void *root, *p1, *p2;
553 :
554 1 : printf("test: realloc\n# REALLOC\n");
555 :
556 1 : root = talloc_new(NULL);
557 :
558 1 : p1 = talloc_size(root, 10);
559 1 : CHECK_SIZE("realloc", p1, 10);
560 :
561 1 : p1 = talloc_realloc_size(NULL, p1, 20);
562 1 : CHECK_SIZE("realloc", p1, 20);
563 :
564 1 : talloc_new(p1);
565 :
566 1 : p2 = talloc_realloc_size(p1, NULL, 30);
567 :
568 1 : talloc_new(p1);
569 :
570 1 : p2 = talloc_realloc_size(p1, p2, 40);
571 :
572 1 : CHECK_SIZE("realloc", p2, 40);
573 1 : CHECK_SIZE("realloc", root, 60);
574 1 : CHECK_BLOCKS("realloc", p1, 4);
575 :
576 1 : p1 = talloc_realloc_size(NULL, p1, 20);
577 1 : CHECK_SIZE("realloc", p1, 60);
578 :
579 1 : talloc_increase_ref_count(p2);
580 1 : torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
581 : "failed: talloc_realloc() on a referenced pointer should fail\n");
582 1 : CHECK_BLOCKS("realloc", p1, 4);
583 :
584 1 : talloc_realloc_size(NULL, p2, 0);
585 1 : talloc_realloc_size(NULL, p2, 0);
586 1 : CHECK_BLOCKS("realloc", p1, 4);
587 1 : talloc_realloc_size(p1, p2, 0);
588 1 : CHECK_BLOCKS("realloc", p1, 3);
589 :
590 1 : torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
591 : "failed: oversize talloc should fail\n");
592 :
593 1 : talloc_realloc_size(NULL, p1, 0);
594 1 : CHECK_BLOCKS("realloc", root, 4);
595 1 : talloc_realloc_size(root, p1, 0);
596 1 : CHECK_BLOCKS("realloc", root, 1);
597 :
598 1 : CHECK_SIZE("realloc", root, 0);
599 :
600 1 : talloc_free(root);
601 :
602 1 : printf("success: realloc\n");
603 :
604 1 : return true;
605 : }
606 :
607 : /*
608 : test realloc with a child
609 : */
610 1 : static bool test_realloc_child(void)
611 : {
612 : void *root;
613 : struct el2 {
614 : const char *name;
615 : } *el2, *el2_2, *el2_3, **el_list_save;
616 : struct el1 {
617 : int count;
618 : struct el2 **list, **list2, **list3;
619 : } *el1;
620 :
621 1 : printf("test: REALLOC WITH CHILD\n");
622 :
623 1 : root = talloc_new(NULL);
624 :
625 1 : el1 = talloc(root, struct el1);
626 1 : el1->list = talloc(el1, struct el2 *);
627 1 : el1->list[0] = talloc(el1->list, struct el2);
628 1 : el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
629 :
630 1 : el1->list2 = talloc(el1, struct el2 *);
631 1 : el1->list2[0] = talloc(el1->list2, struct el2);
632 1 : el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
633 :
634 1 : el1->list3 = talloc(el1, struct el2 *);
635 1 : el1->list3[0] = talloc(el1->list3, struct el2);
636 1 : el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
637 :
638 1 : el2 = talloc(el1->list, struct el2);
639 1 : CHECK_PARENT("el2", el2, el1->list);
640 1 : el2_2 = talloc(el1->list2, struct el2);
641 1 : CHECK_PARENT("el2", el2_2, el1->list2);
642 1 : el2_3 = talloc(el1->list3, struct el2);
643 1 : CHECK_PARENT("el2", el2_3, el1->list3);
644 :
645 1 : el_list_save = el1->list;
646 1 : el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
647 1 : if (el1->list == el_list_save) {
648 0 : printf("failure: talloc_realloc didn't move pointer");
649 0 : return false;
650 : }
651 :
652 1 : CHECK_PARENT("el1_after_realloc", el1->list, el1);
653 1 : el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
654 1 : CHECK_PARENT("el1_after_realloc", el1->list2, el1);
655 1 : el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
656 1 : CHECK_PARENT("el1_after_realloc", el1->list3, el1);
657 :
658 1 : CHECK_PARENT("el2", el2, el1->list);
659 1 : CHECK_PARENT("el2", el2_2, el1->list2);
660 1 : CHECK_PARENT("el2", el2_3, el1->list3);
661 :
662 : /* Finally check realloc with multiple children */
663 1 : el1 = talloc_realloc(root, el1, struct el1, 100);
664 1 : CHECK_PARENT("el1->list", el1->list, el1);
665 1 : CHECK_PARENT("el1->list2", el1->list2, el1);
666 1 : CHECK_PARENT("el1->list3", el1->list3, el1);
667 :
668 1 : talloc_free(root);
669 :
670 1 : printf("success: REALLOC WITH CHILD\n");
671 1 : return true;
672 : }
673 :
674 : /*
675 : test type checking
676 : */
677 1 : static bool test_type(void)
678 : {
679 : void *root;
680 : struct el1 {
681 : int count;
682 : };
683 : struct el2 {
684 : int count;
685 : };
686 : struct el1 *el1;
687 :
688 1 : printf("test: type\n# talloc type checking\n");
689 :
690 1 : root = talloc_new(NULL);
691 :
692 1 : el1 = talloc(root, struct el1);
693 :
694 1 : el1->count = 1;
695 :
696 1 : torture_assert("type", talloc_get_type(el1, struct el1) == el1,
697 : "type check failed on el1\n");
698 1 : torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
699 : "type check failed on el1 with el2\n");
700 1 : talloc_set_type(el1, struct el2);
701 1 : torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
702 : "type set failed on el1 with el2\n");
703 :
704 1 : talloc_free(root);
705 :
706 1 : printf("success: type\n");
707 1 : return true;
708 : }
709 :
710 : /*
711 : test steal
712 : */
713 1 : static bool test_steal(void)
714 : {
715 : void *root, *p1, *p2;
716 :
717 1 : printf("test: steal\n# STEAL\n");
718 :
719 1 : root = talloc_new(NULL);
720 :
721 1 : p1 = talloc_array(root, char, 10);
722 1 : CHECK_SIZE("steal", p1, 10);
723 :
724 1 : p2 = talloc_realloc(root, NULL, char, 20);
725 1 : CHECK_SIZE("steal", p1, 10);
726 1 : CHECK_SIZE("steal", root, 30);
727 :
728 1 : torture_assert("steal", talloc_steal(p1, NULL) == NULL,
729 : "failed: stealing NULL should give NULL\n");
730 :
731 1 : torture_assert("steal", talloc_steal(p1, p1) == p1,
732 : "failed: stealing to ourselves is a nop\n");
733 1 : CHECK_BLOCKS("steal", root, 3);
734 1 : CHECK_SIZE("steal", root, 30);
735 :
736 1 : talloc_steal(NULL, p1);
737 1 : talloc_steal(NULL, p2);
738 1 : CHECK_BLOCKS("steal", root, 1);
739 1 : CHECK_SIZE("steal", root, 0);
740 :
741 1 : talloc_free(p1);
742 1 : talloc_steal(root, p2);
743 1 : CHECK_BLOCKS("steal", root, 2);
744 1 : CHECK_SIZE("steal", root, 20);
745 :
746 1 : talloc_free(p2);
747 :
748 1 : CHECK_BLOCKS("steal", root, 1);
749 1 : CHECK_SIZE("steal", root, 0);
750 :
751 1 : talloc_free(root);
752 :
753 1 : p1 = talloc_size(NULL, 3);
754 1 : talloc_report_full(NULL, stderr);
755 1 : CHECK_SIZE("steal", NULL, 3);
756 1 : talloc_free(p1);
757 :
758 1 : printf("success: steal\n");
759 1 : return true;
760 : }
761 :
762 : /*
763 : test move
764 : */
765 1 : static bool test_move(void)
766 : {
767 : void *root;
768 : struct t_move {
769 : char *p;
770 : int *x;
771 : } *t1, *t2;
772 :
773 1 : printf("test: move\n# MOVE\n");
774 :
775 1 : root = talloc_new(NULL);
776 :
777 1 : t1 = talloc(root, struct t_move);
778 1 : t2 = talloc(root, struct t_move);
779 1 : t1->p = talloc_strdup(t1, "foo");
780 1 : t1->x = talloc(t1, int);
781 1 : *t1->x = 42;
782 :
783 1 : t2->p = talloc_move(t2, &t1->p);
784 1 : t2->x = talloc_move(t2, &t1->x);
785 1 : torture_assert("move", t1->p == NULL && t1->x == NULL &&
786 : strcmp(t2->p, "foo") == 0 && *t2->x == 42,
787 : "talloc move failed");
788 :
789 1 : talloc_free(root);
790 :
791 1 : printf("success: move\n");
792 :
793 1 : return true;
794 : }
795 :
796 : /*
797 : test talloc_realloc_fn
798 : */
799 1 : static bool test_realloc_fn(void)
800 : {
801 : void *root, *p1;
802 :
803 1 : printf("test: realloc_fn\n# talloc_realloc_fn\n");
804 :
805 1 : root = talloc_new(NULL);
806 :
807 1 : p1 = talloc_realloc_fn(root, NULL, 10);
808 1 : CHECK_BLOCKS("realloc_fn", root, 2);
809 1 : CHECK_SIZE("realloc_fn", root, 10);
810 1 : p1 = talloc_realloc_fn(root, p1, 20);
811 1 : CHECK_BLOCKS("realloc_fn", root, 2);
812 1 : CHECK_SIZE("realloc_fn", root, 20);
813 1 : p1 = talloc_realloc_fn(root, p1, 0);
814 1 : CHECK_BLOCKS("realloc_fn", root, 1);
815 1 : CHECK_SIZE("realloc_fn", root, 0);
816 :
817 1 : talloc_free(root);
818 :
819 1 : printf("success: realloc_fn\n");
820 1 : return true;
821 : }
822 :
823 :
824 1 : static bool test_unref_reparent(void)
825 : {
826 : void *root, *p1, *p2, *c1;
827 :
828 1 : printf("test: unref_reparent\n# UNREFERENCE AFTER PARENT FREED\n");
829 :
830 1 : root = talloc_named_const(NULL, 0, "root");
831 1 : p1 = talloc_named_const(root, 1, "orig parent");
832 1 : p2 = talloc_named_const(root, 1, "parent by reference");
833 :
834 1 : c1 = talloc_named_const(p1, 1, "child");
835 1 : talloc_reference(p2, c1);
836 :
837 1 : CHECK_PARENT("unref_reparent", c1, p1);
838 :
839 1 : talloc_free(p1);
840 :
841 1 : CHECK_PARENT("unref_reparent", c1, p2);
842 :
843 1 : talloc_unlink(p2, c1);
844 :
845 1 : CHECK_SIZE("unref_reparent", root, 1);
846 :
847 1 : talloc_free(p2);
848 1 : talloc_free(root);
849 :
850 1 : printf("success: unref_reparent\n");
851 1 : return true;
852 : }
853 :
854 : /*
855 : measure the speed of talloc versus malloc
856 : */
857 1 : static bool test_speed(void)
858 : {
859 1 : void *ctx = talloc_new(NULL);
860 : unsigned count;
861 1 : const int loop = 1000;
862 : int i;
863 : struct timeval tv;
864 :
865 1 : printf("test: speed\n# TALLOC VS MALLOC SPEED\n");
866 :
867 1 : tv = private_timeval_current();
868 1 : count = 0;
869 : do {
870 : void *p1, *p2, *p3;
871 21539518 : for (i=0;i<loop;i++) {
872 21518000 : p1 = talloc_size(ctx, loop % 100);
873 21518000 : p2 = talloc_strdup(p1, "foo bar");
874 21518000 : p3 = talloc_size(p1, 300);
875 : (void)p2;
876 : (void)p3;
877 21518000 : talloc_free(p1);
878 : }
879 21518 : count += 3 * loop;
880 21518 : } while (private_timeval_elapsed(&tv) < 5.0);
881 :
882 1 : fprintf(stderr, "talloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
883 :
884 1 : talloc_free(ctx);
885 :
886 1 : ctx = talloc_pool(NULL, 1024);
887 :
888 1 : tv = private_timeval_current();
889 1 : count = 0;
890 : do {
891 : void *p1, *p2, *p3;
892 17123106 : for (i=0;i<loop;i++) {
893 17106000 : p1 = talloc_size(ctx, loop % 100);
894 17106000 : p2 = talloc_strdup(p1, "foo bar");
895 17106000 : p3 = talloc_size(p1, 300);
896 : (void)p2;
897 : (void)p3;
898 17106000 : talloc_free(p1);
899 : }
900 17106 : count += 3 * loop;
901 17106 : } while (private_timeval_elapsed(&tv) < 5.0);
902 :
903 1 : talloc_free(ctx);
904 :
905 1 : fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
906 :
907 1 : tv = private_timeval_current();
908 1 : count = 0;
909 : do {
910 : void *p1, *p2, *p3;
911 158525367 : for (i=0;i<loop;i++) {
912 158367000 : p1 = malloc(loop % 100);
913 158367000 : p2 = strdup("foo bar");
914 158367000 : p3 = malloc(300);
915 158367000 : free(p1);
916 158367000 : free(p2);
917 158367000 : free(p3);
918 : }
919 158367 : count += 3 * loop;
920 158367 : } while (private_timeval_elapsed(&tv) < 5.0);
921 1 : fprintf(stderr, "malloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
922 :
923 1 : printf("success: speed\n");
924 :
925 1 : return true;
926 : }
927 :
928 1 : static bool test_lifeless(void)
929 : {
930 1 : void *top = talloc_new(NULL);
931 : char *parent, *child;
932 1 : void *child_owner = talloc_new(NULL);
933 :
934 1 : printf("test: lifeless\n# TALLOC_UNLINK LOOP\n");
935 :
936 1 : parent = talloc_strdup(top, "parent");
937 1 : child = talloc_strdup(parent, "child");
938 1 : (void)talloc_reference(child, parent);
939 1 : (void)talloc_reference(child_owner, child);
940 1 : talloc_report_full(top, stderr);
941 1 : talloc_unlink(top, parent);
942 1 : talloc_unlink(top, child);
943 1 : talloc_report_full(top, stderr);
944 1 : talloc_free(top);
945 1 : talloc_free(child_owner);
946 1 : talloc_free(child);
947 :
948 1 : printf("success: lifeless\n");
949 1 : return true;
950 : }
951 :
952 : static int loop_destructor_count;
953 :
954 1 : static int test_loop_destructor(char *ptr)
955 : {
956 1 : loop_destructor_count++;
957 1 : return 0;
958 : }
959 :
960 1 : static bool test_loop(void)
961 : {
962 1 : void *top = talloc_new(NULL);
963 : char *parent;
964 : struct req1 {
965 : char *req2, *req3;
966 : } *req1;
967 :
968 1 : printf("test: loop\n# TALLOC LOOP DESTRUCTION\n");
969 :
970 1 : parent = talloc_strdup(top, "parent");
971 1 : req1 = talloc(parent, struct req1);
972 1 : req1->req2 = talloc_strdup(req1, "req2");
973 1 : talloc_set_destructor(req1->req2, test_loop_destructor);
974 1 : req1->req3 = talloc_strdup(req1, "req3");
975 1 : (void)talloc_reference(req1->req3, req1);
976 1 : talloc_report_full(top, stderr);
977 1 : talloc_free(parent);
978 1 : talloc_report_full(top, stderr);
979 1 : talloc_report_full(NULL, stderr);
980 1 : talloc_free(top);
981 :
982 1 : torture_assert("loop", loop_destructor_count == 1,
983 : "FAILED TO FIRE LOOP DESTRUCTOR\n");
984 1 : loop_destructor_count = 0;
985 :
986 1 : printf("success: loop\n");
987 1 : return true;
988 : }
989 :
990 : static int realloc_parent_destructor_count;
991 :
992 2 : static int test_realloc_parent_destructor(char *ptr)
993 : {
994 2 : realloc_parent_destructor_count++;
995 2 : return 0;
996 : }
997 :
998 1 : static bool test_realloc_on_destructor_parent(void)
999 : {
1000 1 : void *top = talloc_new(NULL);
1001 : char *parent;
1002 : char *a, *b, *C, *D;
1003 1 : realloc_parent_destructor_count = 0;
1004 :
1005 1 : printf("test: free_for_exit\n# TALLOC FREE FOR EXIT\n");
1006 :
1007 1 : parent = talloc_strdup(top, "parent");
1008 1 : a = talloc_strdup(parent, "a");
1009 1 : b = talloc_strdup(a, "b");
1010 1 : C = talloc_strdup(a, "C");
1011 1 : D = talloc_strdup(b, "D");
1012 1 : talloc_set_destructor(D, test_realloc_parent_destructor);
1013 : /* Capitalised ones have destructors.
1014 : *
1015 : * parent --> a -> b -> D
1016 : * -> c
1017 : */
1018 :
1019 1 : a = talloc_realloc(parent, a, char, 2048);
1020 :
1021 1 : torture_assert("check talloc_realloc", a != NULL, "talloc_realloc failed");
1022 :
1023 1 : talloc_set_destructor(C, test_realloc_parent_destructor);
1024 : /*
1025 : * parent --> a[2048] -> b -> D
1026 : * -> C
1027 : *
1028 : */
1029 :
1030 1 : talloc_free(parent);
1031 :
1032 1 : torture_assert("check destructor realloc_parent_destructor",
1033 : realloc_parent_destructor_count == 2,
1034 : "FAILED TO FIRE free_for_exit_destructor\n");
1035 :
1036 :
1037 1 : printf("success: free_for_exit\n");
1038 1 : talloc_free(top); /* make ASAN happy */
1039 :
1040 1 : return true;
1041 : }
1042 :
1043 2 : static int fail_destructor_str(char *ptr)
1044 : {
1045 2 : return -1;
1046 : }
1047 :
1048 1 : static bool test_free_parent_deny_child(void)
1049 : {
1050 1 : void *top = talloc_new(NULL);
1051 : char *level1;
1052 : char *level2;
1053 : char *level3;
1054 :
1055 1 : printf("test: free_parent_deny_child\n# TALLOC FREE PARENT DENY CHILD\n");
1056 :
1057 1 : level1 = talloc_strdup(top, "level1");
1058 1 : level2 = talloc_strdup(level1, "level2");
1059 1 : level3 = talloc_strdup(level2, "level3");
1060 :
1061 1 : talloc_set_destructor(level3, fail_destructor_str);
1062 1 : talloc_free(level1);
1063 1 : talloc_set_destructor(level3, NULL);
1064 :
1065 1 : CHECK_PARENT("free_parent_deny_child", level3, top);
1066 :
1067 1 : talloc_free(top);
1068 :
1069 1 : printf("success: free_parent_deny_child\n");
1070 1 : return true;
1071 : }
1072 :
1073 : struct new_parent {
1074 : void *new_parent;
1075 : char val[20];
1076 : };
1077 :
1078 2 : static int reparenting_destructor(struct new_parent *np)
1079 : {
1080 2 : talloc_set_destructor(np, NULL);
1081 2 : (void)talloc_move(np->new_parent, &np);
1082 2 : return -1;
1083 : }
1084 :
1085 1 : static bool test_free_parent_reparent_child(void)
1086 : {
1087 1 : void *top = talloc_new(NULL);
1088 : char *level1;
1089 : char *alternate_level1;
1090 : char *level2;
1091 : struct new_parent *level3;
1092 :
1093 1 : printf("test: free_parent_reparent_child\n# "
1094 : "TALLOC FREE PARENT REPARENT CHILD\n");
1095 :
1096 1 : level1 = talloc_strdup(top, "level1");
1097 1 : alternate_level1 = talloc_strdup(top, "alternate_level1");
1098 1 : level2 = talloc_strdup(level1, "level2");
1099 1 : level3 = talloc(level2, struct new_parent);
1100 1 : level3->new_parent = alternate_level1;
1101 1 : memset(level3->val, 'x', sizeof(level3->val));
1102 :
1103 1 : talloc_set_destructor(level3, reparenting_destructor);
1104 1 : talloc_free(level1);
1105 :
1106 1 : CHECK_PARENT("free_parent_reparent_child",
1107 : level3, alternate_level1);
1108 :
1109 1 : talloc_free(top);
1110 :
1111 1 : printf("success: free_parent_reparent_child\n");
1112 1 : return true;
1113 : }
1114 :
1115 1 : static bool test_free_parent_reparent_child_in_pool(void)
1116 : {
1117 1 : void *top = talloc_new(NULL);
1118 : char *level1;
1119 : char *alternate_level1;
1120 : char *level2;
1121 : void *pool;
1122 : struct new_parent *level3;
1123 :
1124 1 : printf("test: free_parent_reparent_child_in_pool\n# "
1125 : "TALLOC FREE PARENT REPARENT CHILD IN POOL\n");
1126 :
1127 1 : pool = talloc_pool(top, 1024);
1128 1 : level1 = talloc_strdup(pool, "level1");
1129 1 : alternate_level1 = talloc_strdup(top, "alternate_level1");
1130 1 : level2 = talloc_strdup(level1, "level2");
1131 1 : level3 = talloc(level2, struct new_parent);
1132 1 : level3->new_parent = alternate_level1;
1133 1 : memset(level3->val, 'x', sizeof(level3->val));
1134 :
1135 1 : talloc_set_destructor(level3, reparenting_destructor);
1136 1 : talloc_free(level1);
1137 1 : talloc_set_destructor(level3, NULL);
1138 :
1139 1 : CHECK_PARENT("free_parent_reparent_child_in_pool",
1140 : level3, alternate_level1);
1141 :
1142 : /* Even freeing alternate_level1 should leave pool alone. */
1143 1 : talloc_free(alternate_level1);
1144 1 : talloc_free(top);
1145 :
1146 1 : printf("success: free_parent_reparent_child_in_pool\n");
1147 1 : return true;
1148 : }
1149 :
1150 :
1151 1 : static bool test_talloc_ptrtype(void)
1152 : {
1153 1 : void *top = talloc_new(NULL);
1154 : struct struct1 {
1155 : int foo;
1156 : int bar;
1157 : } *s1, *s2, **s3, ***s4;
1158 : const char *location1;
1159 : const char *location2;
1160 : const char *location3;
1161 : const char *location4;
1162 :
1163 1 : printf("test: ptrtype\n# TALLOC PTRTYPE\n");
1164 :
1165 1 : s1 = talloc_ptrtype(top, s1);location1 = __location__;
1166 :
1167 1 : if (talloc_get_size(s1) != sizeof(struct struct1)) {
1168 0 : printf("failure: ptrtype [\n"
1169 : "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n"
1170 0 : "]\n", (unsigned long)talloc_get_size(s1),
1171 : (unsigned long)sizeof(struct struct1));
1172 0 : return false;
1173 : }
1174 :
1175 1 : if (strcmp(location1, talloc_get_name(s1)) != 0) {
1176 0 : printf("failure: ptrtype [\n"
1177 : "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
1178 : talloc_get_name(s1), location1);
1179 0 : return false;
1180 : }
1181 :
1182 1 : s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
1183 :
1184 1 : if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) {
1185 0 : printf("failure: ptrtype [\n"
1186 : "talloc_array_ptrtype() allocated the wrong size "
1187 : "%lu (should be %lu)\n]\n",
1188 0 : (unsigned long)talloc_get_size(s2),
1189 : (unsigned long)(sizeof(struct struct1)*10));
1190 0 : return false;
1191 : }
1192 :
1193 1 : if (strcmp(location2, talloc_get_name(s2)) != 0) {
1194 0 : printf("failure: ptrtype [\n"
1195 : "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
1196 : talloc_get_name(s2), location2);
1197 0 : return false;
1198 : }
1199 :
1200 1 : s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
1201 :
1202 1 : if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) {
1203 0 : printf("failure: ptrtype [\n"
1204 : "talloc_array_ptrtype() allocated the wrong size "
1205 : "%lu (should be %lu)\n]\n",
1206 0 : (unsigned long)talloc_get_size(s3),
1207 : (unsigned long)(sizeof(struct struct1 *)*10));
1208 0 : return false;
1209 : }
1210 :
1211 1 : torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
1212 : "talloc_array_ptrtype() sets the wrong name");
1213 :
1214 1 : s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
1215 :
1216 1 : if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) {
1217 0 : printf("failure: ptrtype [\n"
1218 : "talloc_array_ptrtype() allocated the wrong size "
1219 : "%lu (should be %lu)\n]\n",
1220 0 : (unsigned long)talloc_get_size(s4),
1221 : (unsigned long)(sizeof(struct struct1 **)*10));
1222 0 : return false;
1223 : }
1224 :
1225 1 : torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
1226 : "talloc_array_ptrtype() sets the wrong name");
1227 :
1228 1 : talloc_free(top);
1229 :
1230 1 : printf("success: ptrtype\n");
1231 1 : return true;
1232 : }
1233 :
1234 1 : static int _test_talloc_free_in_destructor(void **ptr)
1235 : {
1236 1 : talloc_free(*ptr);
1237 1 : return 0;
1238 : }
1239 :
1240 1 : static bool test_talloc_free_in_destructor(void)
1241 : {
1242 : void *level0;
1243 : void *level1;
1244 : void *level2;
1245 : void *level3;
1246 : void *level4;
1247 : void **level5;
1248 :
1249 1 : printf("test: free_in_destructor\n# TALLOC FREE IN DESTRUCTOR\n");
1250 :
1251 1 : level0 = talloc_new(NULL);
1252 1 : level1 = talloc_new(level0);
1253 1 : level2 = talloc_new(level1);
1254 1 : level3 = talloc_new(level2);
1255 1 : level4 = talloc_new(level3);
1256 1 : level5 = talloc(level4, void *);
1257 :
1258 1 : *level5 = level3;
1259 1 : (void)talloc_reference(level0, level3);
1260 1 : (void)talloc_reference(level3, level3);
1261 1 : (void)talloc_reference(level5, level3);
1262 :
1263 1 : talloc_set_destructor(level5, _test_talloc_free_in_destructor);
1264 :
1265 1 : talloc_free(level1);
1266 :
1267 1 : talloc_free(level0);
1268 :
1269 1 : talloc_free(level3); /* make ASAN happy */
1270 :
1271 1 : printf("success: free_in_destructor\n");
1272 1 : return true;
1273 : }
1274 :
1275 1 : static bool test_autofree(void)
1276 : {
1277 : #if _SAMBA_BUILD_ < 4
1278 : /* autofree test would kill smbtorture */
1279 : void *p;
1280 1 : printf("test: autofree\n# TALLOC AUTOFREE CONTEXT\n");
1281 :
1282 1 : p = talloc_autofree_context();
1283 1 : talloc_free(p);
1284 :
1285 1 : p = talloc_autofree_context();
1286 1 : talloc_free(p);
1287 :
1288 1 : printf("success: autofree\n");
1289 : #endif
1290 1 : return true;
1291 : }
1292 :
1293 1 : static bool test_pool(void)
1294 : {
1295 : void *pool;
1296 : void *p1, *p2, *p3, *p4;
1297 : void *p2_2;
1298 :
1299 1 : pool = talloc_pool(NULL, 1024);
1300 :
1301 1 : p1 = talloc_size(pool, 80);
1302 1 : memset(p1, 0x11, talloc_get_size(p1));
1303 1 : p2 = talloc_size(pool, 20);
1304 1 : memset(p2, 0x11, talloc_get_size(p2));
1305 1 : p3 = talloc_size(p1, 50);
1306 1 : memset(p3, 0x11, talloc_get_size(p3));
1307 1 : p4 = talloc_size(p3, 1000);
1308 1 : memset(p4, 0x11, talloc_get_size(p4));
1309 :
1310 1 : p2_2 = talloc_realloc_size(pool, p2, 20+1);
1311 1 : torture_assert("pool realloc 20+1", p2_2 == p2, "failed: pointer changed");
1312 1 : memset(p2, 0x11, talloc_get_size(p2));
1313 1 : p2_2 = talloc_realloc_size(pool, p2, 20-1);
1314 1 : torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
1315 1 : memset(p2, 0x11, talloc_get_size(p2));
1316 1 : p2_2 = talloc_realloc_size(pool, p2, 20-1);
1317 1 : torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
1318 1 : memset(p2, 0x11, talloc_get_size(p2));
1319 :
1320 1 : talloc_free(p3);
1321 :
1322 : /* this should reclaim the memory of p4 and p3 */
1323 1 : p2_2 = talloc_realloc_size(pool, p2, 400);
1324 1 : torture_assert("pool realloc 400", p2_2 == p2, "failed: pointer changed");
1325 1 : memset(p2, 0x11, talloc_get_size(p2));
1326 :
1327 1 : talloc_free(p1);
1328 :
1329 : /* this should reclaim the memory of p1 */
1330 1 : p2_2 = talloc_realloc_size(pool, p2, 800);
1331 1 : torture_assert("pool realloc 800", p2_2 == p1, "failed: pointer not changed");
1332 1 : p2 = p2_2;
1333 1 : memset(p2, 0x11, talloc_get_size(p2));
1334 :
1335 : /* this should do a malloc */
1336 1 : p2_2 = talloc_realloc_size(pool, p2, 1800);
1337 1 : torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
1338 1 : p2 = p2_2;
1339 1 : memset(p2, 0x11, talloc_get_size(p2));
1340 :
1341 : /* this should reclaim the memory from the pool */
1342 1 : p3 = talloc_size(pool, 80);
1343 1 : torture_assert("pool alloc 80", p3 == p1, "failed: pointer changed");
1344 1 : memset(p3, 0x11, talloc_get_size(p3));
1345 :
1346 1 : talloc_free(p2);
1347 1 : talloc_free(p3);
1348 :
1349 1 : p1 = talloc_size(pool, 80);
1350 1 : memset(p1, 0x11, talloc_get_size(p1));
1351 1 : p2 = talloc_size(pool, 20);
1352 1 : memset(p2, 0x11, talloc_get_size(p2));
1353 :
1354 1 : talloc_free(p1);
1355 :
1356 1 : p2_2 = talloc_realloc_size(pool, p2, 20-1);
1357 1 : torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
1358 1 : memset(p2, 0x11, talloc_get_size(p2));
1359 1 : p2_2 = talloc_realloc_size(pool, p2, 20-1);
1360 1 : torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
1361 1 : memset(p2, 0x11, talloc_get_size(p2));
1362 :
1363 : /* this should do a malloc */
1364 1 : p2_2 = talloc_realloc_size(pool, p2, 1800);
1365 1 : torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
1366 1 : p2 = p2_2;
1367 1 : memset(p2, 0x11, talloc_get_size(p2));
1368 :
1369 : /* this should reclaim the memory from the pool */
1370 1 : p3 = talloc_size(pool, 800);
1371 1 : torture_assert("pool alloc 800", p3 == p1, "failed: pointer changed");
1372 1 : memset(p3, 0x11, talloc_get_size(p3));
1373 :
1374 1 : talloc_free(pool);
1375 :
1376 1 : return true;
1377 : }
1378 :
1379 1 : static bool test_pool_steal(void)
1380 : {
1381 : void *root;
1382 : void *pool;
1383 : void *p1, *p2;
1384 : void *p1_2, *p2_2;
1385 : size_t hdr;
1386 : size_t ofs1, ofs2;
1387 :
1388 1 : root = talloc_new(NULL);
1389 1 : pool = talloc_pool(root, 1024);
1390 :
1391 1 : p1 = talloc_size(pool, 4 * 16);
1392 1 : torture_assert("pool allocate 4 * 16", p1 != NULL, "failed ");
1393 1 : memset(p1, 0x11, talloc_get_size(p1));
1394 1 : p2 = talloc_size(pool, 4 * 16);
1395 1 : torture_assert("pool allocate 4 * 16", p2 > p1, "failed: !(p2 > p1) ");
1396 1 : memset(p2, 0x11, talloc_get_size(p2));
1397 :
1398 1 : ofs1 = PTR_DIFF(p2, p1);
1399 1 : hdr = ofs1 - talloc_get_size(p1);
1400 :
1401 1 : talloc_steal(root, p1);
1402 1 : talloc_steal(root, p2);
1403 :
1404 1 : talloc_free(pool);
1405 :
1406 1 : p1_2 = p1;
1407 :
1408 1 : p1_2 = talloc_realloc_size(root, p1, 5 * 16);
1409 1 : torture_assert("pool realloc 5 * 16", p1_2 > p2, "failed: pointer not changed");
1410 1 : memset(p1_2, 0x11, talloc_get_size(p1_2));
1411 1 : ofs1 = PTR_DIFF(p1_2, p2);
1412 1 : ofs2 = talloc_get_size(p2) + hdr;
1413 :
1414 1 : torture_assert("pool realloc ", ofs1 == ofs2, "failed: pointer offset unexpected");
1415 :
1416 1 : p2_2 = talloc_realloc_size(root, p2, 3 * 16);
1417 1 : torture_assert("pool realloc 5 * 16", p2_2 == p2, "failed: pointer changed");
1418 1 : memset(p2_2, 0x11, talloc_get_size(p2_2));
1419 :
1420 1 : talloc_free(p1_2);
1421 :
1422 1 : p2_2 = p2;
1423 :
1424 : /* now we should reclaim the full pool */
1425 1 : p2_2 = talloc_realloc_size(root, p2, 8 * 16);
1426 1 : torture_assert("pool realloc 8 * 16", p2_2 == p1, "failed: pointer not expected");
1427 1 : p2 = p2_2;
1428 1 : memset(p2_2, 0x11, talloc_get_size(p2_2));
1429 :
1430 : /* now we malloc and free the full pool space */
1431 1 : p2_2 = talloc_realloc_size(root, p2, 2 * 1024);
1432 1 : torture_assert("pool realloc 2 * 1024", p2_2 != p1, "failed: pointer not expected");
1433 1 : memset(p2_2, 0x11, talloc_get_size(p2_2));
1434 :
1435 1 : talloc_free(p2_2);
1436 :
1437 1 : talloc_free(root);
1438 :
1439 1 : return true;
1440 : }
1441 :
1442 1 : static bool test_pool_nest(void)
1443 : {
1444 : void *p1, *p2, *p3;
1445 1 : void *e = talloc_new(NULL);
1446 :
1447 1 : p1 = talloc_pool(NULL, 1024);
1448 1 : torture_assert("talloc_pool", p1 != NULL, "failed");
1449 :
1450 1 : p2 = talloc_pool(p1, 500);
1451 1 : torture_assert("talloc_pool", p2 != NULL, "failed");
1452 :
1453 1 : p3 = talloc_size(p2, 10);
1454 :
1455 1 : talloc_steal(e, p3);
1456 :
1457 1 : talloc_free(p2);
1458 :
1459 1 : talloc_free(p3);
1460 :
1461 1 : talloc_free(p1);
1462 :
1463 1 : talloc_free(e); /* make ASAN happy */
1464 :
1465 1 : return true;
1466 : }
1467 :
1468 : struct pooled {
1469 : char *s1;
1470 : char *s2;
1471 : char *s3;
1472 : };
1473 :
1474 1 : static bool test_pooled_object(void)
1475 : {
1476 : struct pooled *p;
1477 1 : const char *s1 = "hello";
1478 1 : const char *s2 = "world";
1479 1 : const char *s3 = "";
1480 :
1481 1 : p = talloc_pooled_object(NULL, struct pooled, 3,
1482 : strlen(s1)+strlen(s2)+strlen(s3)+3);
1483 :
1484 1 : if (talloc_get_size(p) != sizeof(struct pooled)) {
1485 0 : return false;
1486 : }
1487 :
1488 1 : p->s1 = talloc_strdup(p, s1);
1489 :
1490 1 : TALLOC_FREE(p->s1);
1491 1 : p->s1 = talloc_strdup(p, s2);
1492 1 : TALLOC_FREE(p->s1);
1493 :
1494 1 : p->s1 = talloc_strdup(p, s1);
1495 1 : p->s2 = talloc_strdup(p, s2);
1496 1 : p->s3 = talloc_strdup(p, s3);
1497 :
1498 1 : TALLOC_FREE(p);
1499 1 : return true;
1500 : }
1501 :
1502 1 : static bool test_free_ref_null_context(void)
1503 : {
1504 : void *p1, *p2, *p3;
1505 : int ret;
1506 :
1507 1 : talloc_disable_null_tracking();
1508 1 : p1 = talloc_new(NULL);
1509 1 : p2 = talloc_new(NULL);
1510 :
1511 1 : p3 = talloc_reference(p2, p1);
1512 1 : torture_assert("reference", p3 == p1, "failed: reference on null");
1513 :
1514 1 : ret = talloc_free(p1);
1515 1 : torture_assert("ref free with null parent", ret == 0, "failed: free with null parent");
1516 1 : talloc_free(p2);
1517 :
1518 1 : talloc_enable_null_tracking_no_autofree();
1519 1 : p1 = talloc_new(NULL);
1520 1 : p2 = talloc_new(NULL);
1521 :
1522 1 : p3 = talloc_reference(p2, p1);
1523 1 : torture_assert("reference", p3 == p1, "failed: reference on null");
1524 :
1525 1 : ret = talloc_free(p1);
1526 1 : torture_assert("ref free with null tracked parent", ret == 0, "failed: free with null parent");
1527 1 : talloc_free(p2);
1528 :
1529 1 : return true;
1530 : }
1531 :
1532 1 : static bool test_rusty(void)
1533 : {
1534 : void *root;
1535 : char *p1;
1536 :
1537 1 : talloc_enable_null_tracking();
1538 1 : root = talloc_new(NULL);
1539 1 : p1 = talloc_strdup(root, "foo");
1540 1 : talloc_increase_ref_count(p1);
1541 1 : talloc_report_full(root, stdout);
1542 1 : talloc_free(root);
1543 1 : CHECK_BLOCKS("null_context", NULL, 2);
1544 1 : talloc_free(p1); /* make ASAN happy */
1545 :
1546 1 : return true;
1547 : }
1548 :
1549 1 : static bool test_free_children(void)
1550 : {
1551 : void *root;
1552 : char *p1, *p2;
1553 : const char *name, *name2;
1554 :
1555 1 : talloc_enable_null_tracking();
1556 1 : root = talloc_new(NULL);
1557 1 : p1 = talloc_strdup(root, "foo1");
1558 1 : p2 = talloc_strdup(p1, "foo2");
1559 : (void)p2;
1560 :
1561 1 : talloc_set_name(p1, "%s", "testname");
1562 1 : talloc_free_children(p1);
1563 : /* check its still a valid talloc ptr */
1564 1 : talloc_get_size(talloc_get_name(p1));
1565 1 : if (strcmp(talloc_get_name(p1), "testname") != 0) {
1566 0 : return false;
1567 : }
1568 :
1569 1 : talloc_set_name(p1, "%s", "testname");
1570 1 : name = talloc_get_name(p1);
1571 1 : talloc_free_children(p1);
1572 : /* check its still a valid talloc ptr */
1573 1 : talloc_get_size(talloc_get_name(p1));
1574 1 : torture_assert("name", name == talloc_get_name(p1), "name ptr changed");
1575 1 : torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname") == 0,
1576 : "wrong name");
1577 1 : CHECK_BLOCKS("name1", p1, 2);
1578 :
1579 : /* note that this does not free the old child name */
1580 1 : talloc_set_name_const(p1, "testname2");
1581 1 : name2 = talloc_get_name(p1);
1582 : /* but this does */
1583 1 : talloc_free_children(p1);
1584 : (void)name2;
1585 1 : torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname2") == 0,
1586 : "wrong name");
1587 1 : CHECK_BLOCKS("name1", p1, 1);
1588 :
1589 1 : talloc_report_full(root, stdout);
1590 1 : talloc_free(root);
1591 1 : return true;
1592 : }
1593 :
1594 1 : static bool test_memlimit(void)
1595 : {
1596 : void *root;
1597 : char *l1, *l2, *l3, *l4, *l5, *t;
1598 : char *pool;
1599 : int i;
1600 :
1601 1 : printf("test: memlimit\n# MEMORY LIMITS\n");
1602 :
1603 1 : printf("==== talloc_new(NULL)\n");
1604 1 : root = talloc_new(NULL);
1605 :
1606 1 : talloc_report_full(root, stdout);
1607 :
1608 1 : printf("==== talloc_size(root, 2048)\n");
1609 1 : l1 = talloc_size(root, 2048);
1610 1 : torture_assert("memlimit", l1 != NULL,
1611 : "failed: alloc should not fail due to memory limit\n");
1612 :
1613 1 : talloc_report_full(root, stdout);
1614 :
1615 1 : printf("==== talloc_free(l1)\n");
1616 1 : talloc_free(l1);
1617 :
1618 1 : talloc_report_full(root, stdout);
1619 :
1620 1 : printf("==== talloc_strdup(root, level 1)\n");
1621 1 : l1 = talloc_strdup(root, "level 1");
1622 1 : torture_assert("memlimit", l1 != NULL,
1623 : "failed: alloc should not fail due to memory limit\n");
1624 :
1625 1 : talloc_report_full(root, stdout);
1626 :
1627 1 : printf("==== talloc_set_memlimit(l1, 2048)\n");
1628 1 : torture_assert("memlimit", talloc_set_memlimit(l1, 2048) == 0,
1629 : "failed: setting memlimit should never fail\n");
1630 :
1631 1 : talloc_report_full(root, stdout);
1632 :
1633 1 : printf("==== talloc_size(root, 2048)\n");
1634 1 : l2 = talloc_size(l1, 2048);
1635 1 : torture_assert("memlimit", l2 == NULL,
1636 : "failed: alloc should fail due to memory limit\n");
1637 :
1638 1 : talloc_report_full(root, stdout);
1639 :
1640 1 : printf("==== talloc_strdup(l1, level 2)\n");
1641 1 : l2 = talloc_strdup(l1, "level 2");
1642 1 : torture_assert("memlimit", l2 != NULL,
1643 : "failed: alloc should not fail due to memory limit\n");
1644 :
1645 1 : talloc_report_full(root, stdout);
1646 :
1647 1 : printf("==== talloc_free(l2)\n");
1648 1 : talloc_free(l2);
1649 :
1650 1 : talloc_report_full(root, stdout);
1651 :
1652 1 : printf("==== talloc_size(NULL, 2048)\n");
1653 1 : l2 = talloc_size(NULL, 2048);
1654 :
1655 1 : talloc_report_full(root, stdout);
1656 :
1657 1 : printf("==== talloc_steal(l1, l2)\n");
1658 1 : talloc_steal(l1, l2);
1659 :
1660 1 : talloc_report_full(root, stdout);
1661 :
1662 1 : printf("==== talloc_strdup(l2, level 3)\n");
1663 1 : l3 = talloc_strdup(l2, "level 3");
1664 1 : torture_assert("memlimit", l3 == NULL,
1665 : "failed: alloc should fail due to memory limit\n");
1666 :
1667 1 : talloc_report_full(root, stdout);
1668 :
1669 1 : printf("==== talloc_free(l2)\n");
1670 1 : talloc_free(l2);
1671 :
1672 1 : talloc_report_full(root, stdout);
1673 :
1674 1 : printf("==== talloc_strdup(NULL, level 2)\n");
1675 1 : l2 = talloc_strdup(NULL, "level 2");
1676 1 : talloc_steal(l1, l2);
1677 :
1678 1 : talloc_report_full(root, stdout);
1679 :
1680 1 : printf("==== talloc_strdup(l2, level 3)\n");
1681 1 : l3 = talloc_strdup(l2, "level 3");
1682 1 : torture_assert("memlimit", l3 != NULL,
1683 : "failed: alloc should not fail due to memory limit\n");
1684 :
1685 1 : talloc_report_full(root, stdout);
1686 :
1687 1 : printf("==== talloc_set_memlimit(l3, 1024)\n");
1688 1 : torture_assert("memlimit", talloc_set_memlimit(l3, 1024) == 0,
1689 : "failed: setting memlimit should never fail\n");
1690 :
1691 1 : talloc_report_full(root, stdout);
1692 :
1693 1 : printf("==== talloc_strdup(l3, level 4)\n");
1694 1 : l4 = talloc_strdup(l3, "level 4");
1695 1 : torture_assert("memlimit", l4 != NULL,
1696 : "failed: alloc should not fail due to memory limit\n");
1697 :
1698 1 : talloc_report_full(root, stdout);
1699 :
1700 1 : printf("==== talloc_set_memlimit(l4, 512)\n");
1701 1 : torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0,
1702 : "failed: setting memlimit should never fail\n");
1703 :
1704 1 : talloc_report_full(root, stdout);
1705 :
1706 1 : printf("==== talloc_strdup(l4, level 5)\n");
1707 1 : l5 = talloc_strdup(l4, "level 5");
1708 1 : torture_assert("memlimit", l5 != NULL,
1709 : "failed: alloc should not fail due to memory limit\n");
1710 :
1711 1 : talloc_report_full(root, stdout);
1712 :
1713 1 : printf("==== talloc_realloc(NULL, l5, char, 600)\n");
1714 1 : t = talloc_realloc(NULL, l5, char, 600);
1715 1 : torture_assert("memlimit", t == NULL,
1716 : "failed: alloc should fail due to memory limit\n");
1717 :
1718 1 : talloc_report_full(root, stdout);
1719 :
1720 1 : printf("==== talloc_realloc(NULL, l5, char, 5)\n");
1721 1 : l5 = talloc_realloc(NULL, l5, char, 5);
1722 1 : torture_assert("memlimit", l5 != NULL,
1723 : "failed: alloc should not fail due to memory limit\n");
1724 :
1725 1 : talloc_report_full(root, stdout);
1726 :
1727 1 : printf("==== talloc_strdup(l3, level 4)\n");
1728 1 : l4 = talloc_strdup(l3, "level 4");
1729 1 : torture_assert("memlimit", l4 != NULL,
1730 : "failed: alloc should not fail due to memory limit\n");
1731 :
1732 1 : talloc_report_full(root, stdout);
1733 :
1734 1 : printf("==== talloc_set_memlimit(l4, 512)\n");
1735 1 : torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0,
1736 : "failed: setting memlimit should never fail\n");
1737 :
1738 1 : talloc_report_full(root, stdout);
1739 :
1740 1 : printf("==== talloc_strdup(l4, level 5)\n");
1741 1 : l5 = talloc_strdup(l4, "level 5");
1742 1 : torture_assert("memlimit", l5 != NULL,
1743 : "failed: alloc should not fail due to memory limit\n");
1744 :
1745 1 : talloc_report_full(root, stdout);
1746 :
1747 1 : printf("==== Make new temp context and steal l5\n");
1748 1 : t = talloc_new(root);
1749 1 : talloc_steal(t, l5);
1750 :
1751 1 : talloc_report_full(root, stdout);
1752 :
1753 1 : printf("==== talloc_size(t, 2048)\n");
1754 1 : l1 = talloc_size(t, 2048);
1755 1 : torture_assert("memlimit", l1 != NULL,
1756 : "failed: alloc should not fail due to memory limit\n");
1757 :
1758 1 : talloc_report_full(root, stdout);
1759 1 : talloc_free(root);
1760 :
1761 : /* Test memlimits with pools. */
1762 1 : printf("==== talloc_pool(NULL, 10*1024)\n");
1763 1 : pool = talloc_pool(NULL, 10*1024);
1764 1 : torture_assert("memlimit", pool != NULL,
1765 : "failed: alloc should not fail due to memory limit\n");
1766 :
1767 1 : printf("==== talloc_set_memlimit(pool, 10*1024)\n");
1768 1 : talloc_set_memlimit(pool, 10*1024);
1769 10 : for (i = 0; i < 9; i++) {
1770 9 : printf("==== talloc_size(pool, 1024) %i/10\n", i + 1);
1771 9 : l1 = talloc_size(pool, 1024);
1772 9 : torture_assert("memlimit", l1 != NULL,
1773 : "failed: alloc should not fail due to memory limit\n");
1774 9 : talloc_report_full(pool, stdout);
1775 : }
1776 : /* The next alloc should fail. */
1777 1 : printf("==== talloc_size(pool, 1024) 10/10\n");
1778 1 : l2 = talloc_size(pool, 1024);
1779 1 : torture_assert("memlimit", l2 == NULL,
1780 : "failed: alloc should fail due to memory limit\n");
1781 :
1782 1 : talloc_report_full(pool, stdout);
1783 :
1784 : /* Moving one of the children shouldn't change the limit,
1785 : as it's still inside the pool. */
1786 :
1787 1 : printf("==== talloc_new(NULL)\n");
1788 1 : root = talloc_new(NULL);
1789 :
1790 1 : printf("==== talloc_steal(root, l1)\n");
1791 1 : talloc_steal(root, l1);
1792 :
1793 1 : printf("==== talloc_size(pool, 1024)\n");
1794 1 : l2 = talloc_size(pool, 1024);
1795 1 : torture_assert("memlimit", l2 == NULL,
1796 : "failed: alloc should fail due to memory limit\n");
1797 :
1798 1 : printf("==== talloc_free_children(pool)\n");
1799 1 : talloc_free(l1);
1800 1 : talloc_free_children(pool);
1801 :
1802 1 : printf("==== talloc_size(pool, 1024)\n");
1803 1 : l1 = talloc_size(pool, 1024);
1804 :
1805 : /* try reallocs of increasing size */
1806 9 : for (i = 1; i < 9; i++) {
1807 8 : printf("==== talloc_realloc_size(NULL, l1, %i*1024) %i/10\n", i, i + 1);
1808 8 : l1 = talloc_realloc_size(NULL, l1, i*1024);
1809 8 : torture_assert("memlimit", l1 != NULL,
1810 : "failed: realloc should not fail due to memory limit\n");
1811 8 : talloc_report_full(pool, stdout);
1812 : }
1813 : /* The next alloc should fail. */
1814 1 : printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n");
1815 1 : l2 = talloc_realloc_size(NULL, l1, 10*1024);
1816 1 : torture_assert("memlimit", l2 == NULL,
1817 : "failed: realloc should fail due to memory limit\n");
1818 :
1819 : /* Increase the memlimit */
1820 1 : printf("==== talloc_set_memlimit(pool, 11*1024)\n");
1821 1 : talloc_set_memlimit(pool, 11*1024);
1822 :
1823 : /* The final realloc should still fail
1824 : as the entire realloced chunk needs to be moved out of the pool */
1825 1 : printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n");
1826 1 : l2 = talloc_realloc_size(NULL, l1, 10*1024);
1827 1 : torture_assert("memlimit", l2 == NULL,
1828 : "failed: realloc should fail due to memory limit\n");
1829 :
1830 1 : talloc_report_full(pool, stdout);
1831 :
1832 1 : printf("==== talloc_set_memlimit(pool, 21*1024)\n");
1833 1 : talloc_set_memlimit(pool, 21*1024);
1834 :
1835 : /* There's now sufficient space to move the chunk out of the pool */
1836 1 : printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n");
1837 1 : l2 = talloc_realloc_size(NULL, l1, 10*1024);
1838 1 : torture_assert("memlimit", l2 != NULL,
1839 : "failed: realloc should not fail due to memory limit\n");
1840 :
1841 1 : talloc_report_full(pool, stdout);
1842 :
1843 : /* ...which should mean smaller allocations can now occur within the pool */
1844 1 : printf("==== talloc_size(pool, 9*1024)\n");
1845 1 : l1 = talloc_size(pool, 9*1024);
1846 1 : torture_assert("memlimit", l1 != NULL,
1847 : "failed: new allocations should be allowed in the pool\n");
1848 :
1849 1 : talloc_report_full(pool, stdout);
1850 :
1851 : /* But reallocs bigger than the pool will still fail */
1852 1 : printf("==== talloc_realloc_size(NULL, l1, 10*1024)\n");
1853 1 : l2 = talloc_realloc_size(NULL, l1, 10*1024);
1854 1 : torture_assert("memlimit", l2 == NULL,
1855 : "failed: realloc should fail due to memory limit\n");
1856 :
1857 1 : talloc_report_full(pool, stdout);
1858 :
1859 : /* ..as well as allocs */
1860 1 : printf("==== talloc_size(pool, 1024)\n");
1861 1 : l1 = talloc_size(pool, 1024);
1862 1 : torture_assert("memlimit", l1 == NULL,
1863 : "failed: alloc should fail due to memory limit\n");
1864 :
1865 1 : talloc_report_full(pool, stdout);
1866 :
1867 1 : printf("==== talloc_free_children(pool)\n");
1868 1 : talloc_free_children(pool);
1869 :
1870 1 : printf("==== talloc_set_memlimit(pool, 1024)\n");
1871 1 : talloc_set_memlimit(pool, 1024);
1872 :
1873 : /* We should still be able to allocate up to the pool limit
1874 : because the memlimit only applies to new heap allocations */
1875 1 : printf("==== talloc_size(pool, 9*1024)\n");
1876 1 : l1 = talloc_size(pool, 9*1024);
1877 1 : torture_assert("memlimit", l1 != NULL,
1878 : "failed: alloc should not fail due to memory limit\n");
1879 :
1880 1 : talloc_report_full(pool, stdout);
1881 :
1882 1 : l1 = talloc_size(pool, 1024);
1883 1 : torture_assert("memlimit", l1 == NULL,
1884 : "failed: alloc should fail due to memory limit\n");
1885 :
1886 1 : talloc_report_full(pool, stdout);
1887 :
1888 1 : printf("==== talloc_free_children(pool)\n");
1889 1 : talloc_free_children(pool);
1890 :
1891 1 : printf("==== talloc_set_memlimit(pool, 10*1024)\n");
1892 1 : talloc_set_memlimit(pool, 10*1024);
1893 :
1894 1 : printf("==== talloc_size(pool, 1024)\n");
1895 1 : l1 = talloc_size(pool, 1024);
1896 1 : torture_assert("memlimit", l1 != NULL,
1897 : "failed: alloc should not fail due to memory limit\n");
1898 :
1899 1 : talloc_report_full(pool, stdout);
1900 :
1901 1 : talloc_free(pool);
1902 1 : talloc_free(root);
1903 1 : printf("success: memlimit\n");
1904 :
1905 1 : return true;
1906 : }
1907 :
1908 : #ifdef HAVE_PTHREAD
1909 :
1910 : #define NUM_THREADS 100
1911 :
1912 : /* Sync variables. */
1913 : static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
1914 : static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
1915 : static void *intermediate_ptr;
1916 :
1917 : /* Subthread. */
1918 99 : static void *thread_fn(void *arg)
1919 : {
1920 : int ret;
1921 99 : const char *ctx_name = (const char *)arg;
1922 99 : void *sub_ctx = NULL;
1923 : /*
1924 : * Do stuff that creates a new talloc hierarchy in
1925 : * this thread.
1926 : */
1927 99 : void *top_ctx = talloc_named_const(NULL, 0, "top");
1928 100 : if (top_ctx == NULL) {
1929 0 : return NULL;
1930 : }
1931 100 : sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
1932 100 : if (sub_ctx == NULL) {
1933 0 : return NULL;
1934 : }
1935 :
1936 : /*
1937 : * Now transfer a pointer from our hierarchy
1938 : * onto the intermediate ptr.
1939 : */
1940 100 : ret = pthread_mutex_lock(&mtx);
1941 100 : if (ret != 0) {
1942 0 : talloc_free(top_ctx);
1943 0 : return NULL;
1944 : }
1945 : /* Wait for intermediate_ptr to be free. */
1946 638 : while (intermediate_ptr != NULL) {
1947 438 : ret = pthread_cond_wait(&condvar, &mtx);
1948 438 : if (ret != 0) {
1949 0 : talloc_free(top_ctx);
1950 0 : ret = pthread_mutex_unlock(&mtx);
1951 0 : assert(ret == 0);
1952 0 : return NULL;
1953 : }
1954 : }
1955 :
1956 : /* and move our memory onto it from our toplevel hierarchy. */
1957 100 : intermediate_ptr = talloc_move(NULL, &sub_ctx);
1958 :
1959 : /* Tell the main thread it's ready for pickup. */
1960 100 : pthread_cond_broadcast(&condvar);
1961 100 : ret = pthread_mutex_unlock(&mtx);
1962 100 : assert(ret == 0);
1963 :
1964 100 : talloc_free(top_ctx);
1965 100 : return NULL;
1966 : }
1967 :
1968 : /* Main thread. */
1969 1 : static bool test_pthread_talloc_passing(void)
1970 : {
1971 : int i;
1972 : int ret;
1973 : char str_array[NUM_THREADS][20];
1974 : pthread_t thread_id;
1975 : void *mem_ctx;
1976 :
1977 : /*
1978 : * Important ! Null tracking breaks threaded talloc.
1979 : * It *must* be turned off.
1980 : */
1981 1 : talloc_disable_null_tracking();
1982 :
1983 1 : printf("test: pthread_talloc_passing\n# PTHREAD TALLOC PASSING\n");
1984 :
1985 : /* Main thread toplevel context. */
1986 1 : mem_ctx = talloc_named_const(NULL, 0, "toplevel");
1987 1 : if (mem_ctx == NULL) {
1988 0 : printf("failed to create toplevel context\n");
1989 0 : return false;
1990 : }
1991 :
1992 : /*
1993 : * Spin off NUM_THREADS threads.
1994 : * They will use their own toplevel contexts.
1995 : */
1996 101 : for (i = 0; i < NUM_THREADS; i++) {
1997 100 : ret = snprintf(str_array[i],
1998 : 20,
1999 : "thread:%d",
2000 : i);
2001 100 : if (ret < 0) {
2002 0 : printf("snprintf %d failed\n", i);
2003 0 : return false;
2004 : }
2005 100 : ret = pthread_create(&thread_id,
2006 : NULL,
2007 : thread_fn,
2008 100 : str_array[i]);
2009 100 : if (ret != 0) {
2010 0 : printf("failed to create thread %d (%d)\n", i, ret);
2011 0 : return false;
2012 : }
2013 : }
2014 :
2015 1 : printf("Created %d threads\n", NUM_THREADS);
2016 :
2017 : /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */
2018 101 : for (i = 0; i < NUM_THREADS; i++) {
2019 100 : ret = pthread_mutex_lock(&mtx);
2020 100 : if (ret != 0) {
2021 0 : printf("pthread_mutex_lock %d failed (%d)\n", i, ret);
2022 0 : talloc_free(mem_ctx);
2023 0 : return false;
2024 : }
2025 :
2026 : /* Wait for intermediate_ptr to have our data. */
2027 258 : while (intermediate_ptr == NULL) {
2028 58 : ret = pthread_cond_wait(&condvar, &mtx);
2029 58 : if (ret != 0) {
2030 0 : printf("pthread_cond_wait %d failed (%d)\n", i,
2031 : ret);
2032 0 : talloc_free(mem_ctx);
2033 0 : ret = pthread_mutex_unlock(&mtx);
2034 0 : assert(ret == 0);
2035 : }
2036 : }
2037 :
2038 : /* and move it onto our toplevel hierarchy. */
2039 100 : (void)talloc_move(mem_ctx, &intermediate_ptr);
2040 :
2041 : /* Tell the sub-threads we're ready for another. */
2042 100 : pthread_cond_broadcast(&condvar);
2043 100 : ret = pthread_mutex_unlock(&mtx);
2044 100 : assert(ret == 0);
2045 : }
2046 :
2047 1 : CHECK_SIZE("pthread_talloc_passing", mem_ctx, NUM_THREADS * 100);
2048 : #if 1
2049 : /* Dump the hierarchy. */
2050 1 : talloc_report(mem_ctx, stdout);
2051 : #endif
2052 1 : talloc_free(mem_ctx);
2053 1 : printf("success: pthread_talloc_passing\n");
2054 1 : return true;
2055 : }
2056 : #endif
2057 :
2058 0 : static void test_magic_protection_abort(const char *reason)
2059 : {
2060 : /* exit with errcode 42 to communicate successful test to the parent process */
2061 0 : if (strcmp(reason, "Bad talloc magic value - unknown value") == 0) {
2062 0 : _exit(42);
2063 : } else {
2064 0 : printf("talloc aborted for an unexpected reason\n");
2065 : }
2066 0 : }
2067 :
2068 0 : static int test_magic_protection_destructor(int *ptr)
2069 : {
2070 0 : _exit(404); /* Not 42 */
2071 : }
2072 :
2073 1 : static bool test_magic_protection(void)
2074 : {
2075 1 : void *pool = talloc_pool(NULL, 1024);
2076 : int *p1, *p2;
2077 : pid_t pid;
2078 : int exit_status;
2079 :
2080 1 : printf("test: magic_protection\n");
2081 1 : p1 = talloc(pool, int);
2082 1 : p2 = talloc(pool, int);
2083 :
2084 : /* To avoid complaints from the compiler assign values to the p1 & p2. */
2085 1 : *p1 = 6;
2086 1 : *p2 = 9;
2087 :
2088 1 : pid = fork();
2089 1 : if (pid == 0) {
2090 0 : talloc_set_abort_fn(test_magic_protection_abort);
2091 0 : talloc_set_destructor(p2, test_magic_protection_destructor);
2092 :
2093 : /*
2094 : * Simulate a security attack
2095 : * by triggering a buffer overflow in memset to overwrite the
2096 : * constructor in the next pool chunk.
2097 : *
2098 : * Real attacks would attempt to set a real destructor.
2099 : */
2100 0 : memset(p1, '\0', 32);
2101 :
2102 : /* Then the attack takes effect when the memory's freed. */
2103 0 : talloc_free(pool);
2104 :
2105 : /* Never reached. Make compilers happy */
2106 0 : return true;
2107 : }
2108 :
2109 1 : while (wait(&exit_status) != pid);
2110 :
2111 1 : talloc_free(pool); /* make ASAN happy */
2112 :
2113 1 : if (!WIFEXITED(exit_status)) {
2114 0 : printf("Child exited through unexpected abnormal means\n");
2115 0 : return false;
2116 : }
2117 1 : if (WEXITSTATUS(exit_status) != 42) {
2118 0 : printf("Child exited with wrong exit status\n");
2119 0 : return false;
2120 : }
2121 1 : if (WIFSIGNALED(exit_status)) {
2122 0 : printf("Child received unexpected signal\n");
2123 0 : return false;
2124 : }
2125 :
2126 1 : printf("success: magic_protection\n");
2127 1 : return true;
2128 : }
2129 :
2130 0 : static void test_magic_free_protection_abort(const char *reason)
2131 : {
2132 : /* exit with errcode 42 to communicate successful test to the parent process */
2133 0 : if (strcmp(reason, "Bad talloc magic value - access after free") == 0) {
2134 0 : _exit(42);
2135 : }
2136 : /* not 42 */
2137 0 : _exit(404);
2138 : }
2139 :
2140 1 : static bool test_magic_free_protection(void)
2141 : {
2142 1 : void *pool = talloc_pool(NULL, 1024);
2143 : int *p1, *p2, *p3;
2144 : pid_t pid;
2145 : int exit_status;
2146 :
2147 1 : printf("test: magic_free_protection\n");
2148 1 : p1 = talloc(pool, int);
2149 1 : p2 = talloc(pool, int);
2150 :
2151 : /* To avoid complaints from the compiler assign values to the p1 & p2. */
2152 1 : *p1 = 6;
2153 1 : *p2 = 9;
2154 :
2155 1 : p3 = talloc_realloc(pool, p2, int, 2048);
2156 1 : torture_assert("pool realloc 2048",
2157 : p3 != p2,
2158 : "failed: pointer not changed");
2159 :
2160 : /*
2161 : * Now access the memory in the pool after the realloc(). It
2162 : * should be marked as free, so use of the old pointer should
2163 : * trigger the abort function
2164 : */
2165 1 : pid = fork();
2166 1 : if (pid == 0) {
2167 0 : talloc_set_abort_fn(test_magic_free_protection_abort);
2168 :
2169 0 : talloc_get_name(p2);
2170 :
2171 : /* Never reached. Make compilers happy */
2172 0 : return true;
2173 : }
2174 :
2175 1 : while (wait(&exit_status) != pid);
2176 :
2177 1 : if (!WIFEXITED(exit_status)) {
2178 0 : printf("Child exited through unexpected abnormal means\n");
2179 0 : return false;
2180 : }
2181 1 : if (WEXITSTATUS(exit_status) != 42) {
2182 0 : printf("Child exited with wrong exit status\n");
2183 0 : return false;
2184 : }
2185 1 : if (WIFSIGNALED(exit_status)) {
2186 0 : printf("Child received unexpected signal\n");
2187 0 : return false;
2188 : }
2189 :
2190 1 : talloc_free(pool);
2191 :
2192 1 : printf("success: magic_free_protection\n");
2193 1 : return true;
2194 : }
2195 :
2196 35 : static void test_reset(void)
2197 : {
2198 35 : talloc_set_log_fn(test_log_stdout);
2199 35 : test_abort_stop();
2200 35 : talloc_disable_null_tracking();
2201 35 : talloc_enable_null_tracking_no_autofree();
2202 35 : }
2203 :
2204 1 : bool torture_local_talloc(struct torture_context *tctx)
2205 : {
2206 1 : bool ret = true;
2207 :
2208 1 : setlinebuf(stdout);
2209 :
2210 1 : test_reset();
2211 1 : ret &= test_pooled_object();
2212 1 : test_reset();
2213 1 : ret &= test_pool_nest();
2214 1 : test_reset();
2215 1 : ret &= test_ref1();
2216 1 : test_reset();
2217 1 : ret &= test_ref2();
2218 1 : test_reset();
2219 1 : ret &= test_ref3();
2220 1 : test_reset();
2221 1 : ret &= test_ref4();
2222 1 : test_reset();
2223 1 : ret &= test_unlink1();
2224 1 : test_reset();
2225 1 : ret &= test_misc();
2226 1 : test_reset();
2227 1 : ret &= test_realloc();
2228 1 : test_reset();
2229 1 : ret &= test_realloc_child();
2230 1 : test_reset();
2231 1 : ret &= test_steal();
2232 1 : test_reset();
2233 1 : ret &= test_move();
2234 1 : test_reset();
2235 1 : ret &= test_unref_reparent();
2236 1 : test_reset();
2237 1 : ret &= test_realloc_fn();
2238 1 : test_reset();
2239 1 : ret &= test_type();
2240 1 : test_reset();
2241 1 : ret &= test_lifeless();
2242 1 : test_reset();
2243 1 : ret &= test_loop();
2244 1 : test_reset();
2245 1 : ret &= test_free_parent_deny_child();
2246 1 : test_reset();
2247 1 : ret &= test_realloc_on_destructor_parent();
2248 1 : test_reset();
2249 1 : ret &= test_free_parent_reparent_child();
2250 1 : test_reset();
2251 1 : ret &= test_free_parent_reparent_child_in_pool();
2252 1 : test_reset();
2253 1 : ret &= test_talloc_ptrtype();
2254 1 : test_reset();
2255 1 : ret &= test_talloc_free_in_destructor();
2256 1 : test_reset();
2257 1 : ret &= test_pool();
2258 1 : test_reset();
2259 1 : ret &= test_pool_steal();
2260 1 : test_reset();
2261 1 : ret &= test_free_ref_null_context();
2262 1 : test_reset();
2263 1 : ret &= test_rusty();
2264 1 : test_reset();
2265 1 : ret &= test_free_children();
2266 1 : test_reset();
2267 1 : ret &= test_memlimit();
2268 : #ifdef HAVE_PTHREAD
2269 1 : test_reset();
2270 1 : ret &= test_pthread_talloc_passing();
2271 : #endif
2272 :
2273 :
2274 1 : if (ret) {
2275 1 : test_reset();
2276 1 : ret &= test_speed();
2277 : }
2278 1 : test_reset();
2279 1 : ret &= test_autofree();
2280 1 : test_reset();
2281 1 : ret &= test_magic_protection();
2282 1 : test_reset();
2283 1 : ret &= test_magic_free_protection();
2284 :
2285 1 : test_reset();
2286 1 : talloc_disable_null_tracking();
2287 1 : return ret;
2288 : }
|