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