r2744: ben elliston taught me about gcov today, which allows you to measure
authorAndrew Tridgell <tridge@samba.org>
Wed, 29 Sep 2004 06:31:14 +0000 (06:31 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:59:29 +0000 (12:59 -0500)
the % coverage in terms of lines of code of a test suite. I thought a
good first place to start with gcov was the talloc test suite. When I
started the test suite covered about 60% of all lines of code in
talloc.c, and now it covers about 99%. The only lines not covered are
talloc corruption errors, as that would cause smb_panic() to fire.

It will be interesting to try gcov on the main Samba test suite for
smbd. We won't achieve 100% coverage, but it would be nice to get to
90% or more.

I also modified the talloc.c sources to be able to be build standalone, using:

  gcc -c -D_STANDALONE_ -Iinlcude lib/talloc.c

that should make it much easier to re-use talloc in other projects
(This used to be commit 8d4dc99b82efdf24b6811851c7bdd4af5a4c52c9)

source4/include/includes.h
source4/include/talloc.h
source4/lib/talloc.c
source4/torture/local/talloc.c
talloc_guide.txt

index d29353cafcba42ac8593a185af938abd60f91e48..06e9b91347df99b2b0628fc7c5e4a04b80926405 100644 (file)
@@ -1068,7 +1068,9 @@ time_t timegm(struct tm *tm);
 #include <sys/xattr.h>
 #endif
 
-#define discard_const_p(type, ptr) (type *)discard_const(ptr)
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+
+#define TALLOC_ABORT(reason) smb_panic(reason)
 
 #endif /* _INCLUDES_H */
 
index 4c108d865d1f38c1ce4b75df58fd85f2b3fb7e5d..2e0cca7070d347a1ffd819a8da27fdadbd15e684 100644 (file)
@@ -49,5 +49,44 @@ typedef void TALLOC_CTX;
 #define data_blob(ptr, size) data_blob_named(ptr, size, __location__)
 #define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, __location__)
 
+#ifndef PRINTF_ATTRIBUTE
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+
+
+/* The following definitions come from lib/talloc.c  */
+void *_talloc(const void *context, size_t size);
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+void talloc_increase_ref_count(const void *ptr);
+void *talloc_reference(const void *context, const void *ptr);
+void *talloc_unreference(const void *context, const void *ptr);
+void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void talloc_set_name_const(const void *ptr, const char *name);
+void *talloc_named(const void *context, size_t size, 
+                  const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+void *talloc_named_const(const void *context, size_t size, const char *name);
+const char *talloc_get_name(const void *ptr);
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+int talloc_free(void *ptr);
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+void *talloc_steal(const void *new_ctx, const void *ptr);
+off_t talloc_total_size(const void *ptr);
+off_t talloc_total_blocks(const void *ptr);
+void talloc_report_full(const void *ptr, FILE *f);
+void talloc_report(const void *ptr, FILE *f);
+void talloc_enable_leak_report(void);
+void talloc_enable_leak_report_full(void);
+void *talloc_zero(const void *ctx, size_t size);
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+char *talloc_strdup(const void *t, const char *p);
+char *talloc_strndup(const void *t, const char *p, size_t n);
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append(char *s,
+                            const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void *talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+void *talloc_ldb_alloc(void *context, void *ptr, size_t size);
+
 #endif
 
index b81cf7221b155ef8ca0e077fad773a5824a383a1..9d8caeb0e700b4afe4beb7f7168ca05beb27df41 100644 (file)
@@ -1,7 +1,9 @@
 /* 
    Samba Unix SMB/CIFS implementation.
 
-   Samba temporary memory allocation functions - new interface
+   Samba trivial allocation library - new interface
+
+   NOTE: Please read talloc_guide.txt for full documentation
 
    Copyright (C) Andrew Tridgell 2004
    
   inspired by http://swapped.cc/halloc/
 */
 
+
+/*
+  if you need to build this outside of the Samba source tree then please define _STANDALONE_
+*/
+#ifdef _STANDALONE_
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "talloc.h"
+#else
 #include "includes.h"
+#endif
 
 #define MAX_TALLOC_SIZE 0x10000000
 #define TALLOC_MAGIC 0xe814ec4f
 #define TALLOC_MAGIC_FREE 0x7faebef3
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
 
+/* by default we abort when given a bad pointer (such as when talloc_free() is called 
+   on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+   talloc_enable_leak_report_full() is called, otherwise it remains
+   NULL
+*/
 static const void *null_context;
 
+
 struct talloc_reference_handle {
        struct talloc_reference_handle *next, *prev;
        void *ptr;
@@ -44,7 +74,7 @@ struct talloc_chunk {
        struct talloc_chunk *parent, *child;
        struct talloc_reference_handle *refs;
        size_t size;
-       uint_t magic;
+       unsigned magic;
        talloc_destructor_t destructor;
        const char *name;
 };
@@ -52,17 +82,45 @@ struct talloc_chunk {
 /* panic if we get a bad magic value */
 static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
 {
-       struct talloc_chunk *tc = ((struct talloc_chunk *)discard_const(ptr))-1;
-       if (tc->magic != TALLOC_MAGIC) {
+       struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1;
+       if (tc->magic != TALLOC_MAGIC) { 
                if (tc->magic == TALLOC_MAGIC_FREE) {
-                       smb_panic("Bad talloc magic value - double free\n");
+                       TALLOC_ABORT("Bad talloc magic value - double free"); 
                } else {
-                       smb_panic("Bad talloc magic value\n");
+                       TALLOC_ABORT("Bad talloc magic value - unknown value"); 
                }
        }
+
        return tc;
 }
 
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+        if (!(list)) { \
+               (list) = (p); \
+               (p)->next = (p)->prev = NULL; \
+       } else { \
+               (list)->prev = (p); \
+               (p)->next = (list); \
+               (p)->prev = NULL; \
+               (list) = (p); \
+       }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+       if ((p) == (list)) { \
+               (list) = (p)->next; \
+               if (list) (list)->prev = NULL; \
+       } else { \
+               if ((p)->prev) (p)->prev->next = (p)->next; \
+               if ((p)->next) (p)->next->prev = (p)->prev; \
+       } \
+       if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
 
 /*
   return the parent chunk of a pointer
@@ -90,9 +148,7 @@ void *_talloc(const void *context, size_t size)
        }
 
        tc = malloc(sizeof(*tc)+size);
-       if (tc == NULL) {
-               return NULL;
-       }
+       if (tc == NULL) return NULL;
 
        tc->size = size;
        tc->magic = TALLOC_MAGIC;
@@ -110,7 +166,7 @@ void *_talloc(const void *context, size_t size)
                        parent->child->parent = NULL;
                }
 
-               DLIST_ADD(parent->child, tc);
+               _TLIST_ADD(parent->child, tc);
        } else {
                tc->next = tc->prev = tc->parent = NULL;
        }
@@ -150,7 +206,7 @@ static int talloc_reference_destructor(void *ptr)
        if (tc1->destructor != (talloc_destructor_t)-1) {
                tc1->destructor = NULL;
        }
-       DLIST_REMOVE(tc2->refs, handle);
+       _TLIST_REMOVE(tc2->refs, handle);
        talloc_free(handle);
        return 0;
 }
@@ -168,16 +224,15 @@ void *talloc_reference(const void *context, const void *ptr)
 {
        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
        struct talloc_reference_handle *handle;
-       handle = talloc_named_const(context, sizeof(*handle), ".reference");
-       if (handle == NULL) {
-               return NULL;
-       }
+       handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE);
+       if (handle == NULL) return NULL;
+
        /* note that we hang the destructor off the handle, not the
           main context as that allows the caller to still setup their
           own destructor on the context if they want to */
        talloc_set_destructor(handle, talloc_reference_destructor);
-       handle->ptr = discard_const(ptr);
-       DLIST_ADD(tc->refs, handle);
+       handle->ptr = discard_const_p(void, ptr);
+       _TLIST_ADD(tc->refs, handle);
        return handle->ptr;
 }
 
@@ -204,9 +259,9 @@ void *talloc_unreference(const void *context, const void *ptr)
        }
 
        talloc_set_destructor(h, NULL);
-       DLIST_REMOVE(tc->refs, h);
+       _TLIST_REMOVE(tc->refs, h);
        talloc_free(h);
-       return discard_const(ptr);
+       return discard_const_p(void, ptr);
 }
 
 /*
@@ -226,7 +281,7 @@ static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
 /*
   add a name to an existing pointer
 */
-void talloc_set_name(const void *ptr, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3)
+void talloc_set_name(const void *ptr, const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
@@ -249,16 +304,13 @@ void talloc_set_name_const(const void *ptr, const char *name)
   talloc_named() operates just like talloc() except that it allows you
   to name the pointer.
 */
-void *talloc_named(const void *context, size_t size, 
-                  const char *fmt, ...) _PRINTF_ATTRIBUTE(3,4)
+void *talloc_named(const void *context, size_t size, const char *fmt, ...)
 {
        va_list ap;
        void *ptr;
 
        ptr = _talloc(context, size);
-       if (ptr == NULL) {
-               return NULL;
-       }
+       if (ptr == NULL) return NULL;
 
        va_start(ap, fmt);
        talloc_set_name_v(ptr, fmt, ap);
@@ -292,6 +344,9 @@ void *talloc_named_const(const void *context, size_t size, const char *name)
 const char *talloc_get_name(const void *ptr)
 {
        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+       if (tc->name == TALLOC_MAGIC_REFERENCE) {
+               return ".reference";
+       }
        if (tc->name) {
                return tc->name;
        }
@@ -301,15 +356,13 @@ const char *talloc_get_name(const void *ptr)
 /*
   this is for compatibility with older versions of talloc
 */
-void *talloc_init(const char *fmt, ...) _PRINTF_ATTRIBUTE(1,2)
+void *talloc_init(const char *fmt, ...)
 {
        va_list ap;
        void *ptr;
 
        ptr = _talloc(NULL, 0);
-       if (ptr == NULL) {
-               return NULL;
-       }
+       if (ptr == NULL) return NULL;
 
        va_start(ap, fmt);
        talloc_set_name_v(ptr, fmt, ap);
@@ -375,7 +428,7 @@ int talloc_free(void *ptr)
        }
 
        if (tc->parent) {
-               DLIST_REMOVE(tc->parent->child, tc);
+               _TLIST_REMOVE(tc->parent->child, tc);
                if (tc->parent->child) {
                        tc->parent->child->parent = tc->parent;
                }
@@ -407,6 +460,10 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
                return NULL;
        }
 
+       if (size >= MAX_TALLOC_SIZE) {
+               return NULL;
+       }
+
        /* realloc(NULL) is equavalent to malloc() */
        if (ptr == NULL) {
                return talloc_named_const(context, size, name);
@@ -423,9 +480,9 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
        tc->magic = TALLOC_MAGIC_FREE;
 
        new_ptr = realloc(tc, size + sizeof(*tc));
-       if (!new_ptr) {
-               tc->magic = TALLOC_MAGIC;
-               return NULL;
+       if (!new_ptr) { 
+               tc->magic = TALLOC_MAGIC; 
+               return NULL; 
        }
 
        tc = new_ptr;
@@ -463,7 +520,7 @@ void *talloc_steal(const void *new_ctx, const void *ptr)
 
        if (new_ctx == NULL) {
                if (tc->parent) {
-                       DLIST_REMOVE(tc->parent->child, tc);
+                       _TLIST_REMOVE(tc->parent->child, tc);
                        if (tc->parent->child) {
                                tc->parent->child->parent = tc->parent;
                        }
@@ -473,17 +530,17 @@ void *talloc_steal(const void *new_ctx, const void *ptr)
                }
                
                tc->parent = tc->next = tc->prev = NULL;
-               return discard_const(ptr);
+               return discard_const_p(void, ptr);
        }
 
        new_tc = talloc_chunk_from_ptr(new_ctx);
 
        if (tc == new_tc) {
-               return discard_const(ptr);
+               return discard_const_p(void, ptr);
        }
 
        if (tc->parent) {
-               DLIST_REMOVE(tc->parent->child, tc);
+               _TLIST_REMOVE(tc->parent->child, tc);
                if (tc->parent->child) {
                        tc->parent->child->parent = tc->parent;
                }
@@ -494,9 +551,9 @@ void *talloc_steal(const void *new_ctx, const void *ptr)
 
        tc->parent = new_tc;
        if (new_tc->child) new_tc->child->parent = NULL;
-       DLIST_ADD(new_tc->child, tc);
+       _TLIST_ADD(new_tc->child, tc);
 
-       return discard_const(ptr);
+       return discard_const_p(void, ptr);
 }
 
 /*
@@ -561,12 +618,12 @@ static void talloc_report_depth(const void *ptr, FILE *f, int depth)
        struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
 
        for (c=tc->child;c;c=c->next) {
-               const char *name = talloc_get_name(c+1);
-               if (strcmp(name, ".reference") == 0) {
+               if (c->name == TALLOC_MAGIC_REFERENCE) {
                        struct talloc_reference_handle *handle = (void *)(c+1);
                        const char *name2 = talloc_get_name(handle->ptr);
                        fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
                } else {
+                       const char *name = talloc_get_name(c+1);
                        fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", 
                                depth*4, "",
                                name,
@@ -630,10 +687,9 @@ void talloc_report(const void *ptr, FILE *f)
 */
 static void talloc_report_null(void)
 {
-       if (talloc_total_size(null_context) == 0) {
-               return;
+       if (talloc_total_size(null_context) != 0) {
+               talloc_report(null_context, stderr);
        }
-       talloc_report(null_context, stderr);
 }
 
 /*
@@ -641,10 +697,9 @@ static void talloc_report_null(void)
 */
 static void talloc_report_null_full(void)
 {
-       if (talloc_total_size(null_context) == 0) {
-               return;
+       if (talloc_total_size(null_context) != 0) {
+               talloc_report_full(null_context, stderr);
        }
-       talloc_report_full(null_context, stderr);
 }
 
 /*
@@ -715,9 +770,11 @@ char *talloc_strdup(const void *t, const char *p)
 */
 char *talloc_strndup(const void *t, const char *p, size_t n)
 {
-       size_t len = strnlen(p, n);
+       size_t len;
        char *ret;
 
+       for (len=0; p[len] && len<n; len++) ;
+
        ret = talloc(t, len + 1);
        if (!ret) { return NULL; }
        memcpy(ret, p, len);
@@ -725,7 +782,15 @@ char *talloc_strndup(const void *t, const char *p, size_t n)
        return ret;
 }
 
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(2,0)
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
 {      
        int len;
        char *ret;
@@ -750,7 +815,7 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) _PRINTF_ATTRI
   Perform string formatting, and return a pointer to newly allocated
   memory holding the result, inside a memory pool.
  */
-char *talloc_asprintf(const void *t, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3)
+char *talloc_asprintf(const void *t, const char *fmt, ...)
 {
        va_list ap;
        char *ret;
@@ -768,11 +833,9 @@ char *talloc_asprintf(const void *t, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3
  * accumulating output into a string buffer.
  **/
 
-static char *talloc_vasprintf_append(char *s,
-                                    const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
 
-static char *talloc_vasprintf_append(char *s,
-                                    const char *fmt, va_list ap)
+static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
 {      
        int len, s_len;
        va_list ap2;
@@ -802,8 +865,7 @@ static char *talloc_vasprintf_append(char *s,
   s, which may have moved.  Good for gradually accumulating output
   into a string buffer.
  */
-char *talloc_asprintf_append(char *s,
-                            const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3)
+char *talloc_asprintf_append(char *s, const char *fmt, ...)
 {
        va_list ap;
 
@@ -816,7 +878,7 @@ char *talloc_asprintf_append(char *s,
 /*
   alloc an array, checking for integer overflow in the array size
 */
-void *talloc_array(const void *ctx, size_t el_size, uint_t count, const char *name)
+void *talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
 {
        if (count == 0 ||
            count >= MAX_TALLOC_SIZE/el_size) {
@@ -829,7 +891,7 @@ void *talloc_array(const void *ctx, size_t el_size, uint_t count, const char *na
 /*
   realloc an array, checking for integer overflow in the array size
 */
-void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, uint_t count, const char *name)
+void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
 {
        if (count == 0 ||
            count >= MAX_TALLOC_SIZE/el_size) {
index e046ae8dc52b6b29c9bc1ada2f1c089f5e041f69..a3bfb45f54cd97fc8fcb4d3e954c066e77947eca 100644 (file)
@@ -24,8 +24,8 @@
 
 #define CHECK_BLOCKS(ptr, tblocks) do { \
        if (talloc_total_blocks(ptr) != (tblocks)) { \
-               printf("(%d) failed: wrong '%s' tree size: got %u  expected %u\n", \
-                      __LINE__, #ptr, \
+               printf(__location__ " failed: wrong '%s' tree blocks: got %u  expected %u\n", \
+                      #ptr, \
                       (unsigned)talloc_total_blocks(ptr), \
                       (unsigned)tblocks); \
                talloc_report_full(ptr, stdout); \
        } \
 } while (0)
 
+#define CHECK_SIZE(ptr, tsize) do { \
+       if (talloc_total_size(ptr) != (tsize)) { \
+               printf(__location__ " failed: wrong '%s' tree size: got %u  expected %u\n", \
+                      #ptr, \
+                      (unsigned)talloc_total_size(ptr), \
+                      (unsigned)tsize); \
+               talloc_report_full(ptr, stdout); \
+               return False; \
+       } \
+} while (0)
+
 /*
   test references 
 */
@@ -77,10 +88,7 @@ static BOOL test_ref1(void)
 
        CHECK_BLOCKS(root, 1);
 
-       if (talloc_total_size(root) != 0) {
-               printf("failed: non-zero total size\n");
-               return False;
-       }
+       CHECK_SIZE(root, 0);
 
        talloc_free(root);
 
@@ -136,10 +144,7 @@ static BOOL test_ref2(void)
        talloc_free(r1);
        talloc_report_full(root, stdout);
 
-       if (talloc_total_size(root) != 0) {
-               printf("failed: non-zero total size\n");
-               return False;
-       }
+       CHECK_SIZE(root, 0);
 
        talloc_free(root);
 
@@ -177,10 +182,7 @@ static BOOL test_ref3(void)
        talloc_free(p2);
        talloc_report_full(root, stdout);
 
-       if (talloc_total_size(root) != 0) {
-               printf("failed: non-zero total size\n");
-               return False;
-       }
+       CHECK_SIZE(root, 0);
 
        talloc_free(root);
 
@@ -228,10 +230,7 @@ static BOOL test_ref4(void)
        talloc_free(p1);
        talloc_report_full(root, stdout);
 
-       if (talloc_total_size(root) != 0) {
-               printf("failed: non-zero total size\n");
-               return False;
-       }
+       CHECK_SIZE(root, 0);
 
        talloc_free(root);
 
@@ -275,16 +274,293 @@ static BOOL test_unref1(void)
        talloc_free(p1);
        talloc_report_full(root, stdout);
 
-       if (talloc_total_size(root) != 0) {
-               printf("failed: non-zero total size\n");
+       CHECK_SIZE(root, 0);
+
+       talloc_free(root);
+
+       return True;
+}
+
+static int fail_destructor(void *ptr)
+{
+       return -1;
+}
+
+/*
+  miscellaneous tests to try to get a higher test coverage percentage
+*/
+static BOOL test_misc(void)
+{
+       void *root, *p1;
+       char *p2;
+       double *d;
+
+       printf("TESTING MISCELLANEOUS\n");
+
+       root = talloc(NULL, 0);
+
+       p1 = talloc(root, 0x7fffffff);
+       if (p1) {
+               printf("failed: large talloc allowed\n");
+               return False;
+       }
+
+       p1 = talloc_strdup(root, "foo");
+       talloc_increase_ref_count(p1);
+       talloc_increase_ref_count(p1);
+       talloc_increase_ref_count(p1);
+       CHECK_BLOCKS(p1, 1);
+       CHECK_BLOCKS(root, 2);
+       talloc_free(p1);
+       CHECK_BLOCKS(p1, 1);
+       CHECK_BLOCKS(root, 2);
+       talloc_unreference(NULL, p1);
+       CHECK_BLOCKS(p1, 1);
+       CHECK_BLOCKS(root, 2);
+       if (talloc_unreference(root, p1) != NULL) {
+               printf("failed: talloc_unreference() of non-reference context should return NULL\n");
+               return False;
+       }
+       talloc_free(p1);
+       CHECK_BLOCKS(p1, 1);
+       CHECK_BLOCKS(root, 2);
+
+       talloc_set_name(p1, "my name is %s", "foo");
+       if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
+               printf("failed: wrong name after talloc_set_name\n");
+               return False;
+       }
+       CHECK_BLOCKS(p1, 2);
+       CHECK_BLOCKS(root, 3);
+
+       talloc_set_name_const(p1, NULL);
+       if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
+               printf("failed: wrong name after talloc_set_name(NULL)\n");
+               return False;
+       }
+       CHECK_BLOCKS(p1, 2);
+       CHECK_BLOCKS(root, 3);
+       
+
+       if (talloc_free(NULL) != -1) {
+               printf("talloc_free(NULL) should give -1\n");
+               return False;
+       }
+
+       talloc_set_destructor(p1, fail_destructor);
+       if (talloc_free(p1) != -1) {
+               printf("Failed destructor should cause talloc_free to fail\n");
+               return False;
+       }
+       talloc_set_destructor(p1, NULL);
+
+       talloc_report(root, stdout);
+
+
+       p2 = talloc_zero(p1, 20);
+       if (p2[19] != 0) {
+               printf("Failed to give zero memory\n");
+               return False;
+       }
+       talloc_free(p2);
+
+       if (talloc_strdup(root, NULL) != NULL) {
+               printf("failed: strdup on NULL should give NULL\n");
+               return False;
+       }
+
+       p2 = talloc_strndup(p1, "foo", 2);
+       if (strcmp("fo", p2) != 0) {
+               printf("failed: strndup doesn't work\n");
+               return False;
+       }
+       p2 = talloc_asprintf_append(p2, "o%c", 'd');
+       if (strcmp("food", p2) != 0) {
+               printf("failed: talloc_asprintf_append doesn't work\n");
+               return False;
+       }
+       CHECK_BLOCKS(p2, 1);
+       CHECK_BLOCKS(p1, 3);
+
+       p2 = talloc_asprintf_append(NULL, "hello %s", "world");
+       if (strcmp("hello world", p2) != 0) {
+               printf("failed: talloc_asprintf_append doesn't work\n");
+               return False;
+       }
+       CHECK_BLOCKS(p2, 1);
+       CHECK_BLOCKS(p1, 3);
+       talloc_free(p2);
+
+       d = talloc_array_p(p1, double, 0x20000000);
+       if (d) {
+               printf("failed: integer overflow not detected\n");
+               return False;
+       }
+
+       d = talloc_realloc_p(p1, d, double, 0x20000000);
+       if (d) {
+               printf("failed: integer overflow not detected\n");
+               return False;
+       }
+
+       talloc_free(p1);
+       CHECK_BLOCKS(root, 1);
+
+       talloc_report(root, stdout);
+       talloc_report(NULL, stdout);
+
+       CHECK_SIZE(root, 0);
+
+       talloc_free(root);
+
+       CHECK_SIZE(NULL, 0);
+
+       talloc_enable_leak_report();
+       talloc_enable_leak_report_full();
+
+       return True;
+}
+
+
+/*
+  test realloc
+*/
+static BOOL test_realloc(void)
+{
+       void *root, *p1, *p2;
+
+       printf("TESTING REALLOC\n");
+
+       root = talloc(NULL, 0);
+
+       p1 = talloc(root, 10);
+       CHECK_SIZE(p1, 10);
+
+       p1 = talloc_realloc(NULL, p1, 20);
+       CHECK_SIZE(p1, 20);
+
+       talloc(p1, 0);
+
+       p2 = talloc_realloc(p1, NULL, 30);
+
+       talloc(p1, 0);
+
+       p2 = talloc_realloc(p1, p2, 40);
+
+       CHECK_SIZE(p2, 40);
+       CHECK_SIZE(root, 60);
+       CHECK_BLOCKS(p1, 4);
+
+       p1 = talloc_realloc(NULL, p1, 20);
+       CHECK_SIZE(p1, 60);
+
+       talloc_increase_ref_count(p2);
+       if (talloc_realloc(NULL, p2, 5) != NULL) {
+               printf("failed: talloc_realloc() on a referenced pointer should fail\n");
                return False;
        }
+       CHECK_BLOCKS(p1, 4);
+
+       talloc_realloc(NULL, p2, 0);
+       talloc_realloc(NULL, p2, 0);
+       CHECK_BLOCKS(p1, 3);
+
+       if (talloc_realloc(NULL, p1, 0x7fffffff) != NULL) {
+               printf("failed: oversize talloc should fail\n");
+               return False;
+       }
+
+       talloc_realloc(NULL, p1, 0);
+
+       CHECK_BLOCKS(root, 1);
+       CHECK_SIZE(root, 0);
 
        talloc_free(root);
 
        return True;
 }
 
+/*
+  test steal
+*/
+static BOOL test_steal(void)
+{
+       void *root, *p1, *p2;
+
+       printf("TESTING STEAL\n");
+
+       root = talloc(NULL, 0);
+
+       p1 = talloc_array_p(root, char, 10);
+       CHECK_SIZE(p1, 10);
+
+       p2 = talloc_realloc_p(root, NULL, char, 20);
+       CHECK_SIZE(p1, 10);
+       CHECK_SIZE(root, 30);
+
+       if (talloc_steal(p1, NULL) != NULL) {
+               printf("failed: stealing NULL should give NULL\n");
+               return False;
+       }
+
+       if (talloc_steal(p1, p1) != p1) {
+               printf("failed: stealing to ourselves is a nop\n");
+               return False;
+       }
+       CHECK_BLOCKS(root, 3);
+       CHECK_SIZE(root, 30);
+
+       talloc_steal(NULL, p1);
+       talloc_steal(NULL, p2);
+       CHECK_BLOCKS(root, 1);
+       CHECK_SIZE(root, 0);
+
+       talloc_free(p1);
+       talloc_steal(root, p2);
+       CHECK_BLOCKS(root, 2);
+       CHECK_SIZE(root, 20);
+       
+       talloc_free(p2);
+
+       CHECK_BLOCKS(root, 1);
+       CHECK_SIZE(root, 0);
+
+       talloc_free(root);
+
+       p1 = talloc(NULL, 3);
+       CHECK_SIZE(NULL, 3);
+       talloc_free(p1);
+
+       return True;
+}
+
+/*
+  test ldb alloc fn
+*/
+static BOOL test_ldb(void)
+{
+       void *root, *p1;
+
+       printf("TESTING LDB\n");
+
+       root = talloc(NULL, 0);
+
+       p1 = talloc_ldb_alloc(root, NULL, 10);
+       CHECK_BLOCKS(root, 2);
+       CHECK_SIZE(root, 10);
+       p1 = talloc_ldb_alloc(root, p1, 20);
+       CHECK_BLOCKS(root, 2);
+       CHECK_SIZE(root, 20);
+       p1 = talloc_ldb_alloc(root, p1, 0);
+       CHECK_BLOCKS(root, 1);
+       CHECK_SIZE(root, 0);
+
+       talloc_free(root);
+
+
+       return True;
+}
+
 /*
   measure the speed of talloc versus malloc
 */
@@ -340,6 +616,10 @@ BOOL torture_local_talloc(int dummy)
        ret &= test_ref3();
        ret &= test_ref4();
        ret &= test_unref1();
+       ret &= test_misc();
+       ret &= test_realloc();
+       ret &= test_steal();
+       ret &= test_ldb();
        ret &= test_speed();
 
        return ret;
index 7d727c5cb2d1925b4022ec305827a3eeae5e4d32..745426730c629c133b0926b422411fc1d8f6eb5a 100644 (file)
@@ -125,7 +125,9 @@ After creating a reference you can free it in one of the following
 ways:
 
   - you can talloc_free() a parent of the original pointer. That will
-    destroy the reference and make the pointer a child of "context".
+    destroy the reference and make the pointer a child of the
+    "context" argument from the most recently called
+    talloc_reference() on the pointer.
 
   - you can talloc_free() the pointer itself. That will destroy the
     most recently established reference to the pointer and leave the