From 21931b1ca834f41c5ca931cdfb6f0347b5cb3c96 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Sep 2006 04:16:58 +0000 Subject: r18810: use a copy of samba4's talloc under lib/talloc/ to make mergeing easier. metze (This used to be commit d49ffbc19b29f7620e427de133ffab74721f37e8) --- source3/lib/talloc/talloc.c | 1309 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1309 insertions(+) create mode 100644 source3/lib/talloc/talloc.c (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c new file mode 100644 index 0000000000..d790c6c26b --- /dev/null +++ b/source3/lib/talloc/talloc.c @@ -0,0 +1,1309 @@ +/* + Samba Unix SMB/CIFS implementation. + + Samba trivial allocation library - new interface + + NOTE: Please read talloc_guide.txt for full documentation + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + inspired by http://swapped.cc/halloc/ +*/ + +#ifdef _SAMBA_BUILD_ +#include "version.h" +#if (SAMBA_VERSION_MAJOR<4) +#include "includes.h" +/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file + * we trust ourselves... */ +#ifdef malloc +#undef malloc +#endif +#ifdef realloc +#undef realloc +#endif +#define _TALLOC_SAMBA3 +#endif /* (SAMBA_VERSION_MAJOR<4) */ +#endif /* _SAMBA_BUILD_ */ + +#ifndef _TALLOC_SAMBA3 +#include "replace.h" +#include "talloc.h" +#endif /* not _TALLOC_SAMBA3 */ + +/* use this to force every realloc to change the pointer, to stress test + code that might not cope */ +#define ALWAYS_REALLOC 0 + + +#define MAX_TALLOC_SIZE 0x10000000 +#define TALLOC_MAGIC 0xe814ec70 +#define TALLOC_FLAG_FREE 0x01 +#define TALLOC_FLAG_LOOP 0x02 +#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 +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) +# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) +#else +# define discard_const_p(type, ptr) ((type *)(ptr)) +#endif +#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 void *null_context; +static void *cleanup_context; + +struct talloc_reference_handle { + struct talloc_reference_handle *next, *prev; + void *ptr; +}; + +typedef int (*talloc_destructor_t)(void *); + +struct talloc_chunk { + struct talloc_chunk *next, *prev; + struct talloc_chunk *parent, *child; + struct talloc_reference_handle *refs; + talloc_destructor_t destructor; + const char *name; + size_t size; + unsigned flags; +}; + +/* 16 byte alignment seems to keep everyone happy */ +#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15) +#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) + +/* panic if we get a bad magic value */ +static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) +{ + const char *pp = (const char *)ptr; + struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); + if ((tc->flags & ~0xF) != TALLOC_MAGIC) { + TALLOC_ABORT("Bad talloc magic value - unknown value"); + } + if (tc->flags & TALLOC_FLAG_FREE) { + TALLOC_ABORT("Bad talloc magic value - double free"); + } + 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 +*/ +static struct talloc_chunk *talloc_parent_chunk(const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + while (tc->prev) tc=tc->prev; + return tc->parent; +} + +void *talloc_parent(const void *ptr) +{ + struct talloc_chunk *tc = talloc_parent_chunk(ptr); + return tc? TC_PTR_FROM_CHUNK(tc) : NULL; +} + +/* + Allocate a bit of memory as a child of an existing pointer +*/ +void *_talloc(const void *context, size_t size) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + context = null_context; + } + + if (size >= MAX_TALLOC_SIZE) { + return NULL; + } + + tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); + if (tc == NULL) return NULL; + + tc->size = size; + tc->flags = TALLOC_MAGIC; + tc->destructor = NULL; + tc->child = NULL; + tc->name = NULL; + tc->refs = NULL; + + if (context) { + struct talloc_chunk *parent = talloc_chunk_from_ptr(context); + + tc->parent = parent; + + if (parent->child) { + parent->child->parent = NULL; + } + + _TLIST_ADD(parent->child, tc); + } else { + tc->next = tc->prev = tc->parent = NULL; + } + + return TC_PTR_FROM_CHUNK(tc); +} + + +/* + setup a destructor to be called on free of a pointer + the destructor should return 0 on success, or -1 on failure. + if the destructor fails then the free is failed, and the memory can + be continued to be used +*/ +void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->destructor = destructor; +} + +/* + increase the reference count on a piece of memory. +*/ +int talloc_increase_ref_count(const void *ptr) +{ + if (!talloc_reference(null_context, ptr)) { + return -1; + } + return 0; +} + +/* + helper for talloc_reference() +*/ +static int talloc_reference_destructor(struct talloc_reference_handle *handle) +{ + struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr); + _TLIST_REMOVE(ptr_tc->refs, handle); + return 0; +} + +/* + make a secondary reference to a pointer, hanging off the given context. + the pointer remains valid until both the original caller and this given + context are freed. + + the major use for this is when two different structures need to reference the + same underlying data, and you want to be able to free the two instances separately, + and in either order +*/ +void *_talloc_reference(const void *context, const void *ptr) +{ + struct talloc_chunk *tc; + struct talloc_reference_handle *handle; + if (ptr == NULL) return NULL; + + tc = talloc_chunk_from_ptr(ptr); + handle = (struct talloc_reference_handle *)talloc_named_const(context, + sizeof(struct talloc_reference_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_p(void, ptr); + _TLIST_ADD(tc->refs, handle); + return handle->ptr; +} + +/* + remove a secondary reference to a pointer. This undo's what + talloc_reference() has done. The context and pointer arguments + must match those given to a talloc_reference() +*/ +static int talloc_unreference(const void *context, const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + + if (context == NULL) { + context = null_context; + } + + for (h=tc->refs;h;h=h->next) { + struct talloc_chunk *p = talloc_parent_chunk(h); + if (p == NULL) { + if (context == NULL) break; + } else if (TC_PTR_FROM_CHUNK(p) == context) { + break; + } + } + if (h == NULL) { + return -1; + } + + return talloc_free(h); +} + +/* + remove a specific parent context from a pointer. This is a more + controlled varient of talloc_free() +*/ +int talloc_unlink(const void *context, void *ptr) +{ + struct talloc_chunk *tc_p, *new_p; + void *new_parent; + + if (ptr == NULL) { + return -1; + } + + if (context == NULL) { + context = null_context; + } + + if (talloc_unreference(context, ptr) == 0) { + return 0; + } + + if (context == NULL) { + if (talloc_parent_chunk(ptr) != NULL) { + return -1; + } + } else { + if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { + return -1; + } + } + + tc_p = talloc_chunk_from_ptr(ptr); + + if (tc_p->refs == NULL) { + return talloc_free(ptr); + } + + new_p = talloc_parent_chunk(tc_p->refs); + if (new_p) { + new_parent = TC_PTR_FROM_CHUNK(new_p); + } else { + new_parent = NULL; + } + + if (talloc_unreference(new_parent, ptr) != 0) { + return -1; + } + + talloc_steal(new_parent, ptr); + + return 0; +} + +/* + add a name to an existing pointer - va_list version +*/ +static const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +static const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->name = talloc_vasprintf(ptr, fmt, ap); + if (tc->name) { + talloc_set_name_const(tc->name, ".name"); + } + return tc->name; +} + +/* + add a name to an existing pointer +*/ +const char *talloc_set_name(const void *ptr, const char *fmt, ...) +{ + const char *name; + va_list ap; + va_start(ap, fmt); + name = talloc_set_name_v(ptr, fmt, ap); + va_end(ap); + return name; +} + +/* + more efficient way to add a name to a pointer - the name must point to a + true string constant +*/ +void talloc_set_name_const(const void *ptr, const char *name) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->name = name; +} + +/* + create a named talloc pointer. Any talloc pointer can be named, and + 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, ...) +{ + va_list ap; + void *ptr; + const char *name; + + ptr = _talloc(context, size); + if (ptr == NULL) return NULL; + + va_start(ap, fmt); + name = talloc_set_name_v(ptr, fmt, ap); + va_end(ap); + + if (name == NULL) { + talloc_free(ptr); + return NULL; + } + + return ptr; +} + +/* + create a named talloc pointer. Any talloc pointer can be named, and + talloc_named() operates just like talloc() except that it allows you + to name the pointer. +*/ +void *talloc_named_const(const void *context, size_t size, const char *name) +{ + void *ptr; + + ptr = _talloc(context, size); + if (ptr == NULL) { + return NULL; + } + + talloc_set_name_const(ptr, name); + + return ptr; +} + +/* + return the name of a talloc ptr, or "UNNAMED" +*/ +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; + } + return "UNNAMED"; +} + + +/* + check if a pointer has the given name. If it does, return the pointer, + otherwise return NULL +*/ +void *talloc_check_name(const void *ptr, const char *name) +{ + const char *pname; + if (ptr == NULL) return NULL; + pname = talloc_get_name(ptr); + if (pname == name || strcmp(pname, name) == 0) { + return discard_const_p(void, ptr); + } + return NULL; +} + + +/* + this is for compatibility with older versions of talloc +*/ +void *talloc_init(const char *fmt, ...) +{ + va_list ap; + void *ptr; + const char *name; + + /* + * samba3 expects talloc_report_depth_cb(NULL, ...) + * reports all talloc'ed memory, so we need to enable + * null_tracking + */ + talloc_enable_null_tracking(); + + ptr = _talloc(NULL, 0); + if (ptr == NULL) return NULL; + + va_start(ap, fmt); + name = talloc_set_name_v(ptr, fmt, ap); + va_end(ap); + + if (name == NULL) { + talloc_free(ptr); + return NULL; + } + + return ptr; +} + +/* + this is a replacement for the Samba3 talloc_destroy_pool functionality. It + should probably not be used in new code. It's in here to keep the talloc + code consistent across Samba 3 and 4. +*/ +void talloc_free_children(void *ptr) +{ + struct talloc_chunk *tc; + + if (ptr == NULL) { + return; + } + + tc = talloc_chunk_from_ptr(ptr); + + while (tc->child) { + /* we need to work out who will own an abandoned child + if it cannot be freed. In priority order, the first + choice is owner of any remaining reference to this + pointer, the second choice is our parent, and the + final choice is the null context. */ + void *child = TC_PTR_FROM_CHUNK(tc->child); + const void *new_parent = null_context; + if (tc->child->refs) { + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + if (talloc_free(child) == -1) { + if (new_parent == null_context) { + struct talloc_chunk *p = talloc_parent_chunk(ptr); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + talloc_steal(new_parent, child); + } + } +} + +/* + free a talloc pointer. This also frees all child pointers of this + pointer recursively + + return 0 if the memory is actually freed, otherwise -1. The memory + will not be freed if the ref_count is > 1 or the destructor (if + any) returns non-zero +*/ +int talloc_free(void *ptr) +{ + struct talloc_chunk *tc; + int old_errno; + + if (ptr == NULL) { + return -1; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->refs) { + int is_child; + /* check this is a reference from a child or grantchild + * back to it's parent or grantparent + * + * in that case we need to remove the reference and + * call another instance of talloc_free() on the current + * pointer. + */ + is_child = talloc_is_parent(tc->refs, ptr); + talloc_free(tc->refs); + if (is_child) { + return talloc_free(ptr); + } + return -1; + } + + if (tc->flags & TALLOC_FLAG_LOOP) { + /* we have a free loop - stop looping */ + return 0; + } + + if (tc->destructor) { + talloc_destructor_t d = tc->destructor; + if (d == (talloc_destructor_t)-1) { + return -1; + } + tc->destructor = (talloc_destructor_t)-1; + if (d(ptr) == -1) { + tc->destructor = d; + return -1; + } + tc->destructor = NULL; + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->flags |= TALLOC_FLAG_LOOP; + talloc_free_children(ptr); + + tc->flags |= TALLOC_FLAG_FREE; + old_errno = errno; + free(tc); + errno = old_errno; + return 0; +} + + + +/* + A talloc version of realloc. The context argument is only used if + ptr is NULL +*/ +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) +{ + struct talloc_chunk *tc; + void *new_ptr; + + /* size zero is equivalent to free() */ + if (size == 0) { + talloc_free(ptr); + 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); + } + + tc = talloc_chunk_from_ptr(ptr); + + /* don't allow realloc on referenced pointers */ + if (tc->refs) { + return NULL; + } + + /* by resetting magic we catch users of the old memory */ + tc->flags |= TALLOC_FLAG_FREE; + +#if ALWAYS_REALLOC + new_ptr = malloc(size + TC_HDR_SIZE); + if (new_ptr) { + memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); + free(tc); + } +#else + new_ptr = realloc(tc, size + TC_HDR_SIZE); +#endif + if (!new_ptr) { + tc->flags &= ~TALLOC_FLAG_FREE; + return NULL; + } + + tc = (struct talloc_chunk *)new_ptr; + tc->flags &= ~TALLOC_FLAG_FREE; + if (tc->parent) { + tc->parent->child = tc; + } + if (tc->child) { + tc->child->parent = tc; + } + + if (tc->prev) { + tc->prev->next = tc; + } + if (tc->next) { + tc->next->prev = tc; + } + + tc->size = size; + talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); + + return TC_PTR_FROM_CHUNK(tc); +} + +/* + move a lump of memory from one talloc context to another return the + ptr on success, or NULL if it could not be transferred. + passing NULL as ptr will always return NULL with no side effects. +*/ +void *_talloc_steal(const void *new_ctx, const void *ptr) +{ + struct talloc_chunk *tc, *new_tc; + + if (!ptr) { + return NULL; + } + + if (new_ctx == NULL) { + new_ctx = null_context; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (new_ctx == NULL) { + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = tc->next = tc->prev = NULL; + return discard_const_p(void, ptr); + } + + new_tc = talloc_chunk_from_ptr(new_ctx); + + if (tc == new_tc || tc->parent == new_tc) { + return discard_const_p(void, ptr); + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = new_tc; + if (new_tc->child) new_tc->child->parent = NULL; + _TLIST_ADD(new_tc->child, tc); + + return discard_const_p(void, ptr); +} + +/* + a wrapper around talloc_steal() for situations where you are moving a pointer + between two structures, and want the old pointer to be set to NULL +*/ +void *_talloc_move(const void *new_ctx, const void *_pptr) +{ + const void **pptr = (const void **)_pptr; + void *ret = _talloc_steal(new_ctx, *pptr); + (*pptr) = NULL; + return ret; +} + +/* + return the total size of a talloc pool (subtree) +*/ +size_t talloc_total_size(const void *ptr) +{ + size_t total = 0; + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return 0; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + total = tc->size; + for (c=tc->child;c;c=c->next) { + total += talloc_total_size(TC_PTR_FROM_CHUNK(c)); + } + + tc->flags &= ~TALLOC_FLAG_LOOP; + + return total; +} + +/* + return the total number of blocks in a talloc pool (subtree) +*/ +size_t talloc_total_blocks(const void *ptr) +{ + size_t total = 0; + struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return 0; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + total++; + for (c=tc->child;c;c=c->next) { + total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c)); + } + + tc->flags &= ~TALLOC_FLAG_LOOP; + + return total; +} + +/* + return the number of external references to a pointer +*/ +size_t talloc_reference_count(const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + size_t ret = 0; + + for (h=tc->refs;h;h=h->next) { + ret++; + } + return ret; +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *private_data), + void *private_data) +{ + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) return; + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return; + } + + callback(ptr, depth, max_depth, 0, private_data); + + if (max_depth >= 0 && depth >= max_depth) { + return; + } + + tc->flags |= TALLOC_FLAG_LOOP; + for (c=tc->child;c;c=c->next) { + if (c->name == TALLOC_MAGIC_REFERENCE) { + struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c); + callback(h->ptr, depth + 1, max_depth, 1, private_data); + } else { + talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data); + } + } + tc->flags &= ~TALLOC_FLAG_LOOP; +} + +static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f) +{ + const char *name = talloc_get_name(ptr); + FILE *f = (FILE *)_f; + + if (is_ref) { + fprintf(f, "%*sreference to: %s\n", depth*4, "", name); + return; + } + + if (depth == 0) { + fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", + (max_depth < 0 ? "full " :""), name, + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr)); + return; + } + + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", + depth*4, "", + name, + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr), + (int)talloc_reference_count(ptr)); +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f) +{ + talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f); + fflush(f); +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_full(const void *ptr, FILE *f) +{ + talloc_report_depth_file(ptr, 0, -1, f); +} + +/* + report on memory usage by all children of a pointer +*/ +void talloc_report(const void *ptr, FILE *f) +{ + talloc_report_depth_file(ptr, 0, 1, f); +} + +/* + report on any memory hanging off the null context +*/ +static void talloc_report_null(void) +{ + if (talloc_total_size(null_context) != 0) { + talloc_report(null_context, stderr); + } +} + +/* + report on any memory hanging off the null context +*/ +static void talloc_report_null_full(void) +{ + if (talloc_total_size(null_context) != 0) { + talloc_report_full(null_context, stderr); + } +} + +/* + enable tracking of the NULL context +*/ +void talloc_enable_null_tracking(void) +{ + if (null_context == NULL) { + null_context = talloc_named_const(NULL, 0, "null_context"); + } +} + +/* + disable tracking of the NULL context +*/ +void talloc_disable_null_tracking(void) +{ + talloc_free(null_context); + null_context = NULL; +} + +/* + enable leak reporting on exit +*/ +void talloc_enable_leak_report(void) +{ + talloc_enable_null_tracking(); + atexit(talloc_report_null); +} + +/* + enable full leak reporting on exit +*/ +void talloc_enable_leak_report_full(void) +{ + talloc_enable_null_tracking(); + atexit(talloc_report_null_full); +} + +/* + talloc and zero memory. +*/ +void *_talloc_zero(const void *ctx, size_t size, const char *name) +{ + void *p = talloc_named_const(ctx, size, name); + + if (p) { + memset(p, '\0', size); + } + + return p; +} + + +/* + memdup with a talloc. +*/ +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) +{ + void *newp = talloc_named_const(t, size, name); + + if (newp) { + memcpy(newp, p, size); + } + + return newp; +} + +/* + strdup with a talloc +*/ +char *talloc_strdup(const void *t, const char *p) +{ + char *ret; + if (!p) { + return NULL; + } + ret = (char *)talloc_memdup(t, p, strlen(p) + 1); + if (ret) { + talloc_set_name_const(ret, ret); + } + return ret; +} + +/* + append to a talloced string +*/ +char *talloc_append_string(const void *t, char *orig, const char *append) +{ + char *ret; + size_t olen = strlen(orig); + size_t alenz; + + if (!append) + return orig; + + alenz = strlen(append) + 1; + + ret = talloc_realloc(t, orig, char, olen + alenz); + if (!ret) + return NULL; + + /* append the string with the trailing \0 */ + memcpy(&ret[olen], append, alenz); + + return ret; +} + +/* + strndup with a talloc +*/ +char *talloc_strndup(const void *t, const char *p, size_t n) +{ + size_t len; + char *ret; + + for (len=0; lensize - 1; + if ((len = vsnprintf(&c, 1, fmt, ap2)) <= 0) { + /* Either the vsnprintf failed or the format resulted in + * no characters being formatted. In the former case, we + * ought to return NULL, in the latter we ought to return + * the original string. Most current callers of this + * function expect it to never return NULL. + */ + return s; + } + + s = talloc_realloc(NULL, s, char, s_len + len+1); + if (!s) return NULL; + + va_copy(ap2, ap); + + vsnprintf(s+s_len, len+1, fmt, ap2); + talloc_set_name_const(s, s); + + return s; +} + +/* + Realloc @p s to append the formatted result of @p fmt and return @p + s, which may have moved. Good for gradually accumulating output + into a string buffer. + */ +char *talloc_asprintf_append(char *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + s = talloc_vasprintf_append(s, fmt, ap); + va_end(ap); + return s; +} + +/* + alloc an array, checking for integer overflow in the array size +*/ +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return talloc_named_const(ctx, el_size * count, name); +} + +/* + alloc an zero array, checking for integer overflow in the array size +*/ +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_zero(ctx, el_size * count, name); +} + + +/* + realloc an array, checking for integer overflow in the array size +*/ +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_realloc(ctx, ptr, el_size * count, name); +} + +/* + a function version of talloc_realloc(), so it can be passed as a function pointer + to libraries that want a realloc function (a realloc function encapsulates + all the basic capabilities of an allocation library, which is why this is useful) +*/ +void *talloc_realloc_fn(const void *context, void *ptr, size_t size) +{ + return _talloc_realloc(context, ptr, size, NULL); +} + + +static void talloc_autofree(void) +{ + talloc_free(cleanup_context); + cleanup_context = NULL; +} + +/* + return a context which will be auto-freed on exit + this is useful for reducing the noise in leak reports +*/ +void *talloc_autofree_context(void) +{ + if (cleanup_context == NULL) { + cleanup_context = talloc_named_const(NULL, 0, "autofree_context"); + atexit(talloc_autofree); + } + return cleanup_context; +} + +size_t talloc_get_size(const void *context) +{ + struct talloc_chunk *tc; + + if (context == NULL) + return 0; + + tc = talloc_chunk_from_ptr(context); + + return tc->size; +} + +/* + find a parent of this context that has the given name, if any +*/ +void *talloc_find_parent_byname(const void *context, const char *name) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return NULL; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (tc->name && strcmp(tc->name, name) == 0) { + return TC_PTR_FROM_CHUNK(tc); + } + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + return NULL; +} + +/* + show the parentage of a context +*/ +void talloc_show_parents(const void *context, FILE *file) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + fprintf(file, "talloc no parents for NULL\n"); + return; + } + + tc = talloc_chunk_from_ptr(context); + fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); + while (tc) { + fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc))); + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } +} + +/* + return 1 if ptr is a parent of context +*/ +int talloc_is_parent(const void *context, const void *ptr) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + return 0; +} -- cgit From cf5ab86a65bf447174d17198286d8f4ae999e967 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 27 Sep 2006 12:43:08 +0000 Subject: r18952: fix compiler warning (merge from samba4) metze (This used to be commit 4cd59d47c8d21685cfab45f4bcfc005c5d7cf79e) --- source3/lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index d790c6c26b..58028a85b8 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -743,7 +743,7 @@ void *_talloc_steal(const void *new_ctx, const void *ptr) */ void *_talloc_move(const void *new_ctx, const void *_pptr) { - const void **pptr = (const void **)_pptr; + const void **pptr = discard_const_p(const void *,_pptr); void *ret = _talloc_steal(new_ctx, *pptr); (*pptr) = NULL; return ret; -- cgit From 43be47f56bcaa2fd93ede867663cddec04fd8fed Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 29 Sep 2006 10:53:27 +0000 Subject: r18996: merge from samba4: - fix bug 4078 - talloc_free(talloc_autofree_context()); should not result in a SIGABORT on exit - add a test for this, but this test can also pass in the standalone build and samba3, as samba4 uses talloc_autofree_context() metze (This used to be commit f5b0924f975f58bba3c13a53388ea25af51d3bc8) --- source3/lib/talloc/talloc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 58028a85b8..15b27c61ee 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -82,7 +82,7 @@ NULL */ static void *null_context; -static void *cleanup_context; +static void *autofree_context; struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; @@ -1208,10 +1208,15 @@ void *talloc_realloc_fn(const void *context, void *ptr, size_t size) } +static int talloc_autofree_destructor(void *ptr) +{ + autofree_context = NULL; + return 0; +} + static void talloc_autofree(void) { - talloc_free(cleanup_context); - cleanup_context = NULL; + talloc_free(autofree_context); } /* @@ -1220,11 +1225,12 @@ static void talloc_autofree(void) */ void *talloc_autofree_context(void) { - if (cleanup_context == NULL) { - cleanup_context = talloc_named_const(NULL, 0, "autofree_context"); + if (autofree_context == NULL) { + autofree_context = talloc_named_const(NULL, 0, "autofree_context"); + talloc_set_destructor(autofree_context, talloc_autofree_destructor); atexit(talloc_autofree); } - return cleanup_context; + return autofree_context; } size_t talloc_get_size(const void *context) -- cgit From 2729f448c073232bc33feba4b520871bb6a583c9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 21 Oct 2006 00:23:27 +0000 Subject: r19431: merge recent talloc performance improvements from Samba4 (This used to be commit ced12bd6d8c95a103cb2c84166a64f9a21bd32ad) --- source3/lib/talloc/talloc.c | 527 ++++++++++++++++++++++++++------------------ 1 file changed, 316 insertions(+), 211 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 15b27c61ee..bae1942f43 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -77,6 +77,17 @@ #endif #endif +/* these macros gain us a few percent of speed on gcc */ +#if (__GNUC__ >= 3) +/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 + as its first argument */ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) x +#define unlikely(x) x +#endif + /* this null_context is only used if talloc_enable_leak_report() or talloc_enable_leak_report_full() is called, otherwise it remains NULL @@ -106,15 +117,16 @@ struct talloc_chunk { #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) /* panic if we get a bad magic value */ -static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) +static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) { const char *pp = (const char *)ptr; struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); - if ((tc->flags & ~0xF) != TALLOC_MAGIC) { - TALLOC_ABORT("Bad talloc magic value - unknown value"); - } - if (tc->flags & TALLOC_FLAG_FREE) { - TALLOC_ABORT("Bad talloc magic value - double free"); + if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { + if (tc->flags & TALLOC_FLAG_FREE) { + TALLOC_ABORT("Bad talloc magic value - double free"); + } else { + TALLOC_ABORT("Bad talloc magic value - unknown value"); + } } return tc; } @@ -163,23 +175,43 @@ void *talloc_parent(const void *ptr) return tc? TC_PTR_FROM_CHUNK(tc) : NULL; } +/* + find parents name +*/ +const char *talloc_parent_name(const void *context) +{ + struct talloc_chunk *tc; + + if (unlikely(context == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(context); + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + return tc->name; +} + + /* Allocate a bit of memory as a child of an existing pointer */ -void *_talloc(const void *context, size_t size) +static inline void *__talloc(const void *context, size_t size) { struct talloc_chunk *tc; - if (context == NULL) { + if (unlikely(context == NULL)) { context = null_context; } - if (size >= MAX_TALLOC_SIZE) { + if (unlikely(size >= MAX_TALLOC_SIZE)) { return NULL; } tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); - if (tc == NULL) return NULL; + if (unlikely(tc == NULL)) return NULL; tc->size = size; tc->flags = TALLOC_MAGIC; @@ -188,16 +220,19 @@ void *_talloc(const void *context, size_t size) tc->name = NULL; tc->refs = NULL; - if (context) { + if (likely(context)) { struct talloc_chunk *parent = talloc_chunk_from_ptr(context); - tc->parent = parent; - if (parent->child) { parent->child->parent = NULL; + tc->next = parent->child; + tc->next->prev = tc; + } else { + tc->next = NULL; } - - _TLIST_ADD(parent->child, tc); + tc->parent = parent; + tc->prev = NULL; + parent->child = tc; } else { tc->next = tc->prev = tc->parent = NULL; } @@ -205,7 +240,6 @@ void *_talloc(const void *context, size_t size) return TC_PTR_FROM_CHUNK(tc); } - /* setup a destructor to be called on free of a pointer the destructor should return 0 on success, or -1 on failure. @@ -223,7 +257,7 @@ void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) */ int talloc_increase_ref_count(const void *ptr) { - if (!talloc_reference(null_context, ptr)) { + if (unlikely(!talloc_reference(null_context, ptr))) { return -1; } return 0; @@ -239,6 +273,33 @@ static int talloc_reference_destructor(struct talloc_reference_handle *handle) return 0; } +/* + more efficient way to add a name to a pointer - the name must point to a + true string constant +*/ +static inline void _talloc_set_name_const(const void *ptr, const char *name) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->name = name; +} + +/* + internal talloc_named_const() +*/ +static inline void *_talloc_named_const(const void *context, size_t size, const char *name) +{ + void *ptr; + + ptr = __talloc(context, size); + if (unlikely(ptr == NULL)) { + return NULL; + } + + _talloc_set_name_const(ptr, name); + + return ptr; +} + /* make a secondary reference to a pointer, hanging off the given context. the pointer remains valid until both the original caller and this given @@ -252,13 +313,13 @@ void *_talloc_reference(const void *context, const void *ptr) { struct talloc_chunk *tc; struct talloc_reference_handle *handle; - if (ptr == NULL) return NULL; + if (unlikely(ptr == NULL)) return NULL; tc = talloc_chunk_from_ptr(ptr); - handle = (struct talloc_reference_handle *)talloc_named_const(context, + handle = (struct talloc_reference_handle *)_talloc_named_const(context, sizeof(struct talloc_reference_handle), TALLOC_MAGIC_REFERENCE); - if (handle == NULL) return NULL; + if (unlikely(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 @@ -269,6 +330,152 @@ void *_talloc_reference(const void *context, const void *ptr) return handle->ptr; } + +/* + internal talloc_free call +*/ +static inline int _talloc_free(void *ptr) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return -1; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(tc->refs)) { + int is_child; + /* check this is a reference from a child or grantchild + * back to it's parent or grantparent + * + * in that case we need to remove the reference and + * call another instance of talloc_free() on the current + * pointer. + */ + is_child = talloc_is_parent(tc->refs, ptr); + _talloc_free(tc->refs); + if (is_child) { + return _talloc_free(ptr); + } + return -1; + } + + if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) { + /* we have a free loop - stop looping */ + return 0; + } + + if (unlikely(tc->destructor)) { + talloc_destructor_t d = tc->destructor; + if (d == (talloc_destructor_t)-1) { + return -1; + } + tc->destructor = (talloc_destructor_t)-1; + if (d(ptr) == -1) { + tc->destructor = d; + return -1; + } + tc->destructor = NULL; + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + while (tc->child) { + /* we need to work out who will own an abandoned child + if it cannot be freed. In priority order, the first + choice is owner of any remaining reference to this + pointer, the second choice is our parent, and the + final choice is the null context. */ + void *child = TC_PTR_FROM_CHUNK(tc->child); + const void *new_parent = null_context; + if (unlikely(tc->child->refs)) { + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + if (unlikely(_talloc_free(child) == -1)) { + if (new_parent == null_context) { + struct talloc_chunk *p = talloc_parent_chunk(ptr); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + talloc_steal(new_parent, child); + } + } + + tc->flags |= TALLOC_FLAG_FREE; + free(tc); + return 0; +} + +/* + move a lump of memory from one talloc context to another return the + ptr on success, or NULL if it could not be transferred. + passing NULL as ptr will always return NULL with no side effects. +*/ +void *_talloc_steal(const void *new_ctx, const void *ptr) +{ + struct talloc_chunk *tc, *new_tc; + + if (unlikely(!ptr)) { + return NULL; + } + + if (unlikely(new_ctx == NULL)) { + new_ctx = null_context; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(new_ctx == NULL)) { + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = tc->next = tc->prev = NULL; + return discard_const_p(void, ptr); + } + + new_tc = talloc_chunk_from_ptr(new_ctx); + + if (unlikely(tc == new_tc || tc->parent == new_tc)) { + return discard_const_p(void, ptr); + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = new_tc; + if (new_tc->child) new_tc->child->parent = NULL; + _TLIST_ADD(new_tc->child, tc); + + return discard_const_p(void, ptr); +} + + + /* remove a secondary reference to a pointer. This undo's what talloc_reference() has done. The context and pointer arguments @@ -279,7 +486,7 @@ static int talloc_unreference(const void *context, const void *ptr) struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); struct talloc_reference_handle *h; - if (context == NULL) { + if (unlikely(context == NULL)) { context = null_context; } @@ -295,7 +502,7 @@ static int talloc_unreference(const void *context, const void *ptr) return -1; } - return talloc_free(h); + return _talloc_free(h); } /* @@ -332,7 +539,7 @@ int talloc_unlink(const void *context, void *ptr) tc_p = talloc_chunk_from_ptr(ptr); if (tc_p->refs == NULL) { - return talloc_free(ptr); + return _talloc_free(ptr); } new_p = talloc_parent_chunk(tc_p->refs); @@ -360,8 +567,8 @@ static const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list a { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->name = talloc_vasprintf(ptr, fmt, ap); - if (tc->name) { - talloc_set_name_const(tc->name, ".name"); + if (likely(tc->name)) { + _talloc_set_name_const(tc->name, ".name"); } return tc->name; } @@ -379,15 +586,6 @@ const char *talloc_set_name(const void *ptr, const char *fmt, ...) return name; } -/* - more efficient way to add a name to a pointer - the name must point to a - true string constant -*/ -void talloc_set_name_const(const void *ptr, const char *name) -{ - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - tc->name = name; -} /* create a named talloc pointer. Any talloc pointer can be named, and @@ -400,50 +598,31 @@ void *talloc_named(const void *context, size_t size, const char *fmt, ...) void *ptr; const char *name; - ptr = _talloc(context, size); - if (ptr == NULL) return NULL; + ptr = __talloc(context, size); + if (unlikely(ptr == NULL)) return NULL; va_start(ap, fmt); name = talloc_set_name_v(ptr, fmt, ap); va_end(ap); - if (name == NULL) { - talloc_free(ptr); + if (unlikely(name == NULL)) { + _talloc_free(ptr); return NULL; } return ptr; } -/* - create a named talloc pointer. Any talloc pointer can be named, and - talloc_named() operates just like talloc() except that it allows you - to name the pointer. -*/ -void *talloc_named_const(const void *context, size_t size, const char *name) -{ - void *ptr; - - ptr = _talloc(context, size); - if (ptr == NULL) { - return NULL; - } - - talloc_set_name_const(ptr, name); - - return ptr; -} - /* return the name of a talloc ptr, or "UNNAMED" */ const char *talloc_get_name(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); - if (tc->name == TALLOC_MAGIC_REFERENCE) { + if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { return ".reference"; } - if (tc->name) { + if (likely(tc->name)) { return tc->name; } return "UNNAMED"; @@ -457,9 +636,9 @@ const char *talloc_get_name(const void *ptr) void *talloc_check_name(const void *ptr, const char *name) { const char *pname; - if (ptr == NULL) return NULL; + if (unlikely(ptr == NULL)) return NULL; pname = talloc_get_name(ptr); - if (pname == name || strcmp(pname, name) == 0) { + if (likely(pname == name || strcmp(pname, name) == 0)) { return discard_const_p(void, ptr); } return NULL; @@ -482,15 +661,15 @@ void *talloc_init(const char *fmt, ...) */ talloc_enable_null_tracking(); - ptr = _talloc(NULL, 0); - if (ptr == NULL) return NULL; + ptr = __talloc(NULL, 0); + if (unlikely(ptr == NULL)) return NULL; va_start(ap, fmt); name = talloc_set_name_v(ptr, fmt, ap); va_end(ap); - if (name == NULL) { - talloc_free(ptr); + if (unlikely(name == NULL)) { + _talloc_free(ptr); return NULL; } @@ -506,7 +685,7 @@ void talloc_free_children(void *ptr) { struct talloc_chunk *tc; - if (ptr == NULL) { + if (unlikely(ptr == NULL)) { return; } @@ -520,11 +699,11 @@ void talloc_free_children(void *ptr) final choice is the null context. */ void *child = TC_PTR_FROM_CHUNK(tc->child); const void *new_parent = null_context; - if (tc->child->refs) { + if (unlikely(tc->child->refs)) { struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); if (p) new_parent = TC_PTR_FROM_CHUNK(p); } - if (talloc_free(child) == -1) { + if (unlikely(_talloc_free(child) == -1)) { if (new_parent == null_context) { struct talloc_chunk *p = talloc_parent_chunk(ptr); if (p) new_parent = TC_PTR_FROM_CHUNK(p); @@ -534,6 +713,32 @@ void talloc_free_children(void *ptr) } } +/* + Allocate a bit of memory as a child of an existing pointer +*/ +void *_talloc(const void *context, size_t size) +{ + return __talloc(context, size); +} + +/* + externally callable talloc_set_name_const() +*/ +void talloc_set_name_const(const void *ptr, const char *name) +{ + _talloc_set_name_const(ptr, name); +} + +/* + create a named talloc pointer. Any talloc pointer can be named, and + talloc_named() operates just like talloc() except that it allows you + to name the pointer. +*/ +void *talloc_named_const(const void *context, size_t size, const char *name) +{ + return _talloc_named_const(context, size, name); +} + /* free a talloc pointer. This also frees all child pointers of this pointer recursively @@ -544,68 +749,7 @@ void talloc_free_children(void *ptr) */ int talloc_free(void *ptr) { - struct talloc_chunk *tc; - int old_errno; - - if (ptr == NULL) { - return -1; - } - - tc = talloc_chunk_from_ptr(ptr); - - if (tc->refs) { - int is_child; - /* check this is a reference from a child or grantchild - * back to it's parent or grantparent - * - * in that case we need to remove the reference and - * call another instance of talloc_free() on the current - * pointer. - */ - is_child = talloc_is_parent(tc->refs, ptr); - talloc_free(tc->refs); - if (is_child) { - return talloc_free(ptr); - } - return -1; - } - - if (tc->flags & TALLOC_FLAG_LOOP) { - /* we have a free loop - stop looping */ - return 0; - } - - if (tc->destructor) { - talloc_destructor_t d = tc->destructor; - if (d == (talloc_destructor_t)-1) { - return -1; - } - tc->destructor = (talloc_destructor_t)-1; - if (d(ptr) == -1) { - tc->destructor = d; - return -1; - } - tc->destructor = NULL; - } - - if (tc->parent) { - _TLIST_REMOVE(tc->parent->child, tc); - if (tc->parent->child) { - tc->parent->child->parent = tc->parent; - } - } else { - if (tc->prev) tc->prev->next = tc->next; - if (tc->next) tc->next->prev = tc->prev; - } - - tc->flags |= TALLOC_FLAG_LOOP; - talloc_free_children(ptr); - - tc->flags |= TALLOC_FLAG_FREE; - old_errno = errno; - free(tc); - errno = old_errno; - return 0; + return _talloc_free(ptr); } @@ -620,24 +764,24 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n void *new_ptr; /* size zero is equivalent to free() */ - if (size == 0) { - talloc_free(ptr); + if (unlikely(size == 0)) { + _talloc_free(ptr); return NULL; } - if (size >= MAX_TALLOC_SIZE) { + if (unlikely(size >= MAX_TALLOC_SIZE)) { return NULL; } /* realloc(NULL) is equavalent to malloc() */ if (ptr == NULL) { - return talloc_named_const(context, size, name); + return _talloc_named_const(context, size, name); } tc = talloc_chunk_from_ptr(ptr); /* don't allow realloc on referenced pointers */ - if (tc->refs) { + if (unlikely(tc->refs)) { return NULL; } @@ -653,7 +797,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n #else new_ptr = realloc(tc, size + TC_HDR_SIZE); #endif - if (!new_ptr) { + if (unlikely(!new_ptr)) { tc->flags &= ~TALLOC_FLAG_FREE; return NULL; } @@ -675,68 +819,11 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n } tc->size = size; - talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); + _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); return TC_PTR_FROM_CHUNK(tc); } -/* - move a lump of memory from one talloc context to another return the - ptr on success, or NULL if it could not be transferred. - passing NULL as ptr will always return NULL with no side effects. -*/ -void *_talloc_steal(const void *new_ctx, const void *ptr) -{ - struct talloc_chunk *tc, *new_tc; - - if (!ptr) { - return NULL; - } - - if (new_ctx == NULL) { - new_ctx = null_context; - } - - tc = talloc_chunk_from_ptr(ptr); - - if (new_ctx == NULL) { - if (tc->parent) { - _TLIST_REMOVE(tc->parent->child, tc); - if (tc->parent->child) { - tc->parent->child->parent = tc->parent; - } - } else { - if (tc->prev) tc->prev->next = tc->next; - if (tc->next) tc->next->prev = tc->prev; - } - - tc->parent = tc->next = tc->prev = NULL; - return discard_const_p(void, ptr); - } - - new_tc = talloc_chunk_from_ptr(new_ctx); - - if (tc == new_tc || tc->parent == new_tc) { - return discard_const_p(void, ptr); - } - - if (tc->parent) { - _TLIST_REMOVE(tc->parent->child, tc); - if (tc->parent->child) { - tc->parent->child->parent = tc->parent; - } - } else { - if (tc->prev) tc->prev->next = tc->next; - if (tc->next) tc->next->prev = tc->prev; - } - - tc->parent = new_tc; - if (new_tc->child) new_tc->child->parent = NULL; - _TLIST_ADD(new_tc->child, tc); - - return discard_const_p(void, ptr); -} - /* a wrapper around talloc_steal() for situations where you are moving a pointer between two structures, and want the old pointer to be set to NULL @@ -880,12 +967,29 @@ static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_ return; } - fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", depth*4, "", name, (unsigned long)talloc_total_size(ptr), (unsigned long)talloc_total_blocks(ptr), - (int)talloc_reference_count(ptr)); + (int)talloc_reference_count(ptr), ptr); + +#if 0 + fprintf(f, "content: "); + if (talloc_total_size(ptr)) { + int tot = talloc_total_size(ptr); + int i; + + for (i = 0; i < tot; i++) { + if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) { + fprintf(f, "%c", ((char *)ptr)[i]); + } else { + fprintf(f, "~%02x", ((char *)ptr)[i]); + } + } + } + fprintf(f, "\n"); +#endif } /* @@ -939,7 +1043,7 @@ static void talloc_report_null_full(void) void talloc_enable_null_tracking(void) { if (null_context == NULL) { - null_context = talloc_named_const(NULL, 0, "null_context"); + null_context = _talloc_named_const(NULL, 0, "null_context"); } } @@ -948,7 +1052,7 @@ void talloc_enable_null_tracking(void) */ void talloc_disable_null_tracking(void) { - talloc_free(null_context); + _talloc_free(null_context); null_context = NULL; } @@ -975,7 +1079,7 @@ void talloc_enable_leak_report_full(void) */ void *_talloc_zero(const void *ctx, size_t size, const char *name) { - void *p = talloc_named_const(ctx, size, name); + void *p = _talloc_named_const(ctx, size, name); if (p) { memset(p, '\0', size); @@ -990,9 +1094,9 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name) */ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) { - void *newp = talloc_named_const(t, size, name); + void *newp = _talloc_named_const(t, size, name); - if (newp) { + if (likely(newp)) { memcpy(newp, p, size); } @@ -1009,8 +1113,8 @@ char *talloc_strdup(const void *t, const char *p) return NULL; } ret = (char *)talloc_memdup(t, p, strlen(p) + 1); - if (ret) { - talloc_set_name_const(ret, ret); + if (likely(ret)) { + _talloc_set_name_const(ret, ret); } return ret; } @@ -1049,11 +1153,11 @@ char *talloc_strndup(const void *t, const char *p, size_t n) for (len=0; len= MAX_TALLOC_SIZE/el_size) { return NULL; } - return talloc_named_const(ctx, el_size * count, name); + return _talloc_named_const(ctx, el_size * count, name); } /* @@ -1216,7 +1320,7 @@ static int talloc_autofree_destructor(void *ptr) static void talloc_autofree(void) { - talloc_free(autofree_context); + _talloc_free(autofree_context); } /* @@ -1226,7 +1330,7 @@ static void talloc_autofree(void) void *talloc_autofree_context(void) { if (autofree_context == NULL) { - autofree_context = talloc_named_const(NULL, 0, "autofree_context"); + autofree_context = _talloc_named_const(NULL, 0, "autofree_context"); talloc_set_destructor(autofree_context, talloc_autofree_destructor); atexit(talloc_autofree); } @@ -1290,6 +1394,7 @@ void talloc_show_parents(const void *context, FILE *file) tc = tc->parent; } } + fflush(file); } /* -- cgit From e37200a82e171b663d51ec67bd20cf4433235cdd Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 18 Nov 2006 17:06:02 +0000 Subject: r19774: Fix typo (This used to be commit 842599a7fd1217b498dc2d241d39ed604cf0da7d) --- source3/lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index bae1942f43..91e02d7e1e 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -773,7 +773,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n return NULL; } - /* realloc(NULL) is equavalent to malloc() */ + /* realloc(NULL) is equivalent to malloc() */ if (ptr == NULL) { return _talloc_named_const(context, size, name); } -- cgit From 247e1667b00354d0407b8f3de2dc11ba751b1918 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Dec 2006 22:58:06 +0000 Subject: r20197: merge talloc fixes from samba4: - make most static functions inline - handle NULL pointers in talloc_parent_chunk() - use talloc_parent_chunk() in talloc_parent_name() to fix a bug found by the IBM checker metze (This used to be commit c718eb7a7c3cdc4acb25f303a73a3ca478c27af0) --- source3/lib/talloc/talloc.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 91e02d7e1e..15a44bd0d9 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -162,10 +162,17 @@ do { \ /* return the parent chunk of a pointer */ -static struct talloc_chunk *talloc_parent_chunk(const void *ptr) +static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr) { - struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ptr); while (tc->prev) tc=tc->prev; + return tc->parent; } @@ -178,23 +185,12 @@ void *talloc_parent(const void *ptr) /* find parents name */ -const char *talloc_parent_name(const void *context) +const char *talloc_parent_name(const void *ptr) { - struct talloc_chunk *tc; - - if (unlikely(context == NULL)) { - return NULL; - } - - tc = talloc_chunk_from_ptr(context); - while (tc && tc->prev) tc = tc->prev; - if (tc) { - tc = tc->parent; - } - return tc->name; + struct talloc_chunk *tc = talloc_parent_chunk(ptr); + return tc? tc->name : NULL; } - /* Allocate a bit of memory as a child of an existing pointer */ @@ -265,6 +261,8 @@ int talloc_increase_ref_count(const void *ptr) /* helper for talloc_reference() + + this is referenced by a function pointer and should not be inline */ static int talloc_reference_destructor(struct talloc_reference_handle *handle) { @@ -481,7 +479,7 @@ void *_talloc_steal(const void *new_ctx, const void *ptr) talloc_reference() has done. The context and pointer arguments must match those given to a talloc_reference() */ -static int talloc_unreference(const void *context, const void *ptr) +static inline int talloc_unreference(const void *context, const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); struct talloc_reference_handle *h; @@ -561,9 +559,9 @@ int talloc_unlink(const void *context, void *ptr) /* add a name to an existing pointer - va_list version */ -static const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); +static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); -static const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) +static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->name = talloc_vasprintf(ptr, fmt, ap); -- cgit From 5f8840ec844067dba987e8e28d8e96b90338d15c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 6 Feb 2007 05:58:35 +0000 Subject: r21176: merged va_end() changes from Samba4 (This used to be commit 04f6f01dfeda2fa076209a94cdf8e59f6ce47008) --- source3/lib/talloc/talloc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 15a44bd0d9..028b44a8c7 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1174,10 +1174,11 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) va_list ap2; char c; - va_copy(ap2, ap); - /* this call looks strange, but it makes it work on older solaris boxes */ - if ((len = vsnprintf(&c, 1, fmt, ap2)) < 0) { + va_copy(ap2, ap); + len = vsnprintf(&c, 1, fmt, ap2); + va_end(ap2); + if (len < 0) { return NULL; } @@ -1185,6 +1186,7 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) if (ret) { va_copy(ap2, ap); vsnprintf(ret, len+1, fmt, ap2); + va_end(ap2); _talloc_set_name_const(ret, ret); } @@ -1226,10 +1228,13 @@ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) tc = talloc_chunk_from_ptr(s); + s_len = tc->size - 1; + va_copy(ap2, ap); + len = vsnprintf(&c, 1, fmt, ap2); + va_end(ap2); - s_len = tc->size - 1; - if ((len = vsnprintf(&c, 1, fmt, ap2)) <= 0) { + if (len <= 0) { /* Either the vsnprintf failed or the format resulted in * no characters being formatted. In the former case, we * ought to return NULL, in the latter we ought to return @@ -1243,8 +1248,8 @@ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) if (!s) return NULL; va_copy(ap2, ap); - vsnprintf(s+s_len, len+1, fmt, ap2); + va_end(ap2); _talloc_set_name_const(s, s); return s; -- cgit From c07643fa18fed1f7739fb4e92ce6e58dd40be756 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 27 Apr 2007 21:09:16 +0000 Subject: r22539: Added _strict varients of the talloc calls to return NULL on size == 0 varients. Jeremy. (This used to be commit 1283da1bf8ebe458cf84ee4a703909945cdfcd88) --- source3/lib/talloc/talloc.c | 87 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 028b44a8c7..8f7906d0d8 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1087,6 +1087,28 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name) } +/* + talloc and zero memory. + Strict version - returns NULL if size is zero. +*/ +void *_talloc_zero_strict(const void *ctx, size_t size, const char *name) +{ + void *p; + + if (unlikely(size == 0)) { + return NULL; + } + + p = _talloc_named_const(ctx, size, name); + + if (p) { + memset(p, '\0', size); + } + + return p; +} + + /* memdup with a talloc. */ @@ -1101,6 +1123,26 @@ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name return newp; } +/* + memdup with a talloc. + Strict version - returns NULL if size is zero. +*/ +void *_talloc_memdup_strict(const void *t, const void *p, size_t size, const char *name) +{ + void *newp; + + if (unlikely(size == 0)) { + return NULL; + } + + newp = _talloc_named_const(t, size, name); + if (likely(newp)) { + memcpy(newp, p, size); + } + + return newp; +} + /* strdup with a talloc */ @@ -1281,6 +1323,23 @@ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char return _talloc_named_const(ctx, el_size * count, name); } +/* + alloc an array, checking for integer overflow in the array size. + Strict version - returns NULL if count or el_size are zero. +*/ +void *_talloc_array_strict(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + + if (el_size == 0 || count == 0) { + return NULL; + } + + return _talloc_named_const(ctx, el_size * count, name); +} + /* alloc an zero array, checking for integer overflow in the array size */ @@ -1292,6 +1351,23 @@ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const return _talloc_zero(ctx, el_size * count, name); } +/* + alloc an zero array, checking for integer overflow in the array size + Strict version - returns NULL if count or el_size are zero. +*/ +void *_talloc_zero_array_strict(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + + if (el_size == 0 || count == 0) { + return NULL; + } + + return _talloc_zero(ctx, el_size * count, name); +} + /* realloc an array, checking for integer overflow in the array size @@ -1421,3 +1497,14 @@ int talloc_is_parent(const void *context, const void *ptr) } return 0; } + +/* + Talloc wrapper that returns NULL if size == 0. +*/ +void *talloc_strict(const void *context, size_t size, const char *name) +{ + if (unlikely(size == 0)) { + return NULL; + } + return _talloc_named_const(context, size, name); +} -- cgit From 4ab6a8ebb70bbd5d69ad1dc6196c936f01f5aaf7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Sun, 29 Apr 2007 00:09:22 +0000 Subject: r22564: Move the _strict -> _zeronull functions into lib/util.c and out of talloc at tridge's request. Jeremy. (This used to be commit da78488b86c464b6861d36398cca7524ad5906fe) --- source3/lib/talloc/talloc.c | 89 --------------------------------------------- 1 file changed, 89 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 8f7906d0d8..b2b00d8c65 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1086,29 +1086,6 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name) return p; } - -/* - talloc and zero memory. - Strict version - returns NULL if size is zero. -*/ -void *_talloc_zero_strict(const void *ctx, size_t size, const char *name) -{ - void *p; - - if (unlikely(size == 0)) { - return NULL; - } - - p = _talloc_named_const(ctx, size, name); - - if (p) { - memset(p, '\0', size); - } - - return p; -} - - /* memdup with a talloc. */ @@ -1123,26 +1100,6 @@ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name return newp; } -/* - memdup with a talloc. - Strict version - returns NULL if size is zero. -*/ -void *_talloc_memdup_strict(const void *t, const void *p, size_t size, const char *name) -{ - void *newp; - - if (unlikely(size == 0)) { - return NULL; - } - - newp = _talloc_named_const(t, size, name); - if (likely(newp)) { - memcpy(newp, p, size); - } - - return newp; -} - /* strdup with a talloc */ @@ -1323,23 +1280,6 @@ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char return _talloc_named_const(ctx, el_size * count, name); } -/* - alloc an array, checking for integer overflow in the array size. - Strict version - returns NULL if count or el_size are zero. -*/ -void *_talloc_array_strict(const void *ctx, size_t el_size, unsigned count, const char *name) -{ - if (count >= MAX_TALLOC_SIZE/el_size) { - return NULL; - } - - if (el_size == 0 || count == 0) { - return NULL; - } - - return _talloc_named_const(ctx, el_size * count, name); -} - /* alloc an zero array, checking for integer overflow in the array size */ @@ -1351,24 +1291,6 @@ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const return _talloc_zero(ctx, el_size * count, name); } -/* - alloc an zero array, checking for integer overflow in the array size - Strict version - returns NULL if count or el_size are zero. -*/ -void *_talloc_zero_array_strict(const void *ctx, size_t el_size, unsigned count, const char *name) -{ - if (count >= MAX_TALLOC_SIZE/el_size) { - return NULL; - } - - if (el_size == 0 || count == 0) { - return NULL; - } - - return _talloc_zero(ctx, el_size * count, name); -} - - /* realloc an array, checking for integer overflow in the array size */ @@ -1497,14 +1419,3 @@ int talloc_is_parent(const void *context, const void *ptr) } return 0; } - -/* - Talloc wrapper that returns NULL if size == 0. -*/ -void *talloc_strict(const void *context, size_t size, const char *name) -{ - if (unlikely(size == 0)) { - return NULL; - } - return _talloc_named_const(context, size, name); -} -- cgit From dcc2fe7cb61937aa191bf8b5f353d0308a8011a3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 8 May 2007 11:12:11 +0000 Subject: r22759: sync lib/talloc with samba4 metze (This used to be commit 86c510e3198e03ed6efa61b27530bbb008f6802b) --- source3/lib/talloc/talloc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index b2b00d8c65..abc1e9438e 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1137,6 +1137,8 @@ char *talloc_append_string(const void *t, char *orig, const char *append) /* append the string with the trailing \0 */ memcpy(&ret[olen], append, alenz); + _talloc_set_name_const(ret, ret); + return ret; } -- cgit From 2c09988e46d4e917b1c53c9bda3f81a48bba4952 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 01:44:42 +0000 Subject: r23790: LGPLv3+ conversion for our LGPLv2+ library code (This used to be commit 1b78cace504f60c0f525765fbf59d9cc6506cd4d) --- source3/lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index abc1e9438e..a28e9defad 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -15,7 +15,7 @@ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -- cgit From 9fa1c63578733077c0aaaeeb2fc97c3b191089cc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 03:42:26 +0000 Subject: r23798: updated old Temple Place FSF addresses to new URL (This used to be commit c676a971142d7176fd5dbf21405fca14515a0a76) --- source3/lib/talloc/talloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index a28e9defad..6ebdada42f 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -23,8 +23,7 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + License along with this library; if not, see . */ /* -- cgit From 3b29c9cbede001ed0f228ad4738ee4f6604fd367 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 22 Aug 2007 12:44:41 +0000 Subject: r24627: merge from SAMBA_4_0: as TALLOC_ABORT() is defined to abort() by default wrap it into a function so that the function name in the backtrace shows what happens. metze (This used to be commit ddbe971030070ab1b9fc37b8b0ac44a3d9303fe4) --- source3/lib/talloc/talloc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 6ebdada42f..c073a8c774 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -115,6 +115,16 @@ struct talloc_chunk { #define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15) #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) +static void talloc_abort_double_free(void) +{ + TALLOC_ABORT("Bad talloc magic value - double free"); +} + +static void talloc_abort_unknown_value(void) +{ + TALLOC_ABORT("Bad talloc magic value - unknown value"); +} + /* panic if we get a bad magic value */ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) { @@ -122,9 +132,9 @@ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { if (tc->flags & TALLOC_FLAG_FREE) { - TALLOC_ABORT("Bad talloc magic value - double free"); + talloc_abort_double_free(); } else { - TALLOC_ABORT("Bad talloc magic value - unknown value"); + talloc_abort_unknown_value(); } } return tc; -- cgit From 4754b0ec65a3be4380f3216bd3f59c1906db259b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 12 Sep 2007 21:41:36 +0000 Subject: r25116: Fix talloc_asprintf_append to do the right thing with truncated strings. Jeremy. (This used to be commit 93c42fd9b52d9135d8c8b52e97cf342c1c5b5010) --- source3/lib/talloc/talloc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index c073a8c774..c3e5d2c076 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1226,8 +1226,7 @@ char *talloc_asprintf(const void *t, const char *fmt, ...) * accumulating output into a string buffer. **/ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) -{ - struct talloc_chunk *tc; +{ int len, s_len; va_list ap2; char c; @@ -1236,9 +1235,7 @@ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) return talloc_vasprintf(NULL, fmt, ap); } - tc = talloc_chunk_from_ptr(s); - - s_len = tc->size - 1; + s_len = strlen(s); va_copy(ap2, ap); len = vsnprintf(&c, 1, fmt, ap2); -- cgit From 47107b2cdea7c58c337639f6d1aaab94390bf0f6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 14 Sep 2007 17:40:58 +0000 Subject: r25164: Add talloc_asprintf_append_buffer() and the docs for it. Jeremy. (This used to be commit 2243a73d650319208aebbbaf65dfba2a508a7c10) --- source3/lib/talloc/talloc.c | 65 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index c3e5d2c076..7920a66d64 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1223,7 +1223,8 @@ char *talloc_asprintf(const void *t, const char *fmt, ...) /** * Realloc @p s to append the formatted result of @p fmt and @p ap, * and return @p s, which may have moved. Good for gradually - * accumulating output into a string buffer. + * accumulating output into a string buffer. Appends at the end + * of the string. **/ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) { @@ -1245,7 +1246,52 @@ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) /* Either the vsnprintf failed or the format resulted in * no characters being formatted. In the former case, we * ought to return NULL, in the latter we ought to return - * the original string. Most current callers of this + * the original string. Most current callers of this + * function expect it to never return NULL. + */ + return s; + } + + s = talloc_realloc(NULL, s, char, s_len + len+1); + if (!s) return NULL; + + va_copy(ap2, ap); + vsnprintf(s+s_len, len+1, fmt, ap2); + va_end(ap2); + _talloc_set_name_const(s, s); + + return s; +} + +/** + * Realloc @p s to append the formatted result of @p fmt and @p ap, + * and return @p s, which may have moved. Always appends at the + * end of the talloc'ed buffer, not the end of the string. + **/ +char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) +{ + struct talloc_chunk *tc; + int len, s_len; + va_list ap2; + char c; + + if (s == NULL) { + return talloc_vasprintf(NULL, fmt, ap); + } + + tc = talloc_chunk_from_ptr(s); + + s_len = tc->size - 1; + + va_copy(ap2, ap); + len = vsnprintf(&c, 1, fmt, ap2); + va_end(ap2); + + if (len <= 0) { + /* Either the vsnprintf failed or the format resulted in + * no characters being formatted. In the former case, we + * ought to return NULL, in the latter we ought to return + * the original string. Most current callers of this * function expect it to never return NULL. */ return s; @@ -1277,6 +1323,21 @@ char *talloc_asprintf_append(char *s, const char *fmt, ...) return s; } +/* + Realloc @p s to append the formatted result of @p fmt and return @p + s, which may have moved. Good for gradually accumulating output + into a buffer. + */ +char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + s = talloc_vasprintf_append_buffer(s, fmt, ap); + va_end(ap); + return s; +} + /* alloc an array, checking for integer overflow in the array size */ -- cgit From 10cb1b87ed44540454fd99b817c0a7a9d74afea2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 19 Sep 2007 14:44:16 +0000 Subject: r25230: sync lib/talloc with SAMBA_4_0 metze (This used to be commit 84ebb6cac224cabf3856a632de80a8a9c687329b) --- source3/lib/talloc/talloc.c | 233 +++++++++++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 91 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 7920a66d64..4d72c0e871 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1109,64 +1109,132 @@ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name return newp; } +static inline char *__talloc_strlendup(const void *t, const char *p, size_t len) +{ + char *ret; + + ret = (char *)__talloc(t, len + 1); + if (unlikely(!ret)) return NULL; + + memcpy(ret, p, len); + ret[len] = 0; + + _talloc_set_name_const(ret, ret); + return ret; +} + /* - strdup with a talloc + strdup with a talloc */ char *talloc_strdup(const void *t, const char *p) +{ + if (unlikely(!p)) return NULL; + return __talloc_strlendup(t, p, strlen(p)); +} + +/* + strndup with a talloc +*/ +char *talloc_strndup(const void *t, const char *p, size_t n) +{ + if (unlikely(!p)) return NULL; + return __talloc_strlendup(t, p, strnlen(p, n)); +} + +static inline char *__talloc_strlendup_append(char *s, size_t slen, + const char *a, size_t alen) { char *ret; - if (!p) { - return NULL; + + ret = talloc_realloc(NULL, s, char, slen + alen + 1); + if (unlikely(!ret)) return NULL; + + /* append the string and the trailing \0 */ + memcpy(&ret[slen], a, alen); + ret[slen+alen] = 0; + + _talloc_set_name_const(ret, ret); + return ret; +} + +/* + * Appends at the end of the string. + */ +char *talloc_strdup_append(char *s, const char *a) +{ + if (unlikely(!s)) { + return talloc_strdup(NULL, a); } - ret = (char *)talloc_memdup(t, p, strlen(p) + 1); - if (likely(ret)) { - _talloc_set_name_const(ret, ret); + + if (unlikely(!a)) { + return s; } - return ret; + + return __talloc_strlendup_append(s, strlen(s), a, strlen(a)); } /* - append to a talloced string -*/ -char *talloc_append_string(const void *t, char *orig, const char *append) + * Appends at the end of the talloc'ed buffer, + * not the end of the string. + */ +char *talloc_strdup_append_buffer(char *s, const char *a) { - char *ret; - size_t olen = strlen(orig); - size_t alenz; + size_t slen; - if (!append) - return orig; + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } - alenz = strlen(append) + 1; + if (unlikely(!a)) { + return s; + } - ret = talloc_realloc(t, orig, char, olen + alenz); - if (!ret) - return NULL; + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } - /* append the string with the trailing \0 */ - memcpy(&ret[olen], append, alenz); + return __talloc_strlendup_append(s, slen, a, strlen(a)); +} - _talloc_set_name_const(ret, ret); +/* + * Appends at the end of the string. + */ +char *talloc_strndup_append(char *s, const char *a, size_t n) +{ + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } - return ret; + if (unlikely(!a)) { + return s; + } + + return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n)); } /* - strndup with a talloc -*/ -char *talloc_strndup(const void *t, const char *p, size_t n) + * Appends at the end of the talloc'ed buffer, + * not the end of the string. + */ +char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) { - size_t len; - char *ret; + size_t slen; - for (len=0; len 0)) { + slen--; + } + + return __talloc_strlendup_append(s, slen, a, strnlen(a, n)); } #ifndef HAVE_VA_COPY @@ -1188,18 +1256,18 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) va_copy(ap2, ap); len = vsnprintf(&c, 1, fmt, ap2); va_end(ap2); - if (len < 0) { + if (unlikely(len < 0)) { return NULL; } ret = (char *)__talloc(t, len+1); - if (ret) { - va_copy(ap2, ap); - vsnprintf(ret, len+1, fmt, ap2); - va_end(ap2); - _talloc_set_name_const(ret, ret); - } + if (unlikely(!ret)) return NULL; + va_copy(ap2, ap); + vsnprintf(ret, len+1, fmt, ap2); + va_end(ap2); + + _talloc_set_name_const(ret, ret); return ret; } @@ -1219,30 +1287,22 @@ char *talloc_asprintf(const void *t, const char *fmt, ...) return ret; } +static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, + const char *fmt, va_list ap) + PRINTF_ATTRIBUTE(3,0); -/** - * Realloc @p s to append the formatted result of @p fmt and @p ap, - * and return @p s, which may have moved. Good for gradually - * accumulating output into a string buffer. Appends at the end - * of the string. - **/ -char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) +static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, + const char *fmt, va_list ap) { - int len, s_len; + ssize_t alen; va_list ap2; char c; - if (s == NULL) { - return talloc_vasprintf(NULL, fmt, ap); - } - - s_len = strlen(s); - va_copy(ap2, ap); - len = vsnprintf(&c, 1, fmt, ap2); + alen = vsnprintf(&c, 1, fmt, ap2); va_end(ap2); - if (len <= 0) { + if (alen <= 0) { /* Either the vsnprintf failed or the format resulted in * no characters being formatted. In the former case, we * ought to return NULL, in the latter we ought to return @@ -1252,17 +1312,32 @@ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) return s; } - s = talloc_realloc(NULL, s, char, s_len + len+1); + s = talloc_realloc(NULL, s, char, slen + alen + 1); if (!s) return NULL; va_copy(ap2, ap); - vsnprintf(s+s_len, len+1, fmt, ap2); + vsnprintf(s + slen, alen + 1, fmt, ap2); va_end(ap2); - _talloc_set_name_const(s, s); + _talloc_set_name_const(s, s); return s; } +/** + * Realloc @p s to append the formatted result of @p fmt and @p ap, + * and return @p s, which may have moved. Good for gradually + * accumulating output into a string buffer. Appends at the end + * of the string. + **/ +char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) +{ + if (unlikely(!s)) { + return talloc_vasprintf(NULL, fmt, ap); + } + + return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap); +} + /** * Realloc @p s to append the formatted result of @p fmt and @p ap, * and return @p s, which may have moved. Always appends at the @@ -1270,42 +1345,18 @@ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) **/ char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) { - struct talloc_chunk *tc; - int len, s_len; - va_list ap2; - char c; + size_t slen; - if (s == NULL) { + if (unlikely(!s)) { return talloc_vasprintf(NULL, fmt, ap); } - tc = talloc_chunk_from_ptr(s); - - s_len = tc->size - 1; - - va_copy(ap2, ap); - len = vsnprintf(&c, 1, fmt, ap2); - va_end(ap2); - - if (len <= 0) { - /* Either the vsnprintf failed or the format resulted in - * no characters being formatted. In the former case, we - * ought to return NULL, in the latter we ought to return - * the original string. Most current callers of this - * function expect it to never return NULL. - */ - return s; + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; } - s = talloc_realloc(NULL, s, char, s_len + len+1); - if (!s) return NULL; - - va_copy(ap2, ap); - vsnprintf(s+s_len, len+1, fmt, ap2); - va_end(ap2); - _talloc_set_name_const(s, s); - - return s; + return __talloc_vaslenprintf_append(s, slen, fmt, ap); } /* -- cgit From 0af2efcdc4cd669db2a2ee582674dc030c6371a9 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 8 Jan 2008 22:42:27 +0100 Subject: Don't shrink a talloc area if we have less than 1k to gain (This used to be commit 28a72ebd4541fb54f284da49081345e54130c75a) --- source3/lib/talloc/talloc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 4d72c0e871..6dbe21bbf1 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -787,6 +787,11 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n tc = talloc_chunk_from_ptr(ptr); + if ((size < tc->size) && ((tc->size - size) < 1024)) { + tc->size = size; + return ptr; + } + /* don't allow realloc on referenced pointers */ if (unlikely(tc->refs)) { return NULL; -- cgit From ebb21268df233933938e64e83ed315313aedd544 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 9 Jan 2008 01:34:21 +0100 Subject: Fix talloctort: move size check after referenced ptr check. Michael (This used to be commit 45b219642c529865a898625eeb0433c60b233867) --- source3/lib/talloc/talloc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 6dbe21bbf1..476d765104 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -787,16 +787,16 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n tc = talloc_chunk_from_ptr(ptr); - if ((size < tc->size) && ((tc->size - size) < 1024)) { - tc->size = size; - return ptr; - } - /* don't allow realloc on referenced pointers */ if (unlikely(tc->refs)) { return NULL; } + if ((size < tc->size) && ((tc->size - size) < 1024)) { + tc->size = size; + return ptr; + } + /* by resetting magic we catch users of the old memory */ tc->flags |= TALLOC_FLAG_FREE; -- cgit From 2e3ac4d3fe65ee72111c03a9b6fabf06f8192a69 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 9 Jan 2008 01:35:43 +0100 Subject: Add a comment. Michael (This used to be commit 3a4bf4b7c3081048f0d5491dae6610388c268c2f) --- source3/lib/talloc/talloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 476d765104..3e976bc0fc 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -792,6 +792,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n return NULL; } + /* don't shrink if we have less than 1k to gain */ if ((size < tc->size) && ((tc->size - size) < 1024)) { tc->size = size; return ptr; -- cgit From 1ed4fcb271b7885c274bd88bafed8116779d8eb6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 5 Jan 2008 18:26:54 +0100 Subject: Implement talloc_pool() A talloc pool is a chunk of memory that can be used as a context for further talloc calls. Allocations with the pool as the parent just chew from that memory by incrementing a pointer. If the talloc pool is full, then we fall back to the normal system-level malloc(3) to get memory. The use case for talloc pools is the transient memory that is used for handling a single SMB request. Incrementing a pointer will be way faster than any malloc implementation. There is a downside of this: If you use talloc_steal() to move something out of the pool, the whole pool memory is kept around until the last object inside the pool is freed. So if you talloc_free() the pool, it might happen that the memory is freed later. So don't hang anything off a talloc pool that should live long. Volker (This used to be commit 287e29d988813007eeebc0c2bef3b46ab8bedee9) --- source3/lib/talloc/talloc.c | 176 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 7 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 3e976bc0fc..178bbb97e4 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -60,6 +60,8 @@ #define TALLOC_MAGIC 0xe814ec70 #define TALLOC_FLAG_FREE 0x01 #define TALLOC_FLAG_LOOP 0x02 +#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ +#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ #define TALLOC_MAGIC_REFERENCE ((const char *)1) /* by default we abort when given a bad pointer (such as when talloc_free() is called @@ -109,6 +111,19 @@ struct talloc_chunk { const char *name; size_t size; unsigned flags; + + /* + * "pool" has dual use: + * + * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" + * marks the end of the currently allocated area. + * + * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" + * is a pointer to the struct talloc_chunk of the pool that it was + * allocated from. This way children can quickly find the pool to chew + * from. + */ + void *pool; }; /* 16 byte alignment seems to keep everyone happy */ @@ -200,12 +215,82 @@ const char *talloc_parent_name(const void *ptr) return tc? tc->name : NULL; } +/* + A pool carries an in-pool object count count in the first 16 bytes. + bytes. This is done to support talloc_steal() to a parent outside of the + pool. The count includes the pool itself, so a talloc_free() on a pool will + only destroy the pool if the count has dropped to zero. A talloc_free() of a + pool member will reduce the count, and eventually also call free(3) on the + pool memory. + + The object count is not put into "struct talloc_chunk" because it is only + relevant for talloc pools and the alignment to 16 bytes would increase the + memory footprint of each talloc chunk by those 16 bytes. +*/ + +#define TALLOC_POOL_HDR_SIZE 16 + +static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc) +{ + return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk)); +} + +/* + Allocate from a pool +*/ + +static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, + size_t size) +{ + struct talloc_chunk *pool_ctx = NULL; + size_t space_left; + struct talloc_chunk *result; + + if (parent == NULL) { + return NULL; + } + + if (parent->flags & TALLOC_FLAG_POOL) { + pool_ctx = parent; + } + else if (parent->flags & TALLOC_FLAG_POOLMEM) { + pool_ctx = (struct talloc_chunk *)parent->pool; + } + + if (pool_ctx == NULL) { + return NULL; + } + + space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size) + - ((char *)pool_ctx->pool); + + /* + * Align size to 16 bytes + */ + size = ((size + 15) & ~15); + + if (space_left < size) { + return NULL; + } + + result = (struct talloc_chunk *)pool_ctx->pool; + + pool_ctx->pool = (void *)((char *)result + size); + + result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; + result->pool = pool_ctx; + + *talloc_pool_objectcount(pool_ctx) += 1; + + return result; +} + /* Allocate a bit of memory as a child of an existing pointer */ static inline void *__talloc(const void *context, size_t size) { - struct talloc_chunk *tc; + struct talloc_chunk *tc = NULL; if (unlikely(context == NULL)) { context = null_context; @@ -215,11 +300,19 @@ static inline void *__talloc(const void *context, size_t size) return NULL; } - tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); - if (unlikely(tc == NULL)) return NULL; + if (context != NULL) { + tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), + TC_HDR_SIZE+size); + } + + if (tc == NULL) { + tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); + if (unlikely(tc == NULL)) return NULL; + tc->flags = TALLOC_MAGIC; + tc->pool = NULL; + } tc->size = size; - tc->flags = TALLOC_MAGIC; tc->destructor = NULL; tc->child = NULL; tc->name = NULL; @@ -245,6 +338,29 @@ static inline void *__talloc(const void *context, size_t size) return TC_PTR_FROM_CHUNK(tc); } +/* + * Create a talloc pool + */ + +void *talloc_pool(const void *context, size_t size) +{ + void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE); + struct talloc_chunk *tc; + + if (unlikely(result == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(result); + + tc->flags |= TALLOC_FLAG_POOL; + tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE; + + *talloc_pool_objectcount(tc) = 1; + + return result; +} + /* setup a destructor to be called on free of a pointer the destructor should return 0 on success, or -1 on failure. @@ -420,7 +536,29 @@ static inline int _talloc_free(void *ptr) } tc->flags |= TALLOC_FLAG_FREE; - free(tc); + + if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) { + struct talloc_chunk *pool; + unsigned int *pool_object_count; + + pool = (tc->flags & TALLOC_FLAG_POOL) + ? tc : (struct talloc_chunk *)tc->pool; + + pool_object_count = talloc_pool_objectcount(pool); + + if (*pool_object_count == 0) { + TALLOC_ABORT("Pool object count zero!"); + } + + *pool_object_count -= 1; + + if (*pool_object_count == 0) { + free(pool); + } + } + else { + free(tc); + } return 0; } @@ -718,6 +856,10 @@ void talloc_free_children(void *ptr) talloc_steal(new_parent, child); } } + + if (tc->flags & TALLOC_FLAG_POOL) { + tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); + } } /* @@ -769,6 +911,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n { struct talloc_chunk *tc; void *new_ptr; + bool malloced = false; /* size zero is equivalent to free() */ if (unlikely(size == 0)) { @@ -808,7 +951,23 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n free(tc); } #else - new_ptr = realloc(tc, size + TC_HDR_SIZE); + if (tc->flags & TALLOC_FLAG_POOLMEM) { + + new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); + *talloc_pool_objectcount(tc->pool) -= 1; + + if (new_ptr == NULL) { + new_ptr = malloc(TC_HDR_SIZE+size); + malloced = true; + } + + if (new_ptr) { + memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE); + } + } + else { + new_ptr = realloc(tc, size + TC_HDR_SIZE); + } #endif if (unlikely(!new_ptr)) { tc->flags &= ~TALLOC_FLAG_FREE; @@ -816,7 +975,10 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n } tc = (struct talloc_chunk *)new_ptr; - tc->flags &= ~TALLOC_FLAG_FREE; + tc->flags &= ~TALLOC_FLAG_FREE; + if (malloced) { + tc->flags &= ~TALLOC_FLAG_POOLMEM; + } if (tc->parent) { tc->parent->child = tc; } -- cgit From 4803cc5d3ce7db872bd21f6a1232f7cabc46186e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 10 Jan 2008 11:34:07 +0100 Subject: Mark talloc_pool memory for valgrind (This used to be commit d89e42f1d2faa018c584025296d6be8195cbcf20) --- source3/lib/talloc/talloc.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 178bbb97e4..ea4480286e 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -245,6 +245,7 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, struct talloc_chunk *pool_ctx = NULL; size_t space_left; struct talloc_chunk *result; + size_t chunk_size; if (parent == NULL) { return NULL; @@ -267,15 +268,19 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, /* * Align size to 16 bytes */ - size = ((size + 15) & ~15); + chunk_size = ((size + 15) & ~15); - if (space_left < size) { + if (space_left < chunk_size) { return NULL; } result = (struct talloc_chunk *)pool_ctx->pool; - pool_ctx->pool = (void *)((char *)result + size); +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(result, size); +#endif + + pool_ctx->pool = (void *)((char *)result + chunk_size); result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; result->pool = pool_ctx; @@ -358,6 +363,10 @@ void *talloc_pool(const void *context, size_t size) *talloc_pool_objectcount(tc) = 1; +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size); +#endif + return result; } @@ -859,6 +868,10 @@ void talloc_free_children(void *ptr) if (tc->flags & TALLOC_FLAG_POOL) { tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS( + tc->pool, tc->size - TALLOC_POOL_HDR_SIZE); +#endif } } -- cgit From 97a50593fe86456a72762ba4a768614de23c3f14 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 10 Jan 2008 11:35:17 +0100 Subject: talloc_free_children can only reset pool if it's empty (This used to be commit 0272b46515b4c4515d5cad8e86fab61d8e91e29e) --- source3/lib/talloc/talloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index ea4480286e..8683e361a6 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -866,7 +866,8 @@ void talloc_free_children(void *ptr) } } - if (tc->flags & TALLOC_FLAG_POOL) { + if ((tc->flags & TALLOC_FLAG_POOL) + && (*talloc_pool_objectcount(tc) == 1)) { tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) VALGRIND_MAKE_MEM_NOACCESS( -- cgit From 138954e70e18e53f1ae81bad4641380bc8ab3bd3 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 10 Jan 2008 11:35:40 +0100 Subject: Fix a c++ warning (This used to be commit ee905a085fff5410d02c3e5fa2664e989de4afd4) --- source3/lib/talloc/talloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 8683e361a6..9dcd8a2a83 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -968,7 +968,8 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n if (tc->flags & TALLOC_FLAG_POOLMEM) { new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); - *talloc_pool_objectcount(tc->pool) -= 1; + *talloc_pool_objectcount((struct talloc_chunk *) + (tc->pool)) -= 1; if (new_ptr == NULL) { new_ptr = malloc(TC_HDR_SIZE+size); -- cgit From 9ccbef219c9a4f6fe6c67a6806835659e47dd2ac Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 19 Apr 2008 16:56:44 +0200 Subject: Fix bug 5400 Thanks to Jason Mader! Volker (This used to be commit 87d8a63ce4e6dd91ea3193d0a2574520a5857be2) --- source3/lib/talloc/talloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 9dcd8a2a83..d535c3d784 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -85,8 +85,8 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else -#define likely(x) x -#define unlikely(x) x +#define likely(x) (x) +#define unlikely(x) (x) #endif /* this null_context is only used if talloc_enable_leak_report() or -- cgit From e08943f8d855b85765615b2a231fb65d5788a2a6 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Fri, 27 Jun 2008 15:51:35 +0200 Subject: Fix warnings on SuSE 9.0. The macros "[un]likely" are already defined on SuSE 9.0. Patch from Volker. (This used to be commit 30d181c92463aecd6e649330d3645d86d5a17e43) --- source3/lib/talloc/talloc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index d535c3d784..99210f3e1b 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -82,12 +82,20 @@ #if (__GNUC__ >= 3) /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 as its first argument */ +#ifndef likely #define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely #define unlikely(x) __builtin_expect(!!(x), 0) +#endif #else +#ifndef likely #define likely(x) (x) +#endif +#ifndef unlikely #define unlikely(x) (x) #endif +#endif /* this null_context is only used if talloc_enable_leak_report() or talloc_enable_leak_report_full() is called, otherwise it remains -- cgit From 375ca336fecbe33b132fd1abb8df9b7af44ede76 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 14 Sep 2008 19:12:39 +0200 Subject: r26511: Janitorial: Fix a warning for the 'printf' attribute on gendb_search_v While at it, also add a PRINTF_ATTRIBUTE for talloc_vasprintf. (partialy cherry picked from commit 5b3a8c8ae195e6a98357a407a0699493f54a8b79) metze (This used to be commit 0073e41a0157ec43b944372671299b3e8a2b3cd5) --- source3/lib/talloc/talloc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 99210f3e1b..5691a81a9a 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1436,13 +1436,15 @@ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) #endif #endif +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) -{ +{ int len; char *ret; va_list ap2; char c; - + /* this call looks strange, but it makes it work on older solaris boxes */ va_copy(ap2, ap); len = vsnprintf(&c, 1, fmt, ap2); @@ -1467,6 +1469,7 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) 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; -- cgit From b725e9e586a075636fc96212d4c8528c9072e6d6 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Mon, 17 Dec 2007 20:18:02 +0100 Subject: r26514: Revert the talloc.c part of r26511, as talloc.h already takes care of thois. Thanks to metze for pointing this out (cherry picked from commit 4a5e1047fff0620aa534b147ac7e0bd0416a8fe7) (This used to be commit 523cc93f89d00ed5a49fd033988e7221bd2ed902) --- source3/lib/talloc/talloc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'source3/lib/talloc/talloc.c') diff --git a/source3/lib/talloc/talloc.c b/source3/lib/talloc/talloc.c index 5691a81a9a..1f7e52439f 100644 --- a/source3/lib/talloc/talloc.c +++ b/source3/lib/talloc/talloc.c @@ -1436,8 +1436,6 @@ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) #endif #endif -char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); - char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) { int len; @@ -1469,7 +1467,6 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) 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; -- cgit