talloc: use the system pytalloc-util for python3 as well
[sfrench/samba-autobuild/.git] / lib / talloc / testsuite.c
index 8845d960c15423ac409ca083babeb3790eb70eb4..dfaeec1d1d979ef7b9f38de91349408b4ce1f602 100644 (file)
 
 #include "replace.h"
 #include "system/time.h"
-#include "talloc.h"
+#include <talloc.h>
 
-static struct timeval timeval_current(void)
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#include <unistd.h>
+#include <sys/wait.h>
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+
+#include "talloc_testsuite.h"
+
+static struct timeval private_timeval_current(void)
 {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        return tv;
 }
 
-static double timeval_elapsed(struct timeval *tv)
+static double private_timeval_elapsed(struct timeval *tv)
 {
-       struct timeval tv2 = timeval_current();
+       struct timeval tv2 = private_timeval_current();
        return (tv2.tv_sec - tv->tv_sec) + 
               (tv2.tv_usec - tv->tv_usec)*1.0e-6;
 }
@@ -55,15 +70,6 @@ static double timeval_elapsed(struct timeval *tv)
                return false; \
        }
 
-#if _SAMBA_BUILD_==3
-#ifdef malloc
-#undef malloc
-#endif
-#ifdef strdup
-#undef strdup
-#endif
-#endif
-
 #define CHECK_SIZE(test, ptr, tsize) do { \
        if (talloc_total_size(ptr) != (tsize)) { \
                printf("failed: %s [\n%s: wrong '%s' tree size: got %u  expected %u\n]\n", \
@@ -101,6 +107,7 @@ static double timeval_elapsed(struct timeval *tv)
 
 static unsigned int test_abort_count;
 
+#if 0
 static void test_abort_fn(const char *reason)
 {
        printf("# test_abort_fn(%s)\n", reason);
@@ -112,6 +119,7 @@ static void test_abort_start(void)
        test_abort_count = 0;
        talloc_set_abort_fn(test_abort_fn);
 }
+#endif
 
 static void test_abort_stop(void)
 {
@@ -146,6 +154,7 @@ static bool test_ref1(void)
 
        CHECK_BLOCKS("ref1", p1, 5);
        CHECK_BLOCKS("ref1", p2, 1);
+       CHECK_BLOCKS("ref1", ref, 1);
        CHECK_BLOCKS("ref1", r1, 2);
 
        fprintf(stderr, "Freeing p2\n");
@@ -254,6 +263,7 @@ static bool test_ref3(void)
        CHECK_BLOCKS("ref3", p1, 2);
        CHECK_BLOCKS("ref3", p2, 2);
        CHECK_BLOCKS("ref3", r1, 1);
+       CHECK_BLOCKS("ref3", ref, 1);
 
        fprintf(stderr, "Freeing p1\n");
        talloc_free(p1);
@@ -296,6 +306,7 @@ static bool test_ref4(void)
 
        CHECK_BLOCKS("ref4", p1, 5);
        CHECK_BLOCKS("ref4", p2, 1);
+       CHECK_BLOCKS("ref4", ref, 1);
        CHECK_BLOCKS("ref4", r1, 2);
 
        fprintf(stderr, "Freeing r1\n");
@@ -346,6 +357,7 @@ static bool test_unlink1(void)
 
        CHECK_BLOCKS("unlink", p1, 7);
        CHECK_BLOCKS("unlink", p2, 1);
+       CHECK_BLOCKS("unlink", ref, 1);
        CHECK_BLOCKS("unlink", r1, 2);
 
        fprintf(stderr, "Unreferencing r1\n");
@@ -414,6 +426,8 @@ static bool test_misc(void)
        name = talloc_set_name(p1, "my name is %s", "foo");
        torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
                "failed: wrong name after talloc_set_name(my name is foo)");
+       torture_assert_str_equal("misc", talloc_get_name(p1), name,
+               "failed: wrong name after talloc_set_name(my name is foo)");
        CHECK_BLOCKS("misc", p1, 2);
        CHECK_BLOCKS("misc", root, 3);
 
@@ -518,6 +532,7 @@ static bool test_misc(void)
 
        CHECK_SIZE("misc", NULL, 0);
 
+       talloc_enable_null_tracking_no_autofree();
        talloc_enable_leak_report();
        talloc_enable_leak_report_full();
 
@@ -595,7 +610,7 @@ static bool test_realloc_child(void)
        void *root;
        struct el2 {
                const char *name;
-       } *el2
+       } *el2, *el2_2, *el2_3, **el_list_save;
        struct el1 {
                int count;
                struct el2 **list, **list2, **list3;
@@ -619,12 +634,34 @@ static bool test_realloc_child(void)
        el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
        
        el2 = talloc(el1->list, struct el2);
-       el2 = talloc(el1->list2, struct el2);
-       el2 = talloc(el1->list3, struct el2);
+       CHECK_PARENT("el2", el2, el1->list);
+       el2_2 = talloc(el1->list2, struct el2);
+       CHECK_PARENT("el2", el2_2, el1->list2);
+       el2_3 = talloc(el1->list3, struct el2);
+       CHECK_PARENT("el2", el2_3, el1->list3);
 
+       el_list_save = el1->list;
        el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+       if (el1->list == el_list_save) {
+               printf("failure: talloc_realloc didn't move pointer");
+               return false;
+       }
+
+       CHECK_PARENT("el1_after_realloc", el1->list, el1);
        el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
+       CHECK_PARENT("el1_after_realloc", el1->list2, el1);
        el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
+       CHECK_PARENT("el1_after_realloc", el1->list3, el1);
+
+       CHECK_PARENT("el2", el2, el1->list);
+       CHECK_PARENT("el2", el2_2, el1->list2);
+       CHECK_PARENT("el2", el2_3, el1->list3);
+
+       /* Finally check realloc with multiple children */
+       el1 = talloc_realloc(root, el1, struct el1, 100);
+       CHECK_PARENT("el1->list", el1->list, el1);
+       CHECK_PARENT("el1->list2", el1->list2, el1);
+       CHECK_PARENT("el1->list3", el1->list3, el1);
 
        talloc_free(root);
 
@@ -825,7 +862,7 @@ static bool test_speed(void)
 
        printf("test: speed\n# TALLOC VS MALLOC SPEED\n");
 
-       tv = timeval_current();
+       tv = private_timeval_current();
        count = 0;
        do {
                void *p1, *p2, *p3;
@@ -833,18 +870,20 @@ static bool test_speed(void)
                        p1 = talloc_size(ctx, loop % 100);
                        p2 = talloc_strdup(p1, "foo bar");
                        p3 = talloc_size(p1, 300);
+                       (void)p2;
+                       (void)p3;
                        talloc_free(p1);
                }
                count += 3 * loop;
-       } while (timeval_elapsed(&tv) < 5.0);
+       } while (private_timeval_elapsed(&tv) < 5.0);
 
-       fprintf(stderr, "talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+       fprintf(stderr, "talloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
 
        talloc_free(ctx);
 
        ctx = talloc_pool(NULL, 1024);
 
-       tv = timeval_current();
+       tv = private_timeval_current();
        count = 0;
        do {
                void *p1, *p2, *p3;
@@ -852,16 +891,18 @@ static bool test_speed(void)
                        p1 = talloc_size(ctx, loop % 100);
                        p2 = talloc_strdup(p1, "foo bar");
                        p3 = talloc_size(p1, 300);
-                       talloc_free_children(ctx);
+                       (void)p2;
+                       (void)p3;
+                       talloc_free(p1);
                }
                count += 3 * loop;
-       } while (timeval_elapsed(&tv) < 5.0);
+       } while (private_timeval_elapsed(&tv) < 5.0);
 
        talloc_free(ctx);
 
-       fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+       fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
 
-       tv = timeval_current();
+       tv = private_timeval_current();
        count = 0;
        do {
                void *p1, *p2, *p3;
@@ -874,8 +915,8 @@ static bool test_speed(void)
                        free(p3);
                }
                count += 3 * loop;
-       } while (timeval_elapsed(&tv) < 5.0);
-       fprintf(stderr, "malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
+       } while (private_timeval_elapsed(&tv) < 5.0);
+       fprintf(stderr, "malloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
 
        printf("success: speed\n");
 
@@ -944,6 +985,57 @@ static bool test_loop(void)
        return true;
 }
 
+static int realloc_parent_destructor_count;
+
+static int test_realloc_parent_destructor(char *ptr)
+{
+       realloc_parent_destructor_count++;
+       return 0;
+}
+
+static bool test_realloc_on_destructor_parent(void)
+{
+       void *top = talloc_new(NULL);
+       char *parent;
+       char *a, *b, *C, *D;
+       realloc_parent_destructor_count = 0;
+
+       printf("test: free_for_exit\n# TALLOC FREE FOR EXIT\n");
+
+       parent = talloc_strdup(top, "parent");
+       a = talloc_strdup(parent, "a");
+       b = talloc_strdup(a, "b");
+       C = talloc_strdup(a, "C");
+       D = talloc_strdup(b, "D");
+       talloc_set_destructor(D, test_realloc_parent_destructor);
+       /* Capitalised ones have destructors.
+        *
+        * parent --> a -> b -> D
+        *              -> c
+        */
+
+       a = talloc_realloc(parent, a, char, 2048);
+
+       torture_assert("check talloc_realloc", a != NULL, "talloc_realloc failed");
+
+       talloc_set_destructor(C, test_realloc_parent_destructor);
+       /*
+        * parent --> a[2048] -> b -> D
+        *                    -> C
+        *
+        */
+
+       talloc_free(parent);
+
+       torture_assert("check destructor realloc_parent_destructor",
+                      realloc_parent_destructor_count == 2,
+                      "FAILED TO FIRE free_for_exit_destructor\n");
+
+
+       printf("success: free_for_exit\n");
+       return true;
+}
+
 static int fail_destructor_str(char *ptr)
 {
        return -1;
@@ -974,6 +1066,84 @@ static bool test_free_parent_deny_child(void)
        return true;
 }
 
+struct new_parent {
+       void *new_parent;
+       char val[20];
+};
+
+static int reparenting_destructor(struct new_parent *np)
+{
+       talloc_set_destructor(np, NULL);
+       (void)talloc_move(np->new_parent, &np);
+       return -1;
+}
+
+static bool test_free_parent_reparent_child(void)
+{
+       void *top = talloc_new(NULL);
+       char *level1;
+       char *alternate_level1;
+       char *level2;
+       struct new_parent *level3;
+
+       printf("test: free_parent_reparent_child\n# "
+               "TALLOC FREE PARENT REPARENT CHILD\n");
+
+       level1 = talloc_strdup(top, "level1");
+       alternate_level1 = talloc_strdup(top, "alternate_level1");
+       level2 = talloc_strdup(level1, "level2");
+       level3 = talloc(level2, struct new_parent);
+       level3->new_parent = alternate_level1;
+       memset(level3->val, 'x', sizeof(level3->val));
+
+       talloc_set_destructor(level3, reparenting_destructor);
+       talloc_free(level1);
+
+       CHECK_PARENT("free_parent_reparent_child",
+               level3, alternate_level1);
+
+       talloc_free(top);
+
+       printf("success: free_parent_reparent_child\n");
+       return true;
+}
+
+static bool test_free_parent_reparent_child_in_pool(void)
+{
+       void *top = talloc_new(NULL);
+       char *level1;
+       char *alternate_level1;
+       char *level2;
+       void *pool;
+       struct new_parent *level3;
+
+       printf("test: free_parent_reparent_child_in_pool\n# "
+               "TALLOC FREE PARENT REPARENT CHILD IN POOL\n");
+
+       pool = talloc_pool(top, 1024);
+       level1 = talloc_strdup(pool, "level1");
+       alternate_level1 = talloc_strdup(top, "alternate_level1");
+       level2 = talloc_strdup(level1, "level2");
+       level3 = talloc(level2, struct new_parent);
+       level3->new_parent = alternate_level1;
+       memset(level3->val, 'x', sizeof(level3->val));
+
+       talloc_set_destructor(level3, reparenting_destructor);
+       talloc_free(level1);
+       talloc_set_destructor(level3, NULL);
+
+       CHECK_PARENT("free_parent_reparent_child_in_pool",
+               level3, alternate_level1);
+
+       /* Even freeing alternate_level1 should leave pool alone. */
+       talloc_free(alternate_level1);
+       talloc_free(top);
+
+       printf("success: free_parent_reparent_child_in_pool\n");
+       return true;
+}
+
+
 static bool test_talloc_ptrtype(void)
 {
        void *top = talloc_new(NULL);
@@ -1118,16 +1288,721 @@ static bool test_pool(void)
 {
        void *pool;
        void *p1, *p2, *p3, *p4;
+       void *p2_2;
 
        pool = talloc_pool(NULL, 1024);
 
        p1 = talloc_size(pool, 80);
+       memset(p1, 0x11, talloc_get_size(p1));
        p2 = talloc_size(pool, 20);
+       memset(p2, 0x11, talloc_get_size(p2));
        p3 = talloc_size(p1, 50);
+       memset(p3, 0x11, talloc_get_size(p3));
        p4 = talloc_size(p3, 1000);
+       memset(p4, 0x11, talloc_get_size(p4));
+
+#if 1 /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
+       p2_2 = talloc_realloc_size(pool, p2, 20+1);
+       torture_assert("pool realloc 20+1", p2_2 == p2, "failed: pointer changed");
+       memset(p2, 0x11, talloc_get_size(p2));
+       p2_2 = talloc_realloc_size(pool, p2, 20-1);
+       torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+       memset(p2, 0x11, talloc_get_size(p2));
+       p2_2 = talloc_realloc_size(pool, p2, 20-1);
+       torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       talloc_free(p3);
+
+       /* this should reclaim the memory of p4 and p3 */
+       p2_2 = talloc_realloc_size(pool, p2, 400);
+       torture_assert("pool realloc 400", p2_2 == p2, "failed: pointer changed");
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       talloc_free(p1);
+
+       /* this should reclaim the memory of p1 */
+       p2_2 = talloc_realloc_size(pool, p2, 800);
+       torture_assert("pool realloc 800", p2_2 == p1, "failed: pointer not changed");
+       p2 = p2_2;
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       /* this should do a malloc */
+       p2_2 = talloc_realloc_size(pool, p2, 1800);
+       torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
+       p2 = p2_2;
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       /* this should reclaim the memory from the pool */
+       p3 = talloc_size(pool, 80);
+       torture_assert("pool alloc 80", p3 == p1, "failed: pointer changed");
+       memset(p3, 0x11, talloc_get_size(p3));
+
+       talloc_free(p2);
+       talloc_free(p3);
+
+       p1 = talloc_size(pool, 80);
+       memset(p1, 0x11, talloc_get_size(p1));
+       p2 = talloc_size(pool, 20);
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       talloc_free(p1);
+
+       p2_2 = talloc_realloc_size(pool, p2, 20-1);
+       torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+       memset(p2, 0x11, talloc_get_size(p2));
+       p2_2 = talloc_realloc_size(pool, p2, 20-1);
+       torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       /* this should do a malloc */
+       p2_2 = talloc_realloc_size(pool, p2, 1800);
+       torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
+       p2 = p2_2;
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       /* this should reclaim the memory from the pool */
+       p3 = talloc_size(pool, 800);
+       torture_assert("pool alloc 800", p3 == p1, "failed: pointer changed");
+       memset(p3, 0x11, talloc_get_size(p3));
+
+#endif /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
+
+       talloc_free(pool);
+
+       return true;
+}
+
+static bool test_pool_steal(void)
+{
+       void *root;
+       void *pool;
+       void *p1, *p2;
+       void *p1_2, *p2_2;
+       size_t hdr;
+       size_t ofs1, ofs2;
+
+       root = talloc_new(NULL);
+       pool = talloc_pool(root, 1024);
+
+       p1 = talloc_size(pool, 4 * 16);
+       torture_assert("pool allocate 4 * 16", p1 != NULL, "failed ");
+       memset(p1, 0x11, talloc_get_size(p1));
+       p2 = talloc_size(pool, 4 * 16);
+       torture_assert("pool allocate 4 * 16", p2 > p1, "failed: !(p2 > p1) ");
+       memset(p2, 0x11, talloc_get_size(p2));
+
+       ofs1 = PTR_DIFF(p2, p1);
+       hdr = ofs1 - talloc_get_size(p1);
+
+       talloc_steal(root, p1);
+       talloc_steal(root, p2);
 
        talloc_free(pool);
 
+       p1_2 = p1;
+
+#if 1 /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
+       p1_2 = talloc_realloc_size(root, p1, 5 * 16);
+       torture_assert("pool realloc 5 * 16", p1_2 > p2, "failed: pointer not changed");
+       memset(p1_2, 0x11, talloc_get_size(p1_2));
+       ofs1 = PTR_DIFF(p1_2, p2);
+       ofs2 = talloc_get_size(p2) + hdr;
+
+       torture_assert("pool realloc ", ofs1 == ofs2, "failed: pointer offset unexpected");
+
+       p2_2 = talloc_realloc_size(root, p2, 3 * 16);
+       torture_assert("pool realloc 5 * 16", p2_2 == p2, "failed: pointer changed");
+       memset(p2_2, 0x11, talloc_get_size(p2_2));
+#endif /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
+
+       talloc_free(p1_2);
+
+       p2_2 = p2;
+
+#if 1 /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
+       /* now we should reclaim the full pool */
+       p2_2 = talloc_realloc_size(root, p2, 8 * 16);
+       torture_assert("pool realloc 8 * 16", p2_2 == p1, "failed: pointer not expected");
+       p2 = p2_2;
+       memset(p2_2, 0x11, talloc_get_size(p2_2));
+
+       /* now we malloc and free the full pool space */
+       p2_2 = talloc_realloc_size(root, p2, 2 * 1024);
+       torture_assert("pool realloc 2 * 1024", p2_2 != p1, "failed: pointer not expected");
+       memset(p2_2, 0x11, talloc_get_size(p2_2));
+
+#endif /* this relies on ALWAYS_REALLOC == 0 in talloc.c */
+
+       talloc_free(p2_2);
+
+       talloc_free(root);
+
+       return true;
+}
+
+static bool test_pool_nest(void)
+{
+       void *p1, *p2, *p3;
+       void *e = talloc_new(NULL);
+
+       p1 = talloc_pool(NULL, 1024);
+       torture_assert("talloc_pool", p1 != NULL, "failed");
+
+       p2 = talloc_pool(p1, 500);
+       torture_assert("talloc_pool", p2 != NULL, "failed");
+
+       p3 = talloc_size(p2, 10);
+
+       talloc_steal(e, p3);
+
+       talloc_free(p2);
+
+       talloc_free(p3);
+
+       talloc_free(p1);
+
+       return true;
+}
+
+struct pooled {
+       char *s1;
+       char *s2;
+       char *s3;
+};
+
+static bool test_pooled_object(void)
+{
+       struct pooled *p;
+       const char *s1 = "hello";
+       const char *s2 = "world";
+       const char *s3 = "";
+
+       p = talloc_pooled_object(NULL, struct pooled, 3,
+                       strlen(s1)+strlen(s2)+strlen(s3)+3);
+
+       if (talloc_get_size(p) != sizeof(struct pooled)) {
+               return false;
+       }
+
+       p->s1 = talloc_strdup(p, s1);
+
+       TALLOC_FREE(p->s1);
+       p->s1 = talloc_strdup(p, s2);
+       TALLOC_FREE(p->s1);
+
+       p->s1 = talloc_strdup(p, s1);
+       p->s2 = talloc_strdup(p, s2);
+       p->s3 = talloc_strdup(p, s3);
+
+       TALLOC_FREE(p);
+       return true;
+}
+
+static bool test_free_ref_null_context(void)
+{
+       void *p1, *p2, *p3;
+       int ret;
+
+       talloc_disable_null_tracking();
+       p1 = talloc_new(NULL);
+       p2 = talloc_new(NULL);
+
+       p3 = talloc_reference(p2, p1);
+       torture_assert("reference", p3 == p1, "failed: reference on null");
+
+       ret = talloc_free(p1);
+       torture_assert("ref free with null parent", ret == 0, "failed: free with null parent");
+       talloc_free(p2);
+
+       talloc_enable_null_tracking_no_autofree();
+       p1 = talloc_new(NULL);
+       p2 = talloc_new(NULL);
+
+       p3 = talloc_reference(p2, p1);
+       torture_assert("reference", p3 == p1, "failed: reference on null");
+
+       ret = talloc_free(p1);
+       torture_assert("ref free with null tracked parent", ret == 0, "failed: free with null parent");
+       talloc_free(p2);
+
+       return true;
+}
+
+static bool test_rusty(void)
+{
+       void *root;
+       const char *p1;
+
+       talloc_enable_null_tracking();
+       root = talloc_new(NULL);
+       p1 = talloc_strdup(root, "foo");
+       talloc_increase_ref_count(p1);
+       talloc_report_full(root, stdout);
+       talloc_free(root);
+       CHECK_BLOCKS("null_context", NULL, 2);
+       return true;
+}
+
+static bool test_free_children(void)
+{
+       void *root;
+       char *p1, *p2;
+       const char *name, *name2;
+
+       talloc_enable_null_tracking();
+       root = talloc_new(NULL);
+       p1 = talloc_strdup(root, "foo1");
+       p2 = talloc_strdup(p1, "foo2");
+       (void)p2;
+
+       talloc_set_name(p1, "%s", "testname");
+       talloc_free_children(p1);
+       /* check its still a valid talloc ptr */
+       talloc_get_size(talloc_get_name(p1));
+       if (strcmp(talloc_get_name(p1), "testname") != 0) {
+               return false;
+       }
+
+       talloc_set_name(p1, "%s", "testname");
+       name = talloc_get_name(p1);
+       talloc_free_children(p1);
+       /* check its still a valid talloc ptr */
+       talloc_get_size(talloc_get_name(p1));
+       torture_assert("name", name == talloc_get_name(p1), "name ptr changed");
+       torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname") == 0,
+                      "wrong name");
+       CHECK_BLOCKS("name1", p1, 2);
+
+       /* note that this does not free the old child name */
+       talloc_set_name_const(p1, "testname2");
+       name2 = talloc_get_name(p1);
+       /* but this does */
+       talloc_free_children(p1);
+       (void)name2;
+       torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname2") == 0,
+                      "wrong name");
+       CHECK_BLOCKS("name1", p1, 1);
+
+       talloc_report_full(root, stdout);
+       talloc_free(root);
+       return true;
+}
+
+static bool test_memlimit(void)
+{
+       void *root;
+       char *l1, *l2, *l3, *l4, *l5, *t;
+       char *pool;
+       int i;
+
+       printf("test: memlimit\n# MEMORY LIMITS\n");
+
+       printf("==== talloc_new(NULL)\n");
+       root = talloc_new(NULL);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_size(root, 2048)\n");
+       l1 = talloc_size(root, 2048);
+       torture_assert("memlimit", l1 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_free(l1)\n");
+       talloc_free(l1);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(root, level 1)\n");
+       l1 = talloc_strdup(root, "level 1");
+       torture_assert("memlimit", l1 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_set_memlimit(l1, 2048)\n");
+       torture_assert("memlimit", talloc_set_memlimit(l1, 2048) == 0,
+               "failed: setting memlimit should never fail\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_size(root, 2048)\n");
+       l2 = talloc_size(l1, 2048);
+       torture_assert("memlimit", l2 == NULL,
+               "failed: alloc should fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l1, level 2)\n");
+       l2 = talloc_strdup(l1, "level 2");
+       torture_assert("memlimit", l2 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_free(l2)\n");
+       talloc_free(l2);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_size(NULL, 2048)\n");
+       l2 = talloc_size(NULL, 2048);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_steal(l1, l2)\n");
+       talloc_steal(l1, l2);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l2, level 3)\n");
+       l3 = talloc_strdup(l2, "level 3");
+       torture_assert("memlimit", l3 == NULL,
+               "failed: alloc should fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_free(l2)\n");
+       talloc_free(l2);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(NULL, level 2)\n");
+       l2 = talloc_strdup(NULL, "level 2");
+       talloc_steal(l1, l2);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l2, level 3)\n");
+       l3 = talloc_strdup(l2, "level 3");
+       torture_assert("memlimit", l3 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_set_memlimit(l3, 1024)\n");
+       torture_assert("memlimit", talloc_set_memlimit(l3, 1024) == 0,
+               "failed: setting memlimit should never fail\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l3, level 4)\n");
+       l4 = talloc_strdup(l3, "level 4");
+       torture_assert("memlimit", l4 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_set_memlimit(l4, 512)\n");
+       torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0,
+               "failed: setting memlimit should never fail\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l4, level 5)\n");
+       l5 = talloc_strdup(l4, "level 5");
+       torture_assert("memlimit", l5 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_realloc(NULL, l5, char, 600)\n");
+       t = talloc_realloc(NULL, l5, char, 600);
+       torture_assert("memlimit", t == NULL,
+               "failed: alloc should fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_realloc(NULL, l5, char, 5)\n");
+       l5 = talloc_realloc(NULL, l5, char, 5);
+       torture_assert("memlimit", l5 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l3, level 4)\n");
+       l4 = talloc_strdup(l3, "level 4");
+       torture_assert("memlimit", l4 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_set_memlimit(l4, 512)\n");
+       torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0,
+               "failed: setting memlimit should never fail\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_strdup(l4, level 5)\n");
+       l5 = talloc_strdup(l4, "level 5");
+       torture_assert("memlimit", l5 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+
+       printf("==== Make new temp context and steal l5\n");
+       t = talloc_new(root);
+       talloc_steal(t, l5);
+
+       talloc_report_full(root, stdout);
+
+       printf("==== talloc_size(t, 2048)\n");
+       l1 = talloc_size(t, 2048);
+       torture_assert("memlimit", l1 != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+
+       talloc_report_full(root, stdout);
+       talloc_free(root);
+
+       /* Test memlimits with pools. */
+       pool = talloc_pool(NULL, 10*1024);
+       torture_assert("memlimit", pool != NULL,
+               "failed: alloc should not fail due to memory limit\n");
+       talloc_set_memlimit(pool, 10*1024);
+       for (i = 0; i < 9; i++) {
+               l1 = talloc_size(pool, 1024);
+               torture_assert("memlimit", l1 != NULL,
+                       "failed: alloc should not fail due to memory limit\n");
+       }
+       /* The next alloc should fail. */
+       l2 = talloc_size(pool, 1024);
+       torture_assert("memlimit", l2 == NULL,
+                       "failed: alloc should fail due to memory limit\n");
+
+       /* Moving one of the children shouldn't change the limit,
+          as it's still inside the pool. */
+       root = talloc_new(NULL);
+       talloc_steal(root, l1);
+       l2 = talloc_size(pool, 1024);
+       torture_assert("memlimit", l2 == NULL,
+                       "failed: alloc should fail due to memory limit\n");
+
+       talloc_free(pool);
+       talloc_free(root);
+       printf("success: memlimit\n");
+
+       return true;
+}
+
+#ifdef HAVE_PTHREAD
+
+#define NUM_THREADS 100
+
+/* Sync variables. */
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
+static void *intermediate_ptr;
+
+/* Subthread. */
+static void *thread_fn(void *arg)
+{
+       int ret;
+       const char *ctx_name = (const char *)arg;
+       void *sub_ctx = NULL;
+       /*
+        * Do stuff that creates a new talloc hierarchy in
+        * this thread.
+        */
+       void *top_ctx = talloc_named_const(NULL, 0, "top");
+       if (top_ctx == NULL) {
+               return NULL;
+       }
+       sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
+       if (sub_ctx == NULL) {
+               return NULL;
+       }
+
+       /*
+        * Now transfer a pointer from our hierarchy
+        * onto the intermediate ptr.
+        */
+       ret = pthread_mutex_lock(&mtx);
+       if (ret != 0) {
+               talloc_free(top_ctx);
+               return NULL;
+       }
+       /* Wait for intermediate_ptr to be free. */
+       while (intermediate_ptr != NULL) {
+               ret = pthread_cond_wait(&condvar, &mtx);
+               if (ret != 0) {
+                       talloc_free(top_ctx);
+                       ret = pthread_mutex_unlock(&mtx);
+                       assert(ret == 0);
+                       return NULL;
+               }
+       }
+
+       /* and move our memory onto it from our toplevel hierarchy. */
+       intermediate_ptr = talloc_move(NULL, &sub_ctx);
+
+       /* Tell the main thread it's ready for pickup. */
+       pthread_cond_broadcast(&condvar);
+       ret = pthread_mutex_unlock(&mtx);
+       assert(ret == 0);
+
+       talloc_free(top_ctx);
+       return NULL;
+}
+
+/* Main thread. */
+static bool test_pthread_talloc_passing(void)
+{
+       int i;
+       int ret;
+       char str_array[NUM_THREADS][20];
+       pthread_t thread_id;
+       void *mem_ctx;
+
+       /*
+        * Important ! Null tracking breaks threaded talloc.
+        * It *must* be turned off.
+        */
+       talloc_disable_null_tracking();
+
+       printf("test: pthread_talloc_passing\n# PTHREAD TALLOC PASSING\n");
+
+       /* Main thread toplevel context. */
+       mem_ctx = talloc_named_const(NULL, 0, "toplevel");
+       if (mem_ctx == NULL) {
+               printf("failed to create toplevel context\n");
+               return false;
+       }
+
+       /*
+        * Spin off NUM_THREADS threads.
+        * They will use their own toplevel contexts.
+        */
+       for (i = 0; i < NUM_THREADS; i++) {
+               ret = snprintf(str_array[i],
+                              20,
+                              "thread:%d",
+                              i);
+               if (ret < 0) {
+                       printf("snprintf %d failed\n", i);
+                       return false;
+               }
+               ret = pthread_create(&thread_id,
+                               NULL,
+                               thread_fn,
+                               str_array[i]);
+               if (ret != 0) {
+                       printf("failed to create thread %d (%d)\n", i, ret);
+                       return false;
+               }
+       }
+
+       printf("Created %d threads\n", NUM_THREADS);
+
+       /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */
+       for (i = 0; i < NUM_THREADS; i++) {
+               ret = pthread_mutex_lock(&mtx);
+               if (ret != 0) {
+                       printf("pthread_mutex_lock %d failed (%d)\n", i, ret);
+                       talloc_free(mem_ctx);
+                       return false;
+               }
+
+               /* Wait for intermediate_ptr to have our data. */
+               while (intermediate_ptr == NULL) {
+                       ret = pthread_cond_wait(&condvar, &mtx);
+                       if (ret != 0) {
+                               printf("pthread_cond_wait %d failed (%d)\n", i,
+                                       ret);
+                               talloc_free(mem_ctx);
+                               ret = pthread_mutex_unlock(&mtx);
+                               assert(ret == 0);
+                       }
+               }
+
+               /* and move it onto our toplevel hierarchy. */
+               (void)talloc_move(mem_ctx, &intermediate_ptr);
+
+               /* Tell the sub-threads we're ready for another. */
+               pthread_cond_broadcast(&condvar);
+               ret = pthread_mutex_unlock(&mtx);
+               assert(ret == 0);
+       }
+
+       CHECK_SIZE("pthread_talloc_passing", mem_ctx, NUM_THREADS * 100);
+#if 1
+       /* Dump the hierarchy. */
+       talloc_report(mem_ctx, stdout);
+#endif
+       talloc_free(mem_ctx);
+       printf("success: pthread_talloc_passing\n");
+       return true;
+}
+#endif
+
+static void test_magic_protection_abort(const char *reason)
+{
+       /* exit with errcode 42 to communicate successful test to the parent process */
+       if (strcmp(reason, "Bad talloc magic value - unknown value") == 0) {
+               _exit(42);
+       } else {
+               printf("talloc aborted for an unexpected reason\n");
+       }
+}
+
+static int test_magic_protection_destructor(int *ptr)
+{
+       _exit(404); /* Not 42 */
+}
+
+static bool test_magic_protection(void)
+{
+       void *pool = talloc_pool(NULL, 1024);
+       int *p1, *p2;
+       pid_t pid;
+       int exit_status;
+
+       printf("test: magic_protection\n");
+       p1 = talloc(pool, int);
+       p2 = talloc(pool, int);
+
+       /* To avoid complaints from the compiler assign values to the p1 & p2. */
+       *p1 = 6;
+       *p2 = 9;
+
+       pid = fork();
+       if (pid == 0) {
+               talloc_set_abort_fn(test_magic_protection_abort);
+               talloc_set_destructor(p2, test_magic_protection_destructor);
+
+               /*
+                * Simulate a security attack
+                * by triggering a buffer overflow in memset to overwrite the
+                * constructor in the next pool chunk.
+                *
+                * Real attacks would attempt to set a real destructor.
+                */
+               memset(p1, '\0', 32);
+
+               /* Then the attack takes effect when the memory's freed. */
+               talloc_free(pool);
+
+               /* Never reached. Make compilers happy */
+               return true;
+       }
+
+       while (wait(&exit_status) != pid);
+
+       if (!WIFEXITED(exit_status)) {
+               printf("Child exited through unexpected abnormal means\n");
+               return false;
+       }
+       if (WEXITSTATUS(exit_status) != 42) {
+               printf("Child exited with wrong exit status\n");
+               return false;
+       }
+       if (WIFSIGNALED(exit_status)) {
+               printf("Child recieved unexpected signal\n");
+               return false;
+       }
+
+       printf("success: magic_protection\n");
        return true;
 }
 
@@ -1136,16 +2011,19 @@ static void test_reset(void)
        talloc_set_log_fn(test_log_stdout);
        test_abort_stop();
        talloc_disable_null_tracking();
-       talloc_enable_null_tracking();
+       talloc_enable_null_tracking_no_autofree();
 }
 
-struct torture_context;
 bool torture_local_talloc(struct torture_context *tctx)
 {
        bool ret = true;
 
        setlinebuf(stdout);
 
+       test_reset();
+       ret &= test_pooled_object();
+       test_reset();
+       ret &= test_pool_nest();
        test_reset();
        ret &= test_ref1();
        test_reset();
@@ -1179,11 +2057,32 @@ bool torture_local_talloc(struct torture_context *tctx)
        test_reset();
        ret &= test_free_parent_deny_child(); 
        test_reset();
+       ret &= test_realloc_on_destructor_parent();
+       test_reset();
+       ret &= test_free_parent_reparent_child();
+       test_reset();
+       ret &= test_free_parent_reparent_child_in_pool();
+       test_reset();
        ret &= test_talloc_ptrtype();
        test_reset();
        ret &= test_talloc_free_in_destructor();
        test_reset();
        ret &= test_pool();
+       test_reset();
+       ret &= test_pool_steal();
+       test_reset();
+       ret &= test_free_ref_null_context();
+       test_reset();
+       ret &= test_rusty();
+       test_reset();
+       ret &= test_free_children();
+       test_reset();
+       ret &= test_memlimit();
+#ifdef HAVE_PTHREAD
+       test_reset();
+       ret &= test_pthread_talloc_passing();
+#endif
+
 
        if (ret) {
                test_reset();
@@ -1191,8 +2090,10 @@ bool torture_local_talloc(struct torture_context *tctx)
        }
        test_reset();
        ret &= test_autofree();
-
        test_reset();
+       ret &= test_magic_protection();
 
+       test_reset();
+       talloc_disable_null_tracking();
        return ret;
 }