summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/includes.h4
-rw-r--r--source4/include/talloc.h39
-rw-r--r--source4/lib/talloc.c178
-rw-r--r--source4/torture/local/talloc.c320
-rw-r--r--talloc_guide.txt4
5 files changed, 465 insertions, 80 deletions
diff --git a/source4/include/includes.h b/source4/include/includes.h
index d29353cafc..06e9b91347 100644
--- a/source4/include/includes.h
+++ b/source4/include/includes.h
@@ -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 */
diff --git a/source4/include/talloc.h b/source4/include/talloc.h
index 4c108d865d..2e0cca7070 100644
--- a/source4/include/talloc.h
+++ b/source4/include/talloc.h
@@ -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
diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c
index b81cf7221b..9d8caeb0e7 100644
--- a/source4/lib/talloc.c
+++ b/source4/lib/talloc.c
@@ -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
@@ -24,14 +26,42 @@
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) {
diff --git a/source4/torture/local/talloc.c b/source4/torture/local/talloc.c
index e046ae8dc5..a3bfb45f54 100644
--- a/source4/torture/local/talloc.c
+++ b/source4/torture/local/talloc.c
@@ -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); \
@@ -33,6 +33,17 @@
} \
} 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,10 +274,206 @@ 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);
@@ -286,6 +481,87 @@ static BOOL test_unref1(void)
}
/*
+ 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
*/
static BOOL test_speed(void)
@@ -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;
diff --git a/talloc_guide.txt b/talloc_guide.txt
index 7d727c5cb2..745426730c 100644
--- a/talloc_guide.txt
+++ b/talloc_guide.txt
@@ -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