From 37ebf499ec5804f456d48ea3a46770a91e9dac7c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 22 Sep 2012 16:15:47 -0400 Subject: [PATCH 01/47] Add memory limiting capability to talloc By calling talloc_set_memlimit() we can now set a max memory limit for a whole talloc hierarchy. ANy attempt to allocate memory beyond the max allowed for the whole hierarchy wil cause an allocation failure. Stealing memory correctly accounts for used memory in the old and the new hierarchy but exceeding the memory limit in the new parent will not cause a failure. (cherry picked from commit a33a78c302fde61fdb7a6e71669f19be2cf5c836) --- lib/talloc/ABI/pytalloc-util-2.0.8.sigs | 6 + lib/talloc/ABI/talloc-2.0.8.sigs | 63 ++++++++ lib/talloc/talloc.c | 277 +++++++++++++++++++++++++++----- lib/talloc/talloc.h | 19 +++ lib/talloc/wscript | 2 +- 5 files changed, 327 insertions(+), 40 deletions(-) create mode 100644 lib/talloc/ABI/pytalloc-util-2.0.8.sigs create mode 100644 lib/talloc/ABI/talloc-2.0.8.sigs diff --git a/lib/talloc/ABI/pytalloc-util-2.0.8.sigs b/lib/talloc/ABI/pytalloc-util-2.0.8.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.0.8.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/talloc-2.0.8.sigs b/lib/talloc/ABI/talloc-2.0.8.sigs new file mode 100644 index 0000000..15a9e95 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.8.sigs @@ -0,0 +1,63 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 18ee548..afc44b3 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -71,6 +71,7 @@ #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 @@ -221,12 +222,50 @@ static struct { TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size); \ } while (0) +#define TALLOC_MEMLIMIT_CHECK(limit, size) do { \ + struct talloc_memlimit *l; \ + for (l = limit; l != NULL; l = l->upper) { \ + if (l->max_size != 0 && \ + ((l->max_size <= l->cur_size) || \ + (l->max_size - l->cur_size < TC_HDR_SIZE+size))) { \ + errno = ENOMEM; \ + return NULL; \ + } \ + } \ +} while(0) + +#define TALLOC_MEMLIMIT_UPDATE(limit, o_size, n_size) do { \ + struct talloc_memlimit *l; \ + ssize_t d; \ + if (o_size == 0) { \ + d = n_size + TC_HDR_SIZE; \ + } else { \ + d = n_size - o_size; \ + } \ + for (l = limit; l != NULL; l = l->upper) { \ + ssize_t new_size = l->cur_size + d; \ + if (new_size < 0) { \ + talloc_abort("cur_size memlimit counter not correct!"); \ + errno = EINVAL; \ + return NULL; \ + } \ + l->cur_size = new_size; \ + } \ +} while(0) + struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; void *ptr; const char *location; }; +struct talloc_memlimit { + struct talloc_chunk *parent; + struct talloc_memlimit *upper; + size_t max_size; + size_t cur_size; +}; + typedef int (*talloc_destructor_t)(void *); struct talloc_chunk { @@ -239,6 +278,15 @@ struct talloc_chunk { unsigned flags; /* + * limit semantics: + * if 'limit' is set it means all *new* children of the context will + * be limited to a total aggregate size ox max_size for memory + * allocations. + * cur_size is used to kep track of the current use + */ + struct talloc_memlimit *limit; + + /* * "pool" has dual use: * * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" @@ -543,6 +591,7 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, static inline void *__talloc(const void *context, size_t size) { struct talloc_chunk *tc = NULL; + struct talloc_memlimit *limit = NULL; if (unlikely(context == NULL)) { context = null_context; @@ -553,8 +602,15 @@ static inline void *__talloc(const void *context, size_t size) } if (context != NULL) { - tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), - TC_HDR_SIZE+size); + struct talloc_chunk *ptc = talloc_chunk_from_ptr(context); + + if (ptc->limit != NULL) { + limit = ptc->limit; + } + + TALLOC_MEMLIMIT_CHECK(limit, (TC_HDR_SIZE+size)); + + tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size); } if (tc == NULL) { @@ -564,6 +620,15 @@ static inline void *__talloc(const void *context, size_t size) tc->pool = NULL; } + if (limit != NULL) { + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + l->cur_size += TC_HDR_SIZE+size; + } + } + + tc->limit = limit; tc->size = size; tc->destructor = NULL; tc->child = NULL; @@ -852,6 +917,29 @@ static inline int _talloc_free_internal(void *ptr, const char *location) tc->flags |= TALLOC_FLAG_FREE; + /* + * If we are part of a memory limited context hierarchy + * we need to subtract the memory used from the counters + */ + if (tc->limit) { + struct talloc_memlimit *l; + + for (l = tc->limit; l != NULL; l = l->upper) { + if (l->cur_size >= tc->size+TC_HDR_SIZE) { + l->cur_size -= tc->size+TC_HDR_SIZE; + } else { + talloc_abort("cur_size memlimit counter not correct!"); + return 0; + } + } + + if (tc->limit->parent == tc) { + free(tc->limit); + } + + tc->limit = NULL; + } + /* we mark the freed memory with where we called the free * from. This means on a double free error we can report where * the first free came from @@ -880,6 +968,10 @@ static inline int _talloc_free_internal(void *ptr, const char *location) return 0; } +static size_t _talloc_total_limit_size(const void *ptr, + struct talloc_memlimit *old_limit, + struct talloc_memlimit *new_limit); + /* move a lump of memory from one talloc context to another return the ptr on success, or NULL if it could not be transferred. @@ -888,6 +980,7 @@ static inline int _talloc_free_internal(void *ptr, const char *location) static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) { struct talloc_chunk *tc, *new_tc; + size_t ctx_size = 0; if (unlikely(!ptr)) { return NULL; @@ -899,6 +992,19 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) tc = talloc_chunk_from_ptr(ptr); + if (tc->limit != NULL) { + + ctx_size = _talloc_total_limit_size(ptr, NULL, NULL); + + TALLOC_MEMLIMIT_UPDATE(tc->limit->upper, ctx_size, 0); + + if (tc->limit->parent == tc) { + tc->limit->upper = NULL; + } else { + tc->limit = NULL; + } + } + if (unlikely(new_ctx == NULL)) { if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); @@ -909,7 +1015,7 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) 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); } @@ -935,6 +1041,19 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) if (new_tc->child) new_tc->child->parent = NULL; _TLIST_ADD(new_tc->child, tc); + if (tc->limit || new_tc->limit) { + ctx_size = _talloc_total_limit_size(ptr, tc->limit, + new_tc->limit); + } + + if (new_tc->limit) { + struct talloc_memlimit *l; + + for (l = new_tc->limit; l != NULL; l = l->upper) { + l->cur_size += ctx_size; + } + } + return discard_const_p(void, ptr); } @@ -1068,7 +1187,7 @@ _PUBLIC_ int talloc_unlink(const void *context, void *ptr) if (tc_c != talloc_parent_chunk(ptr)) { return -1; } - + tc_p = talloc_chunk_from_ptr(ptr); if (tc_p->refs == NULL) { @@ -1411,6 +1530,10 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons return NULL; } + if (tc->limit && (size - tc->size > 0)) { + TALLOC_MEMLIMIT_CHECK(tc->limit, (size - tc->size)); + } + /* handle realloc inside a talloc_pool */ if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { pool_tc = (union talloc_pool_chunk *)tc->pool; @@ -1418,7 +1541,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons #if (ALWAYS_REALLOC == 0) /* don't shrink if we have less than 1k to gain */ - if (size < tc->size) { + if (size < tc->size && tc->limit == NULL) { if (pool_tc) { void *next_tc = tc_next_chunk(tc); TC_INVALIDATE_SHRINK_CHUNK(tc, size); @@ -1526,6 +1649,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (new_chunk_size == old_chunk_size) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; + TALLOC_MEMLIMIT_UPDATE(tc->limit, tc->size, size); tc->size = size; return ptr; } @@ -1541,6 +1665,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (space_left >= space_needed) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; + TALLOC_MEMLIMIT_UPDATE(tc->limit, tc->size, size); tc->size = size; pool_tc->hdr.c.pool = tc_next_chunk(tc); return ptr; @@ -1589,6 +1714,7 @@ got_new_ptr: tc->next->prev = tc; } + TALLOC_MEMLIMIT_UPDATE(tc->limit, tc->size, size); tc->size = size; _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); @@ -1607,10 +1733,16 @@ _PUBLIC_ void *_talloc_move(const void *new_ctx, const void *_pptr) return ret; } -/* - return the total size of a talloc pool (subtree) -*/ -_PUBLIC_ size_t talloc_total_size(const void *ptr) +enum talloc_mem_count_type { + TOTAL_MEM_SIZE, + TOTAL_MEM_BLOCKS, + TOTAL_MEM_LIMIT, +}; + +static size_t _talloc_total_mem_internal(const void *ptr, + enum talloc_mem_count_type type, + struct talloc_memlimit *old_limit, + struct talloc_memlimit *new_limit) { size_t total = 0; struct talloc_chunk *c, *tc; @@ -1624,17 +1756,50 @@ _PUBLIC_ size_t talloc_total_size(const void *ptr) tc = talloc_chunk_from_ptr(ptr); + if (old_limit || new_limit) { + if (tc->limit && tc->limit->upper == old_limit) { + tc->limit->upper = new_limit; + } + } + + /* optimize in the memlimits case */ + if (type == TOTAL_MEM_LIMIT && + tc->limit != NULL && + tc->limit != old_limit && + tc->limit->parent == tc) { + return tc->limit->cur_size; + } + if (tc->flags & TALLOC_FLAG_LOOP) { return 0; } tc->flags |= TALLOC_FLAG_LOOP; - if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { - total = tc->size; + if (old_limit || new_limit) { + if (old_limit == tc->limit) { + tc->limit = new_limit; + } } - for (c=tc->child;c;c=c->next) { - total += talloc_total_size(TC_PTR_FROM_CHUNK(c)); + + switch (type) { + case TOTAL_MEM_SIZE: + if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { + total = tc->size; + } + break; + case TOTAL_MEM_BLOCKS: + total++; + break; + case TOTAL_MEM_LIMIT: + if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { + total = tc->size + TC_HDR_SIZE; + } + break; + } + for (c = tc->child; c; c = c->next) { + total += _talloc_total_mem_internal(TC_PTR_FROM_CHUNK(c), type, + old_limit, new_limit); } tc->flags &= ~TALLOC_FLAG_LOOP; @@ -1643,36 +1808,19 @@ _PUBLIC_ size_t talloc_total_size(const void *ptr) } /* + return the total size of a talloc pool (subtree) +*/ +_PUBLIC_ size_t talloc_total_size(const void *ptr) +{ + return _talloc_total_mem_internal(ptr, TOTAL_MEM_SIZE, NULL, NULL); +} + +/* return the total number of blocks in a talloc pool (subtree) */ _PUBLIC_ size_t talloc_total_blocks(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++; - 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 _talloc_total_mem_internal(ptr, TOTAL_MEM_BLOCKS, NULL, NULL); } /* @@ -1734,6 +1882,7 @@ _PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, 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); + struct talloc_chunk *tc; FILE *f = (FILE *)_f; if (is_ref) { @@ -1741,6 +1890,16 @@ static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_ return; } + tc = talloc_chunk_from_ptr(ptr); + if (tc->limit && tc->limit->parent == tc) { + fprintf(f, "%*s%-30s is a memlimit context" + " (max_size = %lu bytes, cur_size = %lu bytes)\n", + depth*4, "", + name, + (unsigned long)tc->limit->max_size, + (unsigned long)tc->limit->cur_size); + } + if (depth == 0) { fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", (max_depth < 0 ? "full " :""), name, @@ -2359,3 +2518,43 @@ _PUBLIC_ int talloc_is_parent(const void *context, const void *ptr) { return _talloc_is_parent(context, ptr, TALLOC_MAX_DEPTH); } + +/* + return the total size of memory used by this context and all children +*/ +static size_t _talloc_total_limit_size(const void *ptr, + struct talloc_memlimit *old_limit, + struct talloc_memlimit *new_limit) +{ + return _talloc_total_mem_internal(ptr, TOTAL_MEM_LIMIT, + old_limit, new_limit); +} + +_PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx); + struct talloc_memlimit *orig_limit; + struct talloc_memlimit *limit = NULL; + + if (tc->limit && tc->limit->parent == tc) { + tc->limit->max_size = max_size; + return 0; + } + orig_limit = tc->limit; + + limit = malloc(sizeof(struct talloc_memlimit)); + if (limit == NULL) { + return 1; + } + limit->parent = tc; + limit->max_size = max_size; + limit->cur_size = _talloc_total_limit_size(ctx, tc->limit, limit); + + if (orig_limit) { + limit->upper = orig_limit; + } else { + limit->upper = NULL; + } + + return 0; +} diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index e48dc09..f3cbcd0 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -1842,6 +1842,25 @@ void talloc_set_log_fn(void (*log_fn)(const char *message)); */ void talloc_set_log_stderr(void); +/** + * @brief Set a max memory limit for the current context hierarchy + * This affects all children of this context and constrain any + * allocation in the hierarchy to never exceed the limit set. + * The limit can be removed by setting 0 (unlimited) as the + * max_size by calling the funciton again on the sam context. + * Memory limits can also be nested, meaning a hild can have + * a stricter memory limit than a parent. + * Memory limits are enforced only at memory allocation time. + * Stealing a context into a 'limited' hierarchy properly + * updates memory usage but does *not* cause failure if the + * move causes the new parent to exceed its limits. However + * any further allocation on that hierarchy will then fail. + * + * @param[in] ctx The talloc context to set the limit on + * @param[in] max_size The (new) max_size + */ +int talloc_set_memlimit(const void *ctx, size_t max_size); + /* @} ******************************************************************/ #if TALLOC_DEPRECATED diff --git a/lib/talloc/wscript b/lib/talloc/wscript index a97b5d0b..bd7708e 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'talloc' -VERSION = '2.0.7' +VERSION = '2.0.8' blddir = 'bin' -- 1.9.1 From 2565208ae14599e7738d4c164f557ff25e18ebfd Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 22 Sep 2012 16:35:21 -0400 Subject: [PATCH 02/47] Add tests for talloc_memlimit Autobuild-User(master): Simo Sorce Autobuild-Date(master): Fri Oct 5 07:36:38 CEST 2012 on sn-devel-104 (cherry picked from commit 7d7e33c624875a9694fcebdde942147ac3bf5f74) --- lib/talloc/testsuite.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index eaab9d7..d456cbb 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -1355,6 +1355,175 @@ static bool test_free_children(void) return true; } +static bool test_memlimit(void) +{ + void *root; + char *l1, *l2, *l3, *l4, *l5, *t; + + printf("test: memlimit\n# MEMORY LIMITS\n"); + + printf("==== talloc_new(NULL)\n"); + root = talloc_new(NULL); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(root, 2048)\n"); + l1 = talloc_size(root, 2048); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_free(l1)\n"); + talloc_free(l1); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(root, level 1)\n"); + l1 = talloc_strdup(root, "level 1"); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l1, 2048)\n"); + torture_assert("memlimit", talloc_set_memlimit(l1, 2048) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(root, 2048)\n"); + l2 = talloc_size(l1, 2048); + torture_assert("memlimit", l2 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l1, level 2)\n"); + l2 = talloc_strdup(l1, "level 2"); + torture_assert("memlimit", l2 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_free(l2)\n"); + talloc_free(l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(NULL, 2048)\n"); + l2 = talloc_size(NULL, 2048); + + talloc_report_full(root, stdout); + + printf("==== talloc_steal(l1, l2)\n"); + talloc_steal(l1, l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l2, level 3)\n"); + l3 = talloc_strdup(l2, "level 3"); + torture_assert("memlimit", l3 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_free(l2)\n"); + talloc_free(l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(NULL, level 2)\n"); + l2 = talloc_strdup(NULL, "level 2"); + talloc_steal(l1, l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l2, level 3)\n"); + l3 = talloc_strdup(l2, "level 3"); + torture_assert("memlimit", l3 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l3, 1024)\n"); + torture_assert("memlimit", talloc_set_memlimit(l3, 1024) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l3, level 4)\n"); + l4 = talloc_strdup(l3, "level 4"); + torture_assert("memlimit", l4 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l4, 512)\n"); + torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l4, level 5)\n"); + l5 = talloc_strdup(l4, "level 5"); + torture_assert("memlimit", l5 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_realloc(NULL, l5, char, 600)\n"); + t = talloc_realloc(NULL, l5, char, 600); + torture_assert("memlimit", t == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_realloc(NULL, l5, char, 5)\n"); + l5 = talloc_realloc(NULL, l5, char, 5); + torture_assert("memlimit", l5 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l3, level 4)\n"); + l4 = talloc_strdup(l3, "level 4"); + torture_assert("memlimit", l4 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l4, 512)\n"); + torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l4, level 5)\n"); + l5 = talloc_strdup(l4, "level 5"); + torture_assert("memlimit", l5 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== Make new temp context and steal l5\n"); + t = talloc_new(root); + talloc_steal(t, l5); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(t, 2048)\n"); + l1 = talloc_size(t, 2048); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + talloc_free(root); + + printf("success: memlimit\n"); + + return true; +} static void test_reset(void) { @@ -1416,6 +1585,9 @@ bool torture_local_talloc(struct torture_context *tctx) ret &= test_rusty(); test_reset(); ret &= test_free_children(); + test_reset(); + ret &= test_memlimit(); + if (ret) { test_reset(); -- 1.9.1 From fb8725acffc717b4aff749143de8653899454765 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 5 Oct 2012 10:32:32 -0400 Subject: [PATCH 03/47] talloc: Convert error cecking macros into fns This will avoid 'surprise returns' and makes the code cleare to readers. These macros were complex enough to warrant a full function anyway not just for readability but also for debuggability. Thanks David for pointing out this issue. Autobuild-User(master): Simo Sorce Autobuild-Date(master): Fri Oct 5 23:24:17 CEST 2012 on sn-devel-104 (cherry picked from commit 36ea39edf8dd9ede756debaf9632f3ded2a51abb) --- lib/talloc/talloc.c | 111 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index afc44b3..3e33fc0 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -222,37 +222,6 @@ static struct { TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size); \ } while (0) -#define TALLOC_MEMLIMIT_CHECK(limit, size) do { \ - struct talloc_memlimit *l; \ - for (l = limit; l != NULL; l = l->upper) { \ - if (l->max_size != 0 && \ - ((l->max_size <= l->cur_size) || \ - (l->max_size - l->cur_size < TC_HDR_SIZE+size))) { \ - errno = ENOMEM; \ - return NULL; \ - } \ - } \ -} while(0) - -#define TALLOC_MEMLIMIT_UPDATE(limit, o_size, n_size) do { \ - struct talloc_memlimit *l; \ - ssize_t d; \ - if (o_size == 0) { \ - d = n_size + TC_HDR_SIZE; \ - } else { \ - d = n_size - o_size; \ - } \ - for (l = limit; l != NULL; l = l->upper) { \ - ssize_t new_size = l->cur_size + d; \ - if (new_size < 0) { \ - talloc_abort("cur_size memlimit counter not correct!"); \ - errno = EINVAL; \ - return NULL; \ - } \ - l->cur_size = new_size; \ - } \ -} while(0) - struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; void *ptr; @@ -266,6 +235,10 @@ struct talloc_memlimit { size_t cur_size; }; +static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); +static bool talloc_memlimit_update(struct talloc_memlimit *limit, + size_t old_size, size_t new_size); + typedef int (*talloc_destructor_t)(void *); struct talloc_chunk { @@ -608,7 +581,10 @@ static inline void *__talloc(const void *context, size_t size) limit = ptc->limit; } - TALLOC_MEMLIMIT_CHECK(limit, (TC_HDR_SIZE+size)); + if (!talloc_memlimit_check(limit, (TC_HDR_SIZE+size))) { + errno = ENOMEM; + return NULL; + } tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size); } @@ -996,7 +972,11 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) ctx_size = _talloc_total_limit_size(ptr, NULL, NULL); - TALLOC_MEMLIMIT_UPDATE(tc->limit->upper, ctx_size, 0); + if (!talloc_memlimit_update(tc->limit->upper, ctx_size, 0)) { + talloc_abort("cur_size memlimit counter not correct!"); + errno = EINVAL; + return NULL; + } if (tc->limit->parent == tc) { tc->limit->upper = NULL; @@ -1531,7 +1511,10 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons } if (tc->limit && (size - tc->size > 0)) { - TALLOC_MEMLIMIT_CHECK(tc->limit, (size - tc->size)); + if (!talloc_memlimit_check(tc->limit, (size - tc->size))) { + errno = ENOMEM; + return NULL; + } } /* handle realloc inside a talloc_pool */ @@ -1649,7 +1632,14 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (new_chunk_size == old_chunk_size) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; - TALLOC_MEMLIMIT_UPDATE(tc->limit, tc->size, size); + if (!talloc_memlimit_update(tc->limit, + tc->size, size)) { + talloc_abort("cur_size memlimit counter not" + " correct!"); + errno = EINVAL; + return NULL; + } + tc->size = size; return ptr; } @@ -1665,7 +1655,13 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (space_left >= space_needed) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; - TALLOC_MEMLIMIT_UPDATE(tc->limit, tc->size, size); + if (!talloc_memlimit_update(tc->limit, + tc->size, size)) { + talloc_abort("cur_size memlimit " + "counter not correct!"); + errno = EINVAL; + return NULL; + } tc->size = size; pool_tc->hdr.c.pool = tc_next_chunk(tc); return ptr; @@ -1714,7 +1710,11 @@ got_new_ptr: tc->next->prev = tc; } - TALLOC_MEMLIMIT_UPDATE(tc->limit, tc->size, size); + if (!talloc_memlimit_update(tc->limit, tc->size, size)) { + talloc_abort("cur_size memlimit counter not correct!"); + errno = EINVAL; + return NULL; + } tc->size = size; _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); @@ -2530,6 +2530,43 @@ static size_t _talloc_total_limit_size(const void *ptr, old_limit, new_limit); } +static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) +{ + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + if (l->max_size != 0 && + ((l->max_size <= l->cur_size) || + (l->max_size - l->cur_size < TC_HDR_SIZE+size))) { + return false; + } + } + + return true; +} + +static bool talloc_memlimit_update(struct talloc_memlimit *limit, + size_t old_size, size_t new_size) +{ + struct talloc_memlimit *l; + ssize_t d; + + if (old_size == 0) { + d = new_size + TC_HDR_SIZE; + } else { + d = new_size - old_size; + } + for (l = limit; l != NULL; l = l->upper) { + ssize_t new_cur_size = l->cur_size + d; + if (new_cur_size < 0) { + return false; + } + l->cur_size = new_cur_size; + } + + return true; +} + _PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx); -- 1.9.1 From 3d2b6ff0f345318f2ab5ae4c263c2e72016c77c6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 15 Apr 2013 21:44:38 +0200 Subject: [PATCH 04/47] talloc: Fix nonblank line endings Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit d3928b0c8af01f7751191b81a72590ca35751a8c) --- lib/talloc/talloc.c | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 3e33fc0..d0c81d3 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1,4 +1,4 @@ -/* +/* Samba Unix SMB/CIFS implementation. Samba trivial allocation library - new interface @@ -7,11 +7,11 @@ 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 @@ -74,7 +74,7 @@ #define TALLOC_MAGIC_REFERENCE ((const char *)1) -/* by default we abort when given a bad pointer (such as when talloc_free() is called +/* 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() @@ -367,7 +367,7 @@ 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 (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { + if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) { talloc_abort_magic(tc->flags & (~0xF)); return NULL; @@ -558,7 +558,7 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, return result; } -/* +/* Allocate a bit of memory as a child of an existing pointer */ static inline void *__talloc(const void *context, size_t size) @@ -675,7 +675,7 @@ _PUBLIC_ void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) } /* - increase the reference count on a piece of memory. + increase the reference count on a piece of memory. */ _PUBLIC_ int talloc_increase_ref_count(const void *ptr) { @@ -698,7 +698,7 @@ static int talloc_reference_destructor(struct talloc_reference_handle *handle) } /* - more efficient way to add a name to a pointer - the name must point to a + 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) @@ -728,8 +728,8 @@ static inline void *_talloc_named_const(const void *context, size_t size, const 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 + + 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 */ @@ -818,7 +818,7 @@ static inline void _talloc_free_children_internal(struct talloc_chunk *tc, void *ptr, const char *location); -/* +/* internal talloc_free call */ static inline int _talloc_free_internal(void *ptr, const char *location) @@ -918,8 +918,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location) /* we mark the freed memory with where we called the free * from. This means on a double free error we can report where - * the first free came from - */ + * the first free came from + */ tc->name = location; if (tc->flags & TALLOC_FLAG_POOL) { @@ -948,7 +948,7 @@ static size_t _talloc_total_limit_size(const void *ptr, struct talloc_memlimit *old_limit, struct talloc_memlimit *new_limit); -/* +/* 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. @@ -1037,7 +1037,7 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) return discard_const_p(void, ptr); } -/* +/* 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. @@ -1049,9 +1049,9 @@ _PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const cha if (unlikely(ptr == NULL)) { return NULL; } - + tc = talloc_chunk_from_ptr(ptr); - + if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) { struct talloc_reference_handle *h; @@ -1071,11 +1071,11 @@ _PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const cha talloc_log("WARNING: stealing into talloc child at %s\n", location); } #endif - + return _talloc_steal_internal(new_ctx, ptr); } -/* +/* this is like a talloc_steal(), but you must supply the old parent. This resolves the ambiguity in a talloc_steal() which is called on a context that has more than one parent (via references) @@ -1103,7 +1103,7 @@ _PUBLIC_ void *talloc_reparent(const void *old_parent, const void *new_parent, c } return discard_const_p(void, ptr); } - } + } /* it wasn't a parent */ return NULL; @@ -1403,7 +1403,7 @@ _PUBLIC_ void talloc_free_children(void *ptr) } } -/* +/* Allocate a bit of memory as a child of an existing pointer */ _PUBLIC_ void *_talloc(const void *context, size_t size) @@ -1429,8 +1429,8 @@ _PUBLIC_ void *talloc_named_const(const void *context, size_t size, const char * return _talloc_named_const(context, size, name); } -/* - free a talloc pointer. This also frees all child pointers of this +/* + 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 @@ -1444,9 +1444,9 @@ _PUBLIC_ int _talloc_free(void *ptr, const char *location) if (unlikely(ptr == NULL)) { return -1; } - + tc = talloc_chunk_from_ptr(ptr); - + if (unlikely(tc->refs != NULL)) { struct talloc_reference_handle *h; @@ -1466,7 +1466,7 @@ _PUBLIC_ int _talloc_free(void *ptr, const char *location) } return -1; } - + return _talloc_free_internal(ptr, location); } @@ -1686,9 +1686,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons } got_new_ptr: #endif - if (unlikely(!new_ptr)) { - tc->flags &= ~TALLOC_FLAG_FREE; - return NULL; + if (unlikely(!new_ptr)) { + tc->flags &= ~TALLOC_FLAG_FREE; + return NULL; } tc = (struct talloc_chunk *)new_ptr; @@ -1901,14 +1901,14 @@ static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_ } if (depth == 0) { - fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", + 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) %p\n", + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", depth*4, "", name, (unsigned long)talloc_total_size(ptr), @@ -2047,8 +2047,8 @@ _PUBLIC_ void talloc_enable_leak_report_full(void) atexit(talloc_report_null_full); } -/* - talloc and zero memory. +/* + talloc and zero memory. */ _PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name) { @@ -2062,7 +2062,7 @@ _PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name) } /* - memdup with a talloc. + memdup with a talloc. */ _PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) { -- 1.9.1 From 98903cfc0d5a40bb82e2983649198693ea83ccd7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 15 Apr 2013 22:11:44 +0200 Subject: [PATCH 05/47] talloc: Avoid some "else" by doing early returns Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit ccf33dd0547f32104041c8611626f3e02e22cbe9) --- lib/talloc/talloc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index d0c81d3..011e8f3 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -935,12 +935,16 @@ static inline int _talloc_free_internal(void *ptr, const char *location) TC_INVALIDATE_FULL_CHUNK(tc); free(tc); } - } else if (tc->flags & TALLOC_FLAG_POOLMEM) { + return 0; + } + + if (tc->flags & TALLOC_FLAG_POOLMEM) { _talloc_free_poolmem(tc, location); - } else { - TC_INVALIDATE_FULL_CHUNK(tc); - free(tc); + return 0; } + + TC_INVALIDATE_FULL_CHUNK(tc); + free(tc); return 0; } -- 1.9.1 From 08c6caffb10eea50d4dc55e41ffc94e6289c4d03 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 15 Apr 2013 22:12:50 +0200 Subject: [PATCH 06/47] talloc: Do an early return Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit a796e48b1dfe96b194f3a3a0d70e25c3ab92690d) --- lib/talloc/talloc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 011e8f3..0078b07 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -931,10 +931,13 @@ static inline int _talloc_free_internal(void *ptr, const char *location) } pool->hdr.object_count--; - if (unlikely(pool->hdr.object_count == 0)) { - TC_INVALIDATE_FULL_CHUNK(tc); - free(tc); + + if (likely(pool->hdr.object_count != 0)) { + return 0; } + + TC_INVALIDATE_FULL_CHUNK(tc); + free(tc); return 0; } -- 1.9.1 From aaa56eda40f31106443b86095365a1343d8659ba Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 15 Apr 2013 22:19:25 +0200 Subject: [PATCH 07/47] talloc: Simplify _talloc_free_poolmem a bit Early returns are easier to understand than "else if" Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Apr 18 22:50:42 CEST 2013 on sn-devel-104 (cherry picked from commit 79fe1381a3a78ad2316343fc8c1c27360b46ebbf) --- lib/talloc/talloc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 0078b07..885d700 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -794,7 +794,10 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, */ pool->hdr.c.pool = tc_pool_first_chunk(pool); tc_invalidate_pool(pool); - } else if (unlikely(pool->hdr.object_count == 0)) { + return; + } + + if (unlikely(pool->hdr.object_count == 0)) { /* * we mark the freed memory with where we called the free * from. This means on a double free error we can report where @@ -804,14 +807,23 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, TC_INVALIDATE_FULL_CHUNK(&pool->hdr.c); free(pool); - } else if (pool->hdr.c.pool == next_tc) { + return; + } + + if (pool->hdr.c.pool == next_tc) { /* * if pool->pool still points to end of * 'tc' (which is stored in the 'next_tc' variable), * we can reclaim the memory of 'tc'. */ pool->hdr.c.pool = tc; + return; } + + /* + * Do nothing. The memory is just "wasted", waiting for the pool + * itself to be freed. + */ } static inline void _talloc_free_children_internal(struct talloc_chunk *tc, -- 1.9.1 From f17aa94645dba9e3b1446cd91ecbd805cd35524e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 May 2013 14:15:35 +0200 Subject: [PATCH 08/47] talloc: only provide the --enable-talloc-compat1 in standalone build The compat library is already only built in standalone build, so we need the configure option also only in the standalone build. Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam (cherry picked from commit 8a878ec74bd24180aa73cfb39ff4a6c3e72d9d0b) --- lib/talloc/wscript | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/talloc/wscript b/lib/talloc/wscript index bd7708e..ecc5e24 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -27,10 +27,10 @@ def set_options(opt): opt.BUILTIN_DEFAULT('replace') opt.PRIVATE_EXTENSION_DEFAULT('talloc', noextension='talloc') opt.RECURSE('lib/replace') - opt.add_option('--enable-talloc-compat1', - help=("Build talloc 1.x.x compat library [False]"), - action="store_true", dest='TALLOC_COMPAT1', default=False) if opt.IN_LAUNCH_DIR(): + opt.add_option('--enable-talloc-compat1', + help=("Build talloc 1.x.x compat library [False]"), + action="store_true", dest='TALLOC_COMPAT1', default=False) opt.add_option('--disable-python', help=("disable the pytalloc module"), action="store_true", dest='disable_python', default=False) @@ -51,7 +51,9 @@ def configure(conf): implied_deps='talloc replace'): conf.define('USING_SYSTEM_PYTALLOC_UTIL', 1) - conf.env.TALLOC_COMPAT1 = Options.options.TALLOC_COMPAT1 + conf.env.TALLOC_COMPAT1 = False + if conf.env.standalone_talloc: + conf.env.TALLOC_COMPAT1 = Options.options.TALLOC_COMPAT1 conf.CHECK_XSLTPROC_MANPAGES() -- 1.9.1 From 62d6944515c19e99d6b4e8a956d4db1aea85d67a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 20 May 2013 14:26:08 +0200 Subject: [PATCH 09/47] talloc: Fix a typo Signed-off-by: Volker Lendecke Reviewed-by: Kai Blin Autobuild-User(master): Kai Blin Autobuild-Date(master): Mon May 20 18:48:49 CEST 2013 on sn-devel-104 (cherry picked from commit d7708fd360c1fa1e3111fd4df266b52c96cca196) --- lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 885d700..76f0aee 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -255,7 +255,7 @@ struct talloc_chunk { * if 'limit' is set it means all *new* children of the context will * be limited to a total aggregate size ox max_size for memory * allocations. - * cur_size is used to kep track of the current use + * cur_size is used to keep track of the current use */ struct talloc_memlimit *limit; -- 1.9.1 From 3bf9b642a72c2a271db96f51ee1a1139a2b1273a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:36:23 -0700 Subject: [PATCH 10/47] Start to fix talloc memlimits with talloc pools. Add the functions: talloc_memlimit_grow(), talloc_memlimit_shrink(), talloc_memlimit_update_on_free(). as replacements for talloc_memlimit_update(). The interface to talloc_memlimit_update() is very hard to understand and use. The above functions are (to me) much clearer. The goal of these changes is to only update the memlimits on malloc/free/realloc, not on every pool allocation. That way we only count pool creation as allocation from any imposed limits, not allocation from an already created pool. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit fe790f6cbc9b888a8d613cfb515f0d0c76daad47) --- lib/talloc/talloc.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 76f0aee..067d46f 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -238,6 +238,11 @@ struct talloc_memlimit { static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); static bool talloc_memlimit_update(struct talloc_memlimit *limit, size_t old_size, size_t new_size); +static void talloc_memlimit_grow(struct talloc_memlimit *limit, + size_t size); +static void talloc_memlimit_shrink(struct talloc_memlimit *limit, + size_t size); +static void talloc_memlimit_update_on_free(struct talloc_chunk *tc); typedef int (*talloc_destructor_t)(void *); @@ -2564,6 +2569,73 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) return true; } +/* + Update memory limits when freeing a talloc_chunk. +*/ +static void talloc_memlimit_update_on_free(struct talloc_chunk *tc) +{ + if (!tc->limit) { + return; + } + + /* + * Pool entries don't count. Only the pools + * themselves are counted as part of the memory + * limits. + */ + if (tc->flags & TALLOC_FLAG_POOLMEM) { + return; + } + + /* + * If we are part of a memory limited context hierarchy + * we need to subtract the memory used from the counters + */ + + talloc_memlimit_shrink(tc->limit, tc->size+TC_HDR_SIZE); + + if (tc->limit->parent == tc) { + free(tc->limit); + } + + tc->limit = NULL; +} + +/* + Increase memory limit accounting after a malloc/realloc. +*/ +static void talloc_memlimit_grow(struct talloc_memlimit *limit, + size_t size) +{ + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + size_t new_cur_size = l->cur_size + size; + if (new_cur_size < l->cur_size) { + talloc_abort("logic error in talloc_memlimit_grow\n"); + return; + } + l->cur_size = new_cur_size; + } +} + +/* + Decrease memory limit accounting after a free/realloc. +*/ +static void talloc_memlimit_shrink(struct talloc_memlimit *limit, + size_t size) +{ + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + if (l->cur_size < size) { + talloc_abort("logic error in talloc_memlimit_shrink\n"); + return; + } + l->cur_size = l->cur_size - size; + } +} + static bool talloc_memlimit_update(struct talloc_memlimit *limit, size_t old_size, size_t new_size) { -- 1.9.1 From 0a0314d160ae8e316e8a64975b6b9f12ec07a60f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:43:50 -0700 Subject: [PATCH 11/47] Remove magic TC_HDR_SIZE handling inside talloc_memlimit_check(). Callers already account for TC_HDR_SIZE, do not add it twice. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 7a6beae68ee3f9a97e9e56f4e24a437839fb3e19) --- lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 067d46f..7b827ca 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -2561,7 +2561,7 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) for (l = limit; l != NULL; l = l->upper) { if (l->max_size != 0 && ((l->max_size <= l->cur_size) || - (l->max_size - l->cur_size < TC_HDR_SIZE+size))) { + (l->max_size - l->cur_size < size))) { return false; } } -- 1.9.1 From 33d24f26485721190f20d7e1ec759107dc9c9340 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:46:09 -0700 Subject: [PATCH 12/47] Change _talloc_total_mem_internal() to ignore memory allocated from a pool when calculating limit size. We must only count normal tallocs, or a talloc pool itself. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 4159a78ed7eda340758e22286f16186987a20f2f) --- lib/talloc/talloc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 7b827ca..1e25dfd 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1817,7 +1817,14 @@ static size_t _talloc_total_mem_internal(const void *ptr, break; case TOTAL_MEM_LIMIT: if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { - total = tc->size + TC_HDR_SIZE; + /* + * Don't count memory allocated from a pool + * when calculating limits. Only count the + * pool itself. + */ + if (!(tc->flags & TALLOC_FLAG_POOLMEM)) { + total = tc->size + TC_HDR_SIZE; + } } break; } -- 1.9.1 From 79e04be1716149e8c1a907eac0ddec2d16dbaca5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:49:00 -0700 Subject: [PATCH 13/47] Change __talloc() to only call talloc_memlimit_check()/talloc_memlimit_grow() on actual malloc allocation. Don't check the memlimit if the allocation was successful from a pool. We already checked the memory limit when we created the pool. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit a4ebbe73b4b8dcab4d344e693ad9796ec8997f87) --- lib/talloc/talloc.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 1e25dfd..cee7d23 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -586,27 +586,24 @@ static inline void *__talloc(const void *context, size_t size) limit = ptc->limit; } - if (!talloc_memlimit_check(limit, (TC_HDR_SIZE+size))) { - errno = ENOMEM; - return NULL; - } - tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size); } if (tc == NULL) { + /* + * Only do the memlimit check/update on actual allocation. + */ + if (!talloc_memlimit_check(limit, TC_HDR_SIZE + size)) { + errno = ENOMEM; + return NULL; + } + tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); if (unlikely(tc == NULL)) return NULL; tc->flags = TALLOC_MAGIC; tc->pool = NULL; - } - if (limit != NULL) { - struct talloc_memlimit *l; - - for (l = limit; l != NULL; l = l->upper) { - l->cur_size += TC_HDR_SIZE+size; - } + talloc_memlimit_grow(limit, TC_HDR_SIZE + size); } tc->limit = limit; -- 1.9.1 From 5dad0a88c76b652fe1e7136ae2f6e557a28e4a29 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:51:20 -0700 Subject: [PATCH 14/47] Update memory limits when we call free() on a pool. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 4dfde7d33e7ac6c94833ecc758baff487ab67e4e) --- lib/talloc/talloc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index cee7d23..c45ac93 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -807,6 +807,8 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, */ pool->hdr.c.name = location; + talloc_memlimit_update_on_free(&pool->hdr.c); + TC_INVALIDATE_FULL_CHUNK(&pool->hdr.c); free(pool); return; -- 1.9.1 From 31f60a973966da13cedf43878947e7489f3d6b5b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:54:38 -0700 Subject: [PATCH 15/47] Inside _talloc_free_internal(), always call talloc_memlimit_update_on_free() before we free the real memory. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 6bc190d6dd7fd0ab028c39c1463477a863f6943a) --- lib/talloc/talloc.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index c45ac93..74eca3f 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -909,29 +909,6 @@ static inline int _talloc_free_internal(void *ptr, const char *location) tc->flags |= TALLOC_FLAG_FREE; - /* - * If we are part of a memory limited context hierarchy - * we need to subtract the memory used from the counters - */ - if (tc->limit) { - struct talloc_memlimit *l; - - for (l = tc->limit; l != NULL; l = l->upper) { - if (l->cur_size >= tc->size+TC_HDR_SIZE) { - l->cur_size -= tc->size+TC_HDR_SIZE; - } else { - talloc_abort("cur_size memlimit counter not correct!"); - return 0; - } - } - - if (tc->limit->parent == tc) { - free(tc->limit); - } - - tc->limit = NULL; - } - /* we mark the freed memory with where we called the free * from. This means on a double free error we can report where * the first free came from @@ -952,6 +929,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location) return 0; } + talloc_memlimit_update_on_free(tc); + TC_INVALIDATE_FULL_CHUNK(tc); free(tc); return 0; @@ -962,6 +941,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location) return 0; } + talloc_memlimit_update_on_free(tc); + TC_INVALIDATE_FULL_CHUNK(tc); free(tc); return 0; -- 1.9.1 From adf164fb1ccf24511654577f94f90531a1fa9e01 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:57:43 -0700 Subject: [PATCH 16/47] In _talloc_steal_internal(), correctly decrement the memory limit in the source, and increment in the destination. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 43860293225d14ca2c339277b42f8705322463ab) --- lib/talloc/talloc.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 74eca3f..54f3c0a 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -976,11 +976,8 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) ctx_size = _talloc_total_limit_size(ptr, NULL, NULL); - if (!talloc_memlimit_update(tc->limit->upper, ctx_size, 0)) { - talloc_abort("cur_size memlimit counter not correct!"); - errno = EINVAL; - return NULL; - } + /* Decrement the memory limit from the source .. */ + talloc_memlimit_shrink(tc->limit->upper, ctx_size); if (tc->limit->parent == tc) { tc->limit->upper = NULL; @@ -1028,13 +1025,9 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) if (tc->limit || new_tc->limit) { ctx_size = _talloc_total_limit_size(ptr, tc->limit, new_tc->limit); - } - - if (new_tc->limit) { - struct talloc_memlimit *l; - - for (l = new_tc->limit; l != NULL; l = l->upper) { - l->cur_size += ctx_size; + /* .. and increment it in the destination. */ + if (new_tc->limit) { + talloc_memlimit_grow(new_tc->limit, ctx_size); } } -- 1.9.1 From 1001970327a1dd2c1fb452557041fe525308f3be Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:59:04 -0700 Subject: [PATCH 17/47] Fix a conditional check. (size - tc->size > 0) is always true if size and tc->size are unsigned. Replace with (size > tc->size). Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 0fbcfcc824e474874c15d7c0b2ea0df408448906) --- lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 54f3c0a..2683ff0 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1507,7 +1507,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons return NULL; } - if (tc->limit && (size - tc->size > 0)) { + if (tc->limit && (size > tc->size)) { if (!talloc_memlimit_check(tc->limit, (size - tc->size))) { errno = ENOMEM; return NULL; -- 1.9.1 From 872ab4445e4c805a3d7b0ec585a0d40dadbbdd99 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:03:27 -0700 Subject: [PATCH 18/47] Don't call talloc_memlimit_update() inside _talloc_realloc() when we're just manipulating pool members. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 314508dd73105138d756f4ca3dfb65f1d368a9f7) --- lib/talloc/talloc.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 2683ff0..aabd2fb 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1629,14 +1629,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (new_chunk_size == old_chunk_size) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; - if (!talloc_memlimit_update(tc->limit, - tc->size, size)) { - talloc_abort("cur_size memlimit counter not" - " correct!"); - errno = EINVAL; - return NULL; - } - tc->size = size; return ptr; } @@ -1652,13 +1644,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (space_left >= space_needed) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; - if (!talloc_memlimit_update(tc->limit, - tc->size, size)) { - talloc_abort("cur_size memlimit " - "counter not correct!"); - errno = EINVAL; - return NULL; - } tc->size = size; pool_tc->hdr.c.pool = tc_next_chunk(tc); return ptr; -- 1.9.1 From edc3211b85b45a7fc4ab62e4e3b9927d39b89026 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:07:04 -0700 Subject: [PATCH 19/47] Inside _talloc_realloc(), keep track of size changes over malloc/realloc/free. Replace the last use of talloc_memlimit_update() with talloc_memlimit_grow()/ talloc_memlimit_shrink(). Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 8e2a543e088cac36a5b6bbab1a6be961fa00cc4d) --- lib/talloc/talloc.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index aabd2fb..66ac110 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1479,6 +1479,8 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons void *new_ptr; bool malloced = false; union talloc_pool_chunk *pool_tc = NULL; + size_t old_size = 0; + size_t new_size = 0; /* size zero is equivalent to free() */ if (unlikely(size == 0)) { @@ -1566,6 +1568,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (new_ptr == NULL) { new_ptr = malloc(TC_HDR_SIZE+size); malloced = true; + new_size = size; } if (new_ptr) { @@ -1573,6 +1576,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons TC_INVALIDATE_FULL_CHUNK(tc); } } else { + /* We're doing malloc then free here, so record the difference. */ + old_size = tc->size; + new_size = size; new_ptr = malloc(size + TC_HDR_SIZE); if (new_ptr) { memcpy(new_ptr, tc, MIN(tc->size, size) + TC_HDR_SIZE); @@ -1655,6 +1661,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons if (new_ptr == NULL) { new_ptr = malloc(TC_HDR_SIZE+size); malloced = true; + new_size = size; } if (new_ptr) { @@ -1664,6 +1671,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons } } else { + /* We're doing realloc here, so record the difference. */ + old_size = tc->size; + new_size = size; new_ptr = realloc(tc, size + TC_HDR_SIZE); } got_new_ptr: @@ -1692,11 +1702,12 @@ got_new_ptr: tc->next->prev = tc; } - if (!talloc_memlimit_update(tc->limit, tc->size, size)) { - talloc_abort("cur_size memlimit counter not correct!"); - errno = EINVAL; - return NULL; + if (new_size > old_size) { + talloc_memlimit_grow(tc->limit, new_size - old_size); + } else if (new_size < old_size) { + talloc_memlimit_shrink(tc->limit, old_size - new_size); } + tc->size = size; _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); -- 1.9.1 From 91941ada18899cd5b85a9d47e614a609b1ddf9d3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:08:33 -0700 Subject: [PATCH 20/47] Remove talloc_memlimit_update(). No longer used. Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit 3d0f717d437bb24f430fad788b9eb35e8fe8e0e8) --- lib/talloc/talloc.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 66ac110..677ec0f 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -236,8 +236,6 @@ struct talloc_memlimit { }; static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); -static bool talloc_memlimit_update(struct talloc_memlimit *limit, - size_t old_size, size_t new_size); static void talloc_memlimit_grow(struct talloc_memlimit *limit, size_t size); static void talloc_memlimit_shrink(struct talloc_memlimit *limit, @@ -2612,28 +2610,6 @@ static void talloc_memlimit_shrink(struct talloc_memlimit *limit, } } -static bool talloc_memlimit_update(struct talloc_memlimit *limit, - size_t old_size, size_t new_size) -{ - struct talloc_memlimit *l; - ssize_t d; - - if (old_size == 0) { - d = new_size + TC_HDR_SIZE; - } else { - d = new_size - old_size; - } - for (l = limit; l != NULL; l = l->upper) { - ssize_t new_cur_size = l->cur_size + d; - if (new_cur_size < 0) { - return false; - } - l->cur_size = new_cur_size; - } - - return true; -} - _PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx); -- 1.9.1 From 7289550d04ad65f39bd6bfd8d6b7051b3271db70 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:09:03 -0700 Subject: [PATCH 21/47] Add simple limited pool tests to test_memlimit(). Signed-off-by: Jeremy Allison Reviewed-by: Simo Sorce (cherry picked from commit cbfc3efbfd4a3a6f3b031ce8ef375d37f2c545f3) --- lib/talloc/testsuite.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index d456cbb..426c31a 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -1359,6 +1359,8 @@ static bool test_memlimit(void) { void *root; char *l1, *l2, *l3, *l4, *l5, *t; + char *pool; + int i; printf("test: memlimit\n# MEMORY LIMITS\n"); @@ -1520,6 +1522,31 @@ static bool test_memlimit(void) talloc_report_full(root, stdout); talloc_free(root); + /* Test memlimits with pools. */ + pool = talloc_pool(NULL, 10*1024); + torture_assert("memlimit", pool != NULL, + "failed: alloc should not fail due to memory limit\n"); + talloc_set_memlimit(pool, 10*1024); + for (i = 0; i < 9; i++) { + l1 = talloc_size(pool, 1024); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + } + /* The next alloc should fail. */ + l2 = talloc_size(pool, 1024); + torture_assert("memlimit", l2 == NULL, + "failed: alloc should fail due to memory limit\n"); + + /* Moving one of the children shouldn't change the limit, + as it's still inside the pool. */ + root = talloc_new(NULL); + talloc_steal(root, l1); + l2 = talloc_size(pool, 1024); + torture_assert("memlimit", l2 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_free(pool); + talloc_free(root); printf("success: memlimit\n"); return true; -- 1.9.1 From 743f08d2aa37151cc177855764ee209630b6cd98 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:20:43 -0700 Subject: [PATCH 22/47] Fix valgrind errors with memmove and talloc pools. bin/smbtorture //127.0.0.1 local.talloc now runs with no valgrind errors. Signed-off-by: Jeremy Allison Reviewed-by: "Stefan (metze) Metzmacher" Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Wed Aug 28 02:44:17 CEST 2013 on sn-devel-104 (cherry picked from commit 617c647b8ef562ace589a11a15eb460e6db71f2a) --- lib/talloc/talloc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 677ec0f..69d5a16 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1609,6 +1609,27 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons size_t old_used = TC_HDR_SIZE + tc->size; size_t new_used = TC_HDR_SIZE + size; new_ptr = start; + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + { + /* + * The area from + * start -> tc may have + * been freed and thus been marked as + * VALGRIND_MEM_NOACCESS. Set it to + * VALGRIND_MEM_UNDEFINED so we can + * copy into it without valgrind errors. + * We can't just mark + * new_ptr -> new_ptr + old_used + * as this may overlap on top of tc, + * (which is why we use memmove, not + * memcpy below) hence the MIN. + */ + size_t undef_len = MIN((((char *)tc) - ((char *)new_ptr)),old_used); + VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, undef_len); + } +#endif + memmove(new_ptr, tc, old_used); tc = (struct talloc_chunk *)new_ptr; -- 1.9.1 From 14ab26ebe6163ca67bfcecd74de9ab9a4a5f5e5f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 10:54:43 -0700 Subject: [PATCH 23/47] talloc: Decouple the dual use of chunk->pool If we want nested pools, we will have pools that are pool members. So we will have to have a separate "next object" pointer for pools. As we have struct talloc_pool_chunk now, this additional pointer does not affect normal talloc objects. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 1334c745e1f2157b66e14f9d8b4f6f7750238717) --- lib/talloc/talloc.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 69d5a16..74db284 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -244,6 +244,8 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc); typedef int (*talloc_destructor_t)(void *); +union talloc_pool_chunk; + struct talloc_chunk { struct talloc_chunk *next, *prev; struct talloc_chunk *parent, *child; @@ -263,17 +265,12 @@ struct talloc_chunk { struct talloc_memlimit *limit; /* - * "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" + * For members of a 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; + union talloc_pool_chunk *pool; }; /* 16 byte alignment seems to keep everyone happy */ @@ -466,6 +463,7 @@ union talloc_pool_chunk { * on 32-bit platforms. */ struct tc_pool_hdr { struct talloc_chunk c; + void *next; unsigned int object_count; } hdr; /* This makes it always 16 byte aligned. */ @@ -479,7 +477,7 @@ static void *tc_pool_end(union talloc_pool_chunk *pool_tc) static size_t tc_pool_space_left(union talloc_pool_chunk *pool_tc) { - return (char *)tc_pool_end(pool_tc) - (char *)pool_tc->hdr.c.pool; + return (char *)tc_pool_end(pool_tc) - (char *)pool_tc->hdr.next; } static void *tc_pool_first_chunk(union talloc_pool_chunk *pool_tc) @@ -499,11 +497,11 @@ static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc) size_t flen = tc_pool_space_left(pool_tc); if (unlikely(talloc_fill.enabled)) { - memset(pool_tc->hdr.c.pool, talloc_fill.fill_value, flen); + memset(pool_tc->hdr.next, talloc_fill.fill_value, flen); } #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) - VALGRIND_MAKE_MEM_NOACCESS(pool_tc->hdr.c.pool, flen); + VALGRIND_MAKE_MEM_NOACCESS(pool_tc->hdr.next, flen); #endif } @@ -527,7 +525,7 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, pool_ctx = (union talloc_pool_chunk *)parent; } else if (parent->flags & TALLOC_FLAG_POOLMEM) { - pool_ctx = (union talloc_pool_chunk *)parent->pool; + pool_ctx = parent->pool; } if (pool_ctx == NULL) { @@ -545,13 +543,13 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, return NULL; } - result = (struct talloc_chunk *)pool_ctx->hdr.c.pool; + result = (struct talloc_chunk *)pool_ctx->hdr.next; #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) VALGRIND_MAKE_MEM_UNDEFINED(result, size); #endif - pool_ctx->hdr.c.pool = (void *)((char *)result + chunk_size); + pool_ctx->hdr.next = (void *)((char *)result + chunk_size); result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; result->pool = pool_ctx; @@ -653,7 +651,7 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size) return NULL; } pool_tc->hdr.c.flags |= TALLOC_FLAG_POOL; - pool_tc->hdr.c.pool = tc_pool_first_chunk(pool_tc); + pool_tc->hdr.next = tc_pool_first_chunk(pool_tc); pool_tc->hdr.object_count = 1; @@ -763,7 +761,7 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, union talloc_pool_chunk *pool; void *next_tc; - pool = (union talloc_pool_chunk *)tc->pool; + pool = tc->pool; next_tc = tc_next_chunk(tc); tc->flags |= TALLOC_FLAG_FREE; @@ -792,7 +790,7 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, * the rest is available for new objects * again. */ - pool->hdr.c.pool = tc_pool_first_chunk(pool); + pool->hdr.next = tc_pool_first_chunk(pool); tc_invalidate_pool(pool); return; } @@ -812,13 +810,13 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, return; } - if (pool->hdr.c.pool == next_tc) { + if (pool->hdr.next == next_tc) { /* * if pool->pool still points to end of * 'tc' (which is stored in the 'next_tc' variable), * we can reclaim the memory of 'tc'. */ - pool->hdr.c.pool = tc; + pool->hdr.next = tc; return; } @@ -1516,7 +1514,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons /* handle realloc inside a talloc_pool */ if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { - pool_tc = (union talloc_pool_chunk *)tc->pool; + pool_tc = tc->pool; } #if (ALWAYS_REALLOC == 0) @@ -1526,9 +1524,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons void *next_tc = tc_next_chunk(tc); TC_INVALIDATE_SHRINK_CHUNK(tc, size); tc->size = size; - if (next_tc == pool_tc->hdr.c.pool) { + if (next_tc == pool_tc->hdr.next) { /* note: tc->size has changed, so this works */ - pool_tc->hdr.c.pool = tc_next_chunk(tc); + pool_tc->hdr.next = tc_next_chunk(tc); } return ptr; } else if ((tc->size - size) < 1024) { @@ -1640,11 +1638,11 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons * because we want to invalidate the padding * too. */ - pool_tc->hdr.c.pool = new_used + (char *)new_ptr; + pool_tc->hdr.next = new_used + (char *)new_ptr; tc_invalidate_pool(pool_tc); /* now the aligned pointer */ - pool_tc->hdr.c.pool = new_chunk_size + (char *)new_ptr; + pool_tc->hdr.next = new_chunk_size + (char *)new_ptr; goto got_new_ptr; } @@ -1658,7 +1656,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons return ptr; } - if (next_tc == pool_tc->hdr.c.pool) { + if (next_tc == pool_tc->hdr.next) { /* * optimize for the case where 'tc' is the last * chunk in the pool. @@ -1670,7 +1668,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; tc->size = size; - pool_tc->hdr.c.pool = tc_next_chunk(tc); + pool_tc->hdr.next = tc_next_chunk(tc); return ptr; } } -- 1.9.1 From c8473289ab5728a760bcdaecbf9b19f4da9c99f7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 12:18:26 -0700 Subject: [PATCH 24/47] talloc: Introduce __talloc_with_prefix This will allow to exchange the extra talloc pool header with the talloc_chunk structure Signed-off-by: Volker Lendecke Signed-off-by: Jeremy Allison (cherry picked from commit 9887f387a10e94f71790c0c3c7dc5f8cde7e4eb2) --- lib/talloc/talloc.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 74db284..21d675d 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -510,7 +510,7 @@ static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc) */ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, - size_t size) + size_t size, size_t prefix_len) { union talloc_pool_chunk *pool_ctx = NULL; size_t space_left; @@ -537,13 +537,14 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, /* * Align size to 16 bytes */ - chunk_size = TC_ALIGN16(size); + chunk_size = TC_ALIGN16(size + prefix_len); if (space_left < chunk_size) { return NULL; } - result = (struct talloc_chunk *)pool_ctx->hdr.next; + result = (struct talloc_chunk *) + ((char *)pool_ctx->hdr.next + prefix_len); #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) VALGRIND_MAKE_MEM_UNDEFINED(result, size); @@ -562,10 +563,12 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, /* Allocate a bit of memory as a child of an existing pointer */ -static inline void *__talloc(const void *context, size_t size) +static inline void *__talloc_with_prefix(const void *context, size_t size, + size_t prefix_len) { struct talloc_chunk *tc = NULL; struct talloc_memlimit *limit = NULL; + size_t total_len = TC_HDR_SIZE + size + prefix_len; if (unlikely(context == NULL)) { context = null_context; @@ -575,6 +578,10 @@ static inline void *__talloc(const void *context, size_t size) return NULL; } + if (unlikely(total_len < TC_HDR_SIZE)) { + return NULL; + } + if (context != NULL) { struct talloc_chunk *ptc = talloc_chunk_from_ptr(context); @@ -582,24 +589,24 @@ static inline void *__talloc(const void *context, size_t size) limit = ptc->limit; } - tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size); + tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size, prefix_len); } if (tc == NULL) { /* * Only do the memlimit check/update on actual allocation. */ - if (!talloc_memlimit_check(limit, TC_HDR_SIZE + size)) { + if (!talloc_memlimit_check(limit, total_len)) { errno = ENOMEM; return NULL; } - tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); + tc = (struct talloc_chunk *)malloc(total_len); if (unlikely(tc == NULL)) return NULL; tc->flags = TALLOC_MAGIC; tc->pool = NULL; - talloc_memlimit_grow(limit, TC_HDR_SIZE + size); + talloc_memlimit_grow(limit, total_len); } tc->limit = limit; @@ -629,6 +636,11 @@ static inline void *__talloc(const void *context, size_t size) return TC_PTR_FROM_CHUNK(tc); } +static inline void *__talloc(const void *context, size_t size) +{ + return __talloc_with_prefix(context, size, 0); +} + /* * Create a talloc pool */ @@ -1558,7 +1570,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons #if ALWAYS_REALLOC if (pool_tc) { - new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); + new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0); pool_tc->hdr.object_count--; if (new_ptr == NULL) { @@ -1673,7 +1685,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons } } - new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); + new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0); if (new_ptr == NULL) { new_ptr = malloc(TC_HDR_SIZE+size); -- 1.9.1 From e452a83b73056f64001d757f98ac1fc88627c5bc Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 14:08:43 -0700 Subject: [PATCH 25/47] talloc: Put pool-specific data before the chunk This is a preparation to make talloc pool real objects themselves. Signed-off-by: Volker Lendecke Signed-off-by: Jeremy Allison (cherry picked from commit b87c8fd435d1863d6efcec03830ecd85ddfcd7fb) --- lib/talloc/talloc.c | 204 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 79 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 21d675d..a553050 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -244,7 +244,7 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc); typedef int (*talloc_destructor_t)(void *); -union talloc_pool_chunk; +struct talloc_pool_hdr; struct talloc_chunk { struct talloc_chunk *next, *prev; @@ -270,7 +270,7 @@ struct talloc_chunk { * allocated from. This way children can quickly find the pool to chew * from. */ - union talloc_pool_chunk *pool; + struct talloc_pool_hdr *pool; }; /* 16 byte alignment seems to keep everyone happy */ @@ -458,31 +458,37 @@ _PUBLIC_ const char *talloc_parent_name(const void *ptr) memory footprint of each talloc chunk by those 16 bytes. */ -union talloc_pool_chunk { - /* This lets object_count nestle into 16-byte padding of talloc_chunk, - * on 32-bit platforms. */ - struct tc_pool_hdr { - struct talloc_chunk c; - void *next; - unsigned int object_count; - } hdr; - /* This makes it always 16 byte aligned. */ - char pad[TC_ALIGN16(sizeof(struct tc_pool_hdr))]; +struct talloc_pool_hdr { + void *end; + unsigned int object_count; }; -static void *tc_pool_end(union talloc_pool_chunk *pool_tc) +#define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr)) + +static struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c) +{ + return (struct talloc_pool_hdr *)((char *)c - TP_HDR_SIZE); +} + +static struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h) { - return (char *)pool_tc + TC_HDR_SIZE + pool_tc->hdr.c.size; + return (struct talloc_chunk *)((char *)h + TP_HDR_SIZE); } -static size_t tc_pool_space_left(union talloc_pool_chunk *pool_tc) +static void *tc_pool_end(struct talloc_pool_hdr *pool_hdr) { - return (char *)tc_pool_end(pool_tc) - (char *)pool_tc->hdr.next; + struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); + return (char *)tc + TC_HDR_SIZE + tc->size; } -static void *tc_pool_first_chunk(union talloc_pool_chunk *pool_tc) +static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) { - return pool_tc + 1; + return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end; +} + +static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) +{ + return TC_PTR_FROM_CHUNK(talloc_chunk_from_pool(pool_hdr)); } /* If tc is inside a pool, this gives the next neighbour. */ @@ -492,16 +498,16 @@ static void *tc_next_chunk(struct talloc_chunk *tc) } /* Mark the whole remaining pool as not accessable */ -static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc) +static void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) { - size_t flen = tc_pool_space_left(pool_tc); + size_t flen = tc_pool_space_left(pool_hdr); if (unlikely(talloc_fill.enabled)) { - memset(pool_tc->hdr.next, talloc_fill.fill_value, flen); + memset(pool_hdr->end, talloc_fill.fill_value, flen); } #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) - VALGRIND_MAKE_MEM_NOACCESS(pool_tc->hdr.next, flen); + VALGRIND_MAKE_MEM_NOACCESS(pool_hdr->end, flen); #endif } @@ -512,7 +518,7 @@ static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc) static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, size_t size, size_t prefix_len) { - union talloc_pool_chunk *pool_ctx = NULL; + struct talloc_pool_hdr *pool_hdr = NULL; size_t space_left; struct talloc_chunk *result; size_t chunk_size; @@ -522,17 +528,17 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, } if (parent->flags & TALLOC_FLAG_POOL) { - pool_ctx = (union talloc_pool_chunk *)parent; + pool_hdr = talloc_pool_from_chunk(parent); } else if (parent->flags & TALLOC_FLAG_POOLMEM) { - pool_ctx = parent->pool; + pool_hdr = parent->pool; } - if (pool_ctx == NULL) { + if (pool_hdr == NULL) { return NULL; } - space_left = tc_pool_space_left(pool_ctx); + space_left = tc_pool_space_left(pool_hdr); /* * Align size to 16 bytes @@ -543,19 +549,18 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, return NULL; } - result = (struct talloc_chunk *) - ((char *)pool_ctx->hdr.next + prefix_len); + result = (struct talloc_chunk *)((char *)pool_hdr->end + prefix_len); #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) - VALGRIND_MAKE_MEM_UNDEFINED(result, size); + VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, chunk_size); #endif - pool_ctx->hdr.next = (void *)((char *)result + chunk_size); + pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size); result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; - result->pool = pool_ctx; + result->pool = pool_hdr; - pool_ctx->hdr.object_count++; + pool_hdr->object_count++; return result; } @@ -593,6 +598,8 @@ static inline void *__talloc_with_prefix(const void *context, size_t size, } if (tc == NULL) { + char *ptr; + /* * Only do the memlimit check/update on actual allocation. */ @@ -601,8 +608,11 @@ static inline void *__talloc_with_prefix(const void *context, size_t size, return NULL; } - tc = (struct talloc_chunk *)malloc(total_len); - if (unlikely(tc == NULL)) return NULL; + ptr = malloc(total_len); + if (unlikely(ptr == NULL)) { + return NULL; + } + tc = (struct talloc_chunk *)(ptr + prefix_len); tc->flags = TALLOC_MAGIC; tc->pool = NULL; @@ -647,27 +657,32 @@ static inline void *__talloc(const void *context, size_t size) _PUBLIC_ void *talloc_pool(const void *context, size_t size) { - union talloc_pool_chunk *pool_tc; - void *result = __talloc(context, sizeof(*pool_tc) - TC_HDR_SIZE + size); + struct talloc_chunk *tc; + struct talloc_pool_hdr *pool_hdr; + void *result; + + result = __talloc_with_prefix(context, size, TP_HDR_SIZE); if (unlikely(result == NULL)) { return NULL; } - pool_tc = (union talloc_pool_chunk *)talloc_chunk_from_ptr(result); - if (unlikely(pool_tc->hdr.c.flags & TALLOC_FLAG_POOLMEM)) { + tc = talloc_chunk_from_ptr(result); + pool_hdr = talloc_pool_from_chunk(tc); + + if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { /* We don't handle this correctly, so fail. */ talloc_log("talloc: cannot allocate pool off another pool %s\n", talloc_get_name(context)); talloc_free(result); return NULL; } - pool_tc->hdr.c.flags |= TALLOC_FLAG_POOL; - pool_tc->hdr.next = tc_pool_first_chunk(pool_tc); + tc->flags |= TALLOC_FLAG_POOL; - pool_tc->hdr.object_count = 1; + pool_hdr->object_count = 1; + pool_hdr->end = result; - tc_invalidate_pool(pool_tc); + tc_invalidate_pool(pool_hdr); return result; } @@ -770,10 +785,12 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr); static inline void _talloc_free_poolmem(struct talloc_chunk *tc, const char *location) { - union talloc_pool_chunk *pool; + struct talloc_pool_hdr *pool; + struct talloc_chunk *pool_tc; void *next_tc; pool = tc->pool; + pool_tc = talloc_chunk_from_pool(pool); next_tc = tc_next_chunk(tc); tc->flags |= TALLOC_FLAG_FREE; @@ -786,15 +803,15 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, TC_INVALIDATE_FULL_CHUNK(tc); - if (unlikely(pool->hdr.object_count == 0)) { + if (unlikely(pool->object_count == 0)) { talloc_abort("Pool object count zero!"); return; } - pool->hdr.object_count--; + pool->object_count--; - if (unlikely(pool->hdr.object_count == 1 - && !(pool->hdr.c.flags & TALLOC_FLAG_FREE))) { + if (unlikely(pool->object_count == 1 + && !(pool_tc->flags & TALLOC_FLAG_FREE))) { /* * if there is just one object left in the pool * and pool->flags does not have TALLOC_FLAG_FREE, @@ -802,33 +819,33 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, * the rest is available for new objects * again. */ - pool->hdr.next = tc_pool_first_chunk(pool); + pool->end = tc_pool_first_chunk(pool); tc_invalidate_pool(pool); return; } - if (unlikely(pool->hdr.object_count == 0)) { + if (unlikely(pool->object_count == 0)) { /* * we mark the freed memory with where we called the free * from. This means on a double free error we can report where * the first free came from */ - pool->hdr.c.name = location; + pool_tc->name = location; - talloc_memlimit_update_on_free(&pool->hdr.c); + talloc_memlimit_update_on_free(pool_tc); - TC_INVALIDATE_FULL_CHUNK(&pool->hdr.c); + TC_INVALIDATE_FULL_CHUNK(pool_tc); free(pool); return; } - if (pool->hdr.next == next_tc) { + if (pool->end == next_tc) { /* * if pool->pool still points to end of * 'tc' (which is stored in the 'next_tc' variable), * we can reclaim the memory of 'tc'. */ - pool->hdr.next = tc; + pool->end = tc; return; } @@ -924,23 +941,30 @@ static inline int _talloc_free_internal(void *ptr, const char *location) tc->name = location; if (tc->flags & TALLOC_FLAG_POOL) { - union talloc_pool_chunk *pool = (union talloc_pool_chunk *)tc; + struct talloc_pool_hdr *pool; + + pool = talloc_pool_from_chunk(tc); - if (unlikely(pool->hdr.object_count == 0)) { + if (unlikely(pool->object_count == 0)) { talloc_abort("Pool object count zero!"); return 0; } - pool->hdr.object_count--; + pool->object_count--; - if (likely(pool->hdr.object_count != 0)) { + if (likely(pool->object_count != 0)) { return 0; } + /* + * This call takes into account the + * prefix TP_HDR_SIZE allocated before + * the pool talloc_chunk. + */ talloc_memlimit_update_on_free(tc); TC_INVALIDATE_FULL_CHUNK(tc); - free(tc); + free(pool); return 0; } @@ -1486,7 +1510,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons struct talloc_chunk *tc; void *new_ptr; bool malloced = false; - union talloc_pool_chunk *pool_tc = NULL; + struct talloc_pool_hdr *pool_hdr = NULL; size_t old_size = 0; size_t new_size = 0; @@ -1526,19 +1550,19 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons /* handle realloc inside a talloc_pool */ if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { - pool_tc = tc->pool; + pool_hdr = tc->pool; } #if (ALWAYS_REALLOC == 0) /* don't shrink if we have less than 1k to gain */ if (size < tc->size && tc->limit == NULL) { - if (pool_tc) { + if (pool_hdr) { void *next_tc = tc_next_chunk(tc); TC_INVALIDATE_SHRINK_CHUNK(tc, size); tc->size = size; - if (next_tc == pool_tc->hdr.next) { + if (next_tc == pool_hdr->end) { /* note: tc->size has changed, so this works */ - pool_tc->hdr.next = tc_next_chunk(tc); + pool_hdr->end = tc_next_chunk(tc); } return ptr; } else if ((tc->size - size) < 1024) { @@ -1569,9 +1593,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons tc->flags |= TALLOC_FLAG_FREE; #if ALWAYS_REALLOC - if (pool_tc) { + if (pool_hdr) { new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0); - pool_tc->hdr.object_count--; + pool_hdr->object_count--; if (new_ptr == NULL) { new_ptr = malloc(TC_HDR_SIZE+size); @@ -1594,15 +1618,17 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons } } #else - if (pool_tc) { + if (pool_hdr) { + struct talloc_chunk *pool_tc; void *next_tc = tc_next_chunk(tc); size_t old_chunk_size = TC_ALIGN16(TC_HDR_SIZE + tc->size); size_t new_chunk_size = TC_ALIGN16(TC_HDR_SIZE + size); size_t space_needed; size_t space_left; - unsigned int chunk_count = pool_tc->hdr.object_count; + unsigned int chunk_count = pool_hdr->object_count; - if (!(pool_tc->hdr.c.flags & TALLOC_FLAG_FREE)) { + pool_tc = talloc_chunk_from_pool(pool_hdr); + if (!(pool_tc->flags & TALLOC_FLAG_FREE)) { chunk_count -= 1; } @@ -1611,9 +1637,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons * optimize for the case where 'tc' is the only * chunk in the pool. */ - char *start = tc_pool_first_chunk(pool_tc); + char *start = tc_pool_first_chunk(pool_hdr); space_needed = new_chunk_size; - space_left = (char *)tc_pool_end(pool_tc) - start; + space_left = (char *)tc_pool_end(pool_hdr) - start; if (space_left >= space_needed) { size_t old_used = TC_HDR_SIZE + tc->size; @@ -1650,11 +1676,11 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons * because we want to invalidate the padding * too. */ - pool_tc->hdr.next = new_used + (char *)new_ptr; - tc_invalidate_pool(pool_tc); + pool_hdr->end = new_used + (char *)new_ptr; + tc_invalidate_pool(pool_hdr); /* now the aligned pointer */ - pool_tc->hdr.next = new_chunk_size + (char *)new_ptr; + pool_hdr->end = new_chunk_size + (char *)new_ptr; goto got_new_ptr; } @@ -1668,19 +1694,19 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons return ptr; } - if (next_tc == pool_tc->hdr.next) { + if (next_tc == pool_hdr->end) { /* * optimize for the case where 'tc' is the last * chunk in the pool. */ space_needed = new_chunk_size - old_chunk_size; - space_left = tc_pool_space_left(pool_tc); + space_left = tc_pool_space_left(pool_hdr); if (space_left >= space_needed) { TC_UNDEFINE_GROW_CHUNK(tc, size); tc->flags &= ~TALLOC_FLAG_FREE; tc->size = size; - pool_tc->hdr.next = tc_next_chunk(tc); + pool_hdr->end = tc_next_chunk(tc); return ptr; } } @@ -1822,6 +1848,13 @@ static size_t _talloc_total_mem_internal(const void *ptr, */ if (!(tc->flags & TALLOC_FLAG_POOLMEM)) { total = tc->size + TC_HDR_SIZE; + /* + * If this is a pool, remember to + * add the prefix length. + */ + if (tc->flags & TALLOC_FLAG_POOL) { + total += TP_HDR_SIZE; + } } } break; @@ -2579,6 +2612,8 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) */ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc) { + size_t limit_shrink_size; + if (!tc->limit) { return; } @@ -2597,7 +2632,18 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc) * we need to subtract the memory used from the counters */ - talloc_memlimit_shrink(tc->limit, tc->size+TC_HDR_SIZE); + limit_shrink_size = tc->size+TC_HDR_SIZE; + + /* + * If we're deallocating a pool, take into + * account the prefix size added for the pool. + */ + + if (tc->flags & TALLOC_FLAG_POOL) { + limit_shrink_size += TP_HDR_SIZE; + } + + talloc_memlimit_shrink(tc->limit, limit_shrink_size); if (tc->limit->parent == tc) { free(tc->limit); -- 1.9.1 From 35d9ff77439b28f9dd7b87941ab38380aff91c47 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 14:20:20 -0700 Subject: [PATCH 26/47] talloc: Add a separate pool size This is necessary to allow talloc pools to be objects on their own. It is an incompatible change in the sense that talloc_get_size(pool) now returns 0 instead of the pool size. When the talloc_pooled_object() call is added, this will start to make sense again. Maybe we should add a talloc_pool_size call? Or is that overkill? Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit a3d9099d9a96b36df21ee0733adc5210438fe9dc) --- lib/talloc/talloc.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index a553050..5d13567 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -461,6 +461,7 @@ _PUBLIC_ const char *talloc_parent_name(const void *ptr) struct talloc_pool_hdr { void *end; unsigned int object_count; + size_t poolsize; }; #define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr)) @@ -478,7 +479,7 @@ static struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h) static void *tc_pool_end(struct talloc_pool_hdr *pool_hdr) { struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); - return (char *)tc + TC_HDR_SIZE + tc->size; + return (char *)tc + TC_HDR_SIZE + pool_hdr->poolsize; } static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) @@ -486,17 +487,18 @@ static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end; } -static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) -{ - return TC_PTR_FROM_CHUNK(talloc_chunk_from_pool(pool_hdr)); -} - /* If tc is inside a pool, this gives the next neighbour. */ static void *tc_next_chunk(struct talloc_chunk *tc) { return (char *)tc + TC_ALIGN16(TC_HDR_SIZE + tc->size); } +static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) +{ + struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); + return tc_next_chunk(tc); +} + /* Mark the whole remaining pool as not accessable */ static void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) { @@ -678,9 +680,11 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size) return NULL; } tc->flags |= TALLOC_FLAG_POOL; + tc->size = 0; pool_hdr->object_count = 1; pool_hdr->end = result; + pool_hdr->poolsize = size; tc_invalidate_pool(pool_hdr); @@ -1847,13 +1851,20 @@ static size_t _talloc_total_mem_internal(const void *ptr, * pool itself. */ if (!(tc->flags & TALLOC_FLAG_POOLMEM)) { - total = tc->size + TC_HDR_SIZE; - /* - * If this is a pool, remember to - * add the prefix length. - */ if (tc->flags & TALLOC_FLAG_POOL) { - total += TP_HDR_SIZE; + /* + * If this is a pool, the allocated + * size is in the pool header, and + * remember to add in the prefix + * length. + */ + struct talloc_pool_hdr *pool_hdr + = talloc_pool_from_chunk(tc); + total = pool_hdr->poolsize + + TC_HDR_SIZE + + TP_HDR_SIZE; + } else { + total = tc->size + TC_HDR_SIZE; } } } -- 1.9.1 From 4bebbe98dfe5326692e6b5a49d720622e136635d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 14:52:28 -0700 Subject: [PATCH 27/47] talloc: Allow nested pools. Signed-off-by: Volker Lendecke Signed-off-by: Jeremy Allison (cherry picked from commit 20ad6d7aa3dc5e7db4d886202f757ac1f68287d4) --- lib/talloc/talloc.c | 47 +++++++++++++++++++++++++---------------------- lib/talloc/talloc.h | 3 +-- lib/talloc/testsuite.c | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 5d13567..198bab9 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -672,13 +672,6 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size) tc = talloc_chunk_from_ptr(result); pool_hdr = talloc_pool_from_chunk(tc); - if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { - /* We don't handle this correctly, so fail. */ - talloc_log("talloc: cannot allocate pool off another pool %s\n", - talloc_get_name(context)); - talloc_free(result); - return NULL; - } tc->flags |= TALLOC_FLAG_POOL; tc->size = 0; @@ -836,10 +829,19 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc, */ pool_tc->name = location; - talloc_memlimit_update_on_free(pool_tc); - - TC_INVALIDATE_FULL_CHUNK(pool_tc); - free(pool); + if (pool_tc->flags & TALLOC_FLAG_POOLMEM) { + _talloc_free_poolmem(pool_tc, location); + } else { + /* + * The talloc_memlimit_update_on_free() + * call takes into account the + * prefix TP_HDR_SIZE allocated before + * the pool talloc_chunk. + */ + talloc_memlimit_update_on_free(pool_tc); + TC_INVALIDATE_FULL_CHUNK(pool_tc); + free(pool); + } return; } @@ -869,6 +871,7 @@ static inline void _talloc_free_children_internal(struct talloc_chunk *tc, static inline int _talloc_free_internal(void *ptr, const char *location) { struct talloc_chunk *tc; + void *ptr_to_free; if (unlikely(ptr == NULL)) { return -1; @@ -961,15 +964,13 @@ static inline int _talloc_free_internal(void *ptr, const char *location) } /* - * This call takes into account the - * prefix TP_HDR_SIZE allocated before - * the pool talloc_chunk. - */ - talloc_memlimit_update_on_free(tc); - - TC_INVALIDATE_FULL_CHUNK(tc); - free(pool); - return 0; + * With object_count==0, a pool becomes a normal piece of + * memory to free. If it's allocated inside a pool, it needs + * to be freed as poolmem, else it needs to be just freed. + */ + ptr_to_free = pool; + } else { + ptr_to_free = tc; } if (tc->flags & TALLOC_FLAG_POOLMEM) { @@ -980,7 +981,7 @@ static inline int _talloc_free_internal(void *ptr, const char *location) talloc_memlimit_update_on_free(tc); TC_INVALIDATE_FULL_CHUNK(tc); - free(tc); + free(ptr_to_free); return 0; } @@ -2632,7 +2633,9 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc) /* * Pool entries don't count. Only the pools * themselves are counted as part of the memory - * limits. + * limits. Note that this also takes care of + * nested pools which have both flags + * TALLOC_FLAG_POOLMEM|TALLOC_FLAG_POOL set. */ if (tc->flags & TALLOC_FLAG_POOLMEM) { return; diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index f3cbcd0..aa9864b 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -839,8 +839,7 @@ void *talloc_find_parent_bytype(const void *ptr, #type); * talloc pool to a talloc parent outside the pool, the whole pool memory is * not free(3)'ed until that moved chunk is also talloc_free()ed. * - * @param[in] context The talloc context to hang the result off (must not - * be another pool). + * @param[in] context The talloc context to hang the result off. * * @param[in] size Size of the talloc pool. * diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index 426c31a..f04f4f1 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -1267,6 +1267,30 @@ static bool test_pool_steal(void) return true; } +static bool test_pool_nest(void) +{ + void *p1, *p2, *p3; + void *e = talloc_new(NULL); + + p1 = talloc_pool(NULL, 1024); + torture_assert("talloc_pool", p1 != NULL, "failed"); + + p2 = talloc_pool(p1, 500); + torture_assert("talloc_pool", p2 != NULL, "failed"); + + p3 = talloc_size(p2, 10); + + talloc_steal(e, p3); + + talloc_free(p2); + + talloc_free(p3); + + talloc_free(p1); + + return true; +} + static bool test_free_ref_null_context(void) { void *p1, *p2, *p3; @@ -1567,6 +1591,8 @@ bool torture_local_talloc(struct torture_context *tctx) setlinebuf(stdout); test_reset(); + ret &= test_pool_nest(); + test_reset(); ret &= test_ref1(); test_reset(); ret &= test_ref2(); -- 1.9.1 From 362946fb96155b43ed7608d9e4fed8990ae3972c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 15:15:32 -0700 Subject: [PATCH 28/47] talloc: Add talloc_pooled_object Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit e82320e5197bcdd0330bc829c0963ad09854a36c) --- lib/talloc/ABI/pytalloc-util-2.1.0.sigs | 6 +++ lib/talloc/ABI/talloc-2.1.0.sigs | 64 ++++++++++++++++++++++++++++++++ lib/talloc/talloc.c | 66 +++++++++++++++++++++++++++++++++ lib/talloc/talloc.h | 37 ++++++++++++++++++ lib/talloc/wscript | 2 +- 5 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 lib/talloc/ABI/pytalloc-util-2.1.0.sigs create mode 100644 lib/talloc/ABI/talloc-2.1.0.sigs diff --git a/lib/talloc/ABI/pytalloc-util-2.1.0.sigs b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/talloc-2.1.0.sigs b/lib/talloc/ABI/talloc-2.1.0.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.0.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 198bab9..1cb4d7d 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -685,6 +685,72 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size) } /* + * Create a talloc pool correctly sized for a basic size plus + * a number of subobjects whose total size is given. Essentially + * a custom allocator for talloc to reduce fragmentation. + */ + +_PUBLIC_ void *_talloc_pooled_object(const void *ctx, + size_t type_size, + const char *type_name, + unsigned num_subobjects, + size_t total_subobjects_size) +{ + size_t poolsize, subobjects_slack, tmp; + struct talloc_chunk *tc; + struct talloc_pool_hdr *pool_hdr; + void *ret; + + poolsize = type_size + total_subobjects_size; + + if ((poolsize < type_size) || (poolsize < total_subobjects_size)) { + goto overflow; + } + + if (num_subobjects == UINT_MAX) { + goto overflow; + } + num_subobjects += 1; /* the object body itself */ + + /* + * Alignment can increase the pool size by at most 15 bytes per object + * plus alignment for the object itself + */ + subobjects_slack = (TC_HDR_SIZE + TP_HDR_SIZE + 15) * num_subobjects; + if (subobjects_slack < num_subobjects) { + goto overflow; + } + + tmp = poolsize + subobjects_slack; + if ((tmp < poolsize) || (tmp < subobjects_slack)) { + goto overflow; + } + poolsize = tmp; + + ret = talloc_pool(ctx, poolsize); + if (ret == NULL) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ret); + tc->size = type_size; + + pool_hdr = talloc_pool_from_chunk(tc); + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, type_size); +#endif + + pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(type_size)); + + talloc_set_name_const(ret, type_name); + return ret; + +overflow: + return NULL; +} + +/* 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 diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index aa9864b..1b59390 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -847,6 +847,43 @@ void *talloc_find_parent_bytype(const void *ptr, #type); */ void *talloc_pool(const void *context, size_t size); +#ifdef DOXYGEN +/** + * @brief Allocate a talloc object as/with an additional pool. + * + * This is like talloc_pool(), but's it's more flexible + * and allows an object to be a pool for its children. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] type The type that we want to allocate. + * + * @param[in] num_subobjects The expected number of subobjects, which will + * be allocated within the pool. This allocates + * space for talloc_chunk headers. + * + * @param[in] total_subobjects_size The size that all subobjects can use in total. + * + * + * @return The allocated talloc object, NULL on error. + */ +void *talloc_pooled_object(const void *ctx, #type, + unsigned num_subobjects, + size_t total_subobjects_size); +#else +#define talloc_pooled_object(_ctx, _type, \ + _num_subobjects, \ + _total_subobjects_size) \ + (_type *)_talloc_pooled_object((_ctx), sizeof(_type), #_type, \ + (_num_subobjects), \ + (_total_subobjects_size)) +void *_talloc_pooled_object(const void *ctx, + size_t type_size, + const char *type_name, + unsigned num_subobjects, + size_t total_subobjects_size); +#endif + /** * @brief Free a talloc chunk and NULL out the pointer. * diff --git a/lib/talloc/wscript b/lib/talloc/wscript index ecc5e24..1ca41f6 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'talloc' -VERSION = '2.0.8' +VERSION = '2.1.0' blddir = 'bin' -- 1.9.1 From 573396891865f25202d064bc51f80bcd72802da9 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 15:30:38 -0700 Subject: [PATCH 29/47] talloc: Test the pooled object Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 256d10f5792a37d20cbb45f2af3f8578bd354110) --- lib/talloc/testsuite.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index f04f4f1..888d260 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -1291,6 +1291,40 @@ static bool test_pool_nest(void) return true; } +struct pooled { + char *s1; + char *s2; + char *s3; +}; + +static bool test_pooled_object(void) +{ + struct pooled *p; + const char *s1 = "hello"; + const char *s2 = "world"; + const char *s3 = ""; + + p = talloc_pooled_object(NULL, struct pooled, 3, + strlen(s1)+strlen(s2)+strlen(s3)+3); + + if (talloc_get_size(p) != sizeof(struct pooled)) { + return false; + } + + p->s1 = talloc_strdup(p, s1); + + TALLOC_FREE(p->s1); + p->s1 = talloc_strdup(p, s2); + TALLOC_FREE(p->s1); + + p->s1 = talloc_strdup(p, s1); + p->s2 = talloc_strdup(p, s2); + p->s3 = talloc_strdup(p, s3); + + TALLOC_FREE(p); + return true; +} + static bool test_free_ref_null_context(void) { void *p1, *p2, *p3; @@ -1591,6 +1625,8 @@ bool torture_local_talloc(struct torture_context *tctx) setlinebuf(stdout); test_reset(); + ret &= test_pooled_object(); + test_reset(); ret &= test_pool_nest(); test_reset(); ret &= test_ref1(); -- 1.9.1 From 6fd1949759e988ad6d322835ed12452ff009c570 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 14 Oct 2013 13:17:12 +0200 Subject: [PATCH 30/47] talloc: Add a warning to talloc_reference() documentation. Signed-off-by: Andreas Schneider Reviewed-by: Kai Blin Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Mon Oct 14 23:05:54 CEST 2013 on sn-devel-104 (cherry picked from commit 2343df451a13115eebfd46f9247ec2ae8c3a85c0) --- lib/talloc/talloc.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index 1b59390..5d29a8d 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -961,6 +961,10 @@ size_t talloc_reference_count(const void *ptr); * @return The original pointer 'ptr', NULL if talloc ran out of * memory in creating the reference. * + * @warning You should try to avoid using this interface. It turns a beautiful + * talloc-tree into a graph. It is often really hard to debug if you + * screw something up by accident. + * * Example: * @code * unsigned int *a, *b, *c; @@ -1001,6 +1005,10 @@ void *_talloc_reference_loc(const void *context, const void *ptr, const char *lo * this function will fail and will return -1. Likewise, if ptr is NULL, * then the function will make no modifications and return -1. * + * @warning You should try to avoid using this interface. It turns a beautiful + * talloc-tree into a graph. It is often really hard to debug if you + * screw something up by accident. + * * Example: * @code * unsigned int *a, *b, *c; -- 1.9.1 From f5589a3adecce2c859050b56a2ad8ecf41f846df Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 27 Nov 2013 02:12:02 +0000 Subject: [PATCH 31/47] Add a basic guide on pytalloc. Signed-off-by: Jelmer Vernooij Reviewed-By: Andrew Bartlett Autobuild-User(master): Jelmer Vernooij Autobuild-Date(master): Thu Nov 28 02:24:45 CET 2013 on sn-devel-104 (cherry picked from commit 91c1053413e1f309b2d5b215a423f37e3883aa91) --- lib/talloc/pytalloc.h | 3 + lib/talloc/pytalloc_guide.txt | 153 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 lib/talloc/pytalloc_guide.txt diff --git a/lib/talloc/pytalloc.h b/lib/talloc/pytalloc.h index 2d2c57b..5c3876e 100644 --- a/lib/talloc/pytalloc.h +++ b/lib/talloc/pytalloc.h @@ -29,7 +29,10 @@ typedef struct { void *ptr; } pytalloc_Object; +/* Return the PyTypeObject for pytalloc_Object. Returns a new reference. */ PyTypeObject *pytalloc_GetObjectType(void); + +/* Check whether a specific object is a talloc Object. */ int pytalloc_Check(PyObject *); /* Retrieve the pointer for a pytalloc_object. Like talloc_get_type() diff --git a/lib/talloc/pytalloc_guide.txt b/lib/talloc/pytalloc_guide.txt new file mode 100644 index 0000000..755a52b --- /dev/null +++ b/lib/talloc/pytalloc_guide.txt @@ -0,0 +1,153 @@ +Using talloc in Samba4 +====================== + +.. contents:: + +Jelmer Vernooij +August 2013 + +The most current version of this document is available at + http://samba.org/ftp/unpacked/talloc/pytalloc_guide.txt + +pytalloc is a small library that provides glue for wrapping +talloc-allocated objects from C in Python objects. + +What is pytalloc, and what is it not? +------------------------------------- + +pytalloc is merely a helper library - it provides a convenient base type object +for objects that wrap talloc-maintained memory in C. It won't write your +bindings for you but it will make it easier to write C bindings that involve +talloc, and take away some of the boiler plate. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +pytalloc_Object + +This is the new base class that all Python objects that wrap talloc pointers +derive from. It is itself a subclass of the "Object" type that all objects +in Python derive from. + +Note that you will almost never create objects of the pytalloc_Object type +itself, as they are just opaque pointers that can not be accessed from +Python. A common pattern is other objects that subclass pytalloc_Object and +rely on it for their memory management. + +Each `pytalloc_Object` wraps two core of information - a talloc context +and a pointer. The pointer is the actual data that is wrapped. The talloc +context is used for memory management purposes only; when the wrapping Python object +goes away, it unlinks the talloc context. The talloc context pointer and the ptr +can (and often do) have the same value. + +Each pytalloc_Object has a custom __repr__ implementation that +describes that it is a talloc object and the location of the +pointer it is wrapping. it also has a custom __cmp__/__eq__/__neq__ method that +compares the pointers the object is wrapping rather than the objects +themselves (since there can be multiple objects that wrap the same talloc +pointer). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyTypeObject *pytalloc_GetObjectType(void) + +Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference +counter for the object will be incremented, so the caller will have to +decrement it when it no longer needs it (using `Py_DECREF`). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=- +int pytalloc_Check(PyObject *) + +Check whether a specific object is a talloc Object. Returns non-zero if it is +a pytalloc_Object and zero otherwise. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +type *pytalloc_get_type(PyObject *py_obj, type) + +Retrieve the pointer from a `pytalloc_Object` py_obj. type should be a +C type, similar to a type passed to `talloc_get_type`. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +pytalloc_get_ptr(PyObject *py_obj) + +Retrieve the pointer from a `pytalloc_Object` py_obj. There is no +type checking - use `pytalloc_get_type` if possible. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj) + +Retrieve the talloc context associated with a pytalloc_Object. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr) + +Create a new Python wrapping object for a talloc pointer and context, with +py_type as associated Python sub type object. + +This will *not* increment the reference counter for the talloc context, +so the caller should make sure such an increment has happened. When the Python +object goes away, it will unreference the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr) + +Create a new Python wrapping object for a talloc pointer and context, with +py_type as associated Python sub type object. + +This will *not* increment the reference counter for the talloc context, +so the caller should make sure such an increment has happened. When the Python +object goes away, it will unreference the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr) + +Create a new Python wrapping object for a talloc pointer and context, with +py_type as associated Python sub type object. + +This will increment the reference counter for the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_reference(PyTypeObject *py_type, void *talloc_ptr) + +Create a new Python wrapping object for a talloc pointer, with +py_type as associated Python sub type object. The pointer will also be used +as the talloc context. + +This will increment the reference counter for the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_new(type, PyTypeObject *typeobj) + +Create a new, empty pytalloc_Object with the specified Python type object. type +should be a C type, similar to talloc_new(). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_CObject_FromTallocPtr(void *); + +Create a new pytalloc_Object for an abitrary talloc-maintained C pointer. This will +use a generic VoidPtr Python type, which just provides an opaque object in +Python. The caller is responsible for incrementing the talloc reference count before calling +this function - it will dereference the talloc pointer when it is garbage collected. + +Debug function for talloc in Python +----------------------------------- + +The "talloc" module in Python provides a couple of functions that can be used +to debug issues with objects wrapped by pytalloc. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +report_full(obj?) + +Print a full report on a specific object or on all allocated objects by Python. +Same behaviour as the `talloc_report_full()` function that is provided by +C talloc. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +enable_null_tracking() + +This enables tracking of the NULL memory context without enabling leak +reporting on exit. Useful for when you want to do your own leak +reporting call via talloc_report_null_full(). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +pytalloc_total_blocks(obj?) + +Return the talloc block count for all allocated objects or a specific object if +specified. -- 1.9.1 From 57a06cd5d630979effcadc63a9e362153f3b3bd3 Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Fri, 4 Apr 2014 13:29:39 +0200 Subject: [PATCH 32/47] talloc: Update flags in pytalloc-util pkgconfig file After exapnding, @LIB_RPATH@ will be -Wl,-rpatch,/usr/local/lib if rpath is used on install. But "-Wl," will be passed to linker and should not be among CFLAGS. Other pkgconfig files have @LIB_RPATH@ in the right place. @see commit 735c1cd2da15167748e92ba6de48fdb5169db587 Signed-off-by: Lukas Slebodnik Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Fri Apr 4 23:50:25 CEST 2014 on sn-devel-104 (cherry picked from commit e1df75b5a965829db0c1f76673dcc824447b3ae7) --- lib/talloc/pytalloc-util.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/talloc/pytalloc-util.pc.in b/lib/talloc/pytalloc-util.pc.in index bc704b4..b7426bb 100644 --- a/lib/talloc/pytalloc-util.pc.in +++ b/lib/talloc/pytalloc-util.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: pytalloc-util Description: Utility functions for using talloc objects with Python Version: @TALLOC_VERSION@ -Libs: -L${libdir} -lpytalloc-util -Cflags: @LIB_RPATH@ -I${includedir} +Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util +Cflags: -I${includedir} URL: http://talloc.samba.org/ -- 1.9.1 From 9d9eb307165938a8c829ebd518434850cc0280a6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 10 Jan 2014 10:45:22 +0100 Subject: [PATCH 33/47] talloc: Tune talloc_vasprintf vsnprintf is significantly more expensive than memcpy. For the common case where the string we print is less than a kilobyte, avoid the second vsnprintf. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu May 15 12:49:14 CEST 2014 on sn-devel-104 (cherry picked from commit 593c8103af5a5ed6b3c915369fed5b90efb42c25) --- lib/talloc/talloc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 1cb4d7d..2a5406e 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -2356,11 +2356,11 @@ _PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) int len; char *ret; va_list ap2; - char c; + char buf[1024]; /* this call looks strange, but it makes it work on older solaris boxes */ va_copy(ap2, ap); - len = vsnprintf(&c, 1, fmt, ap2); + len = vsnprintf(buf, sizeof(buf), fmt, ap2); va_end(ap2); if (unlikely(len < 0)) { return NULL; @@ -2369,9 +2369,13 @@ _PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) ret = (char *)__talloc(t, len+1); if (unlikely(!ret)) return NULL; - va_copy(ap2, ap); - vsnprintf(ret, len+1, fmt, ap2); - va_end(ap2); + if (len < sizeof(buf)) { + memcpy(ret, buf, len+1); + } else { + va_copy(ap2, ap); + vsnprintf(ret, len+1, fmt, ap2); + va_end(ap2); + } _talloc_set_name_const(ret, ret); return ret; -- 1.9.1 From ccad4583abf54bc766e0dd52fd1187a1cb5c4488 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 20 Nov 2013 09:57:58 +0100 Subject: [PATCH 34/47] talloc: inline more static functions We need the code to be as fast as possible. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 3aa35354724b88acc63f6b4439f7203d10db4e90) --- lib/talloc/talloc.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 2a5406e..56ad4f7 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -235,12 +235,14 @@ struct talloc_memlimit { size_t cur_size; }; -static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); -static void talloc_memlimit_grow(struct talloc_memlimit *limit, +static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); +static inline void talloc_memlimit_grow(struct talloc_memlimit *limit, size_t size); -static void talloc_memlimit_shrink(struct talloc_memlimit *limit, +static inline void talloc_memlimit_shrink(struct talloc_memlimit *limit, size_t size); -static void talloc_memlimit_update_on_free(struct talloc_chunk *tc); +static inline void talloc_memlimit_update_on_free(struct talloc_chunk *tc); + +static inline void _talloc_set_name_const(const void *ptr, const char *name); typedef int (*talloc_destructor_t)(void *); @@ -466,41 +468,41 @@ struct talloc_pool_hdr { #define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr)) -static struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c) +static inline struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c) { return (struct talloc_pool_hdr *)((char *)c - TP_HDR_SIZE); } -static struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h) +static inline struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h) { return (struct talloc_chunk *)((char *)h + TP_HDR_SIZE); } -static void *tc_pool_end(struct talloc_pool_hdr *pool_hdr) +static inline void *tc_pool_end(struct talloc_pool_hdr *pool_hdr) { struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); return (char *)tc + TC_HDR_SIZE + pool_hdr->poolsize; } -static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) +static inline size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) { return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end; } /* If tc is inside a pool, this gives the next neighbour. */ -static void *tc_next_chunk(struct talloc_chunk *tc) +static inline void *tc_next_chunk(struct talloc_chunk *tc) { return (char *)tc + TC_ALIGN16(TC_HDR_SIZE + tc->size); } -static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) +static inline void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) { struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); return tc_next_chunk(tc); } /* Mark the whole remaining pool as not accessable */ -static void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) +static inline void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) { size_t flen = tc_pool_space_left(pool_hdr); @@ -517,8 +519,8 @@ static void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) Allocate from a pool */ -static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, - size_t size, size_t prefix_len) +static inline struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, + size_t size, size_t prefix_len) { struct talloc_pool_hdr *pool_hdr = NULL; size_t space_left; @@ -657,7 +659,7 @@ static inline void *__talloc(const void *context, size_t size) * Create a talloc pool */ -_PUBLIC_ void *talloc_pool(const void *context, size_t size) +static inline void *_talloc_pool(const void *context, size_t size) { struct talloc_chunk *tc; struct talloc_pool_hdr *pool_hdr; @@ -684,6 +686,11 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size) return result; } +_PUBLIC_ void *talloc_pool(const void *context, size_t size) +{ + return _talloc_pool(context, size); +} + /* * Create a talloc pool correctly sized for a basic size plus * a number of subobjects whose total size is given. Essentially @@ -727,7 +734,7 @@ _PUBLIC_ void *_talloc_pooled_object(const void *ctx, } poolsize = tmp; - ret = talloc_pool(ctx, poolsize); + ret = _talloc_pool(ctx, poolsize); if (ret == NULL) { return NULL; } @@ -743,7 +750,7 @@ _PUBLIC_ void *_talloc_pooled_object(const void *ctx, pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(type_size)); - talloc_set_name_const(ret, type_name); + _talloc_set_name_const(ret, type_name); return ret; overflow: @@ -1858,7 +1865,7 @@ enum talloc_mem_count_type { TOTAL_MEM_LIMIT, }; -static size_t _talloc_total_mem_internal(const void *ptr, +static inline size_t _talloc_total_mem_internal(const void *ptr, enum talloc_mem_count_type type, struct talloc_memlimit *old_limit, struct talloc_memlimit *new_limit) @@ -2666,7 +2673,7 @@ _PUBLIC_ int talloc_is_parent(const void *context, const void *ptr) /* return the total size of memory used by this context and all children */ -static size_t _talloc_total_limit_size(const void *ptr, +static inline size_t _talloc_total_limit_size(const void *ptr, struct talloc_memlimit *old_limit, struct talloc_memlimit *new_limit) { @@ -2674,7 +2681,7 @@ static size_t _talloc_total_limit_size(const void *ptr, old_limit, new_limit); } -static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) +static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) { struct talloc_memlimit *l; -- 1.9.1 From 900a8dc1b6ee7d6ca5e6a78a0048ffc1483b80bf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Dec 2013 23:22:04 +0100 Subject: [PATCH 35/47] talloc: inline talloc_get_name() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 014eecd0b2aead3a160af0d864feddd53c85b580) --- lib/talloc/talloc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 56ad4f7..3b8cb81 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1355,7 +1355,7 @@ _PUBLIC_ void *talloc_named(const void *context, size_t size, const char *fmt, . /* return the name of a talloc ptr, or "UNNAMED" */ -_PUBLIC_ const char *talloc_get_name(const void *ptr) +static inline const char *__talloc_get_name(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { @@ -1367,6 +1367,10 @@ _PUBLIC_ const char *talloc_get_name(const void *ptr) return "UNNAMED"; } +_PUBLIC_ const char *talloc_get_name(const void *ptr) +{ + return __talloc_get_name(ptr); +} /* check if a pointer has the given name. If it does, return the pointer, @@ -1376,7 +1380,7 @@ _PUBLIC_ void *talloc_check_name(const void *ptr, const char *name) { const char *pname; if (unlikely(ptr == NULL)) return NULL; - pname = talloc_get_name(ptr); + pname = __talloc_get_name(ptr); if (likely(pname == name || strcmp(pname, name) == 0)) { return discard_const_p(void, ptr); } @@ -1410,7 +1414,7 @@ _PUBLIC_ void *_talloc_get_type_abort(const void *ptr, const char *name, const c return NULL; } - pname = talloc_get_name(ptr); + pname = __talloc_get_name(ptr); if (likely(pname == name || strcmp(pname, name) == 0)) { return discard_const_p(void, ptr); } @@ -2028,7 +2032,7 @@ _PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, 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); + const char *name = __talloc_get_name(ptr); struct talloc_chunk *tc; FILE *f = (FILE *)_f; @@ -2628,9 +2632,9 @@ _PUBLIC_ void talloc_show_parents(const void *context, FILE *file) } tc = talloc_chunk_from_ptr(context); - fprintf(file, "talloc parents of '%s'\n", talloc_get_name(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))); + 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; -- 1.9.1 From 2925b6a1c40a47f386304c84b9df408e5642bbe5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Dec 2013 15:35:37 +0100 Subject: [PATCH 36/47] talloc: avoid a function call in TALLOC_FREE() if possible. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit b9fcfc6399eab750880ee0b9806311dd351a8ff6) --- lib/talloc/talloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index 5d29a8d..0d47d23 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -893,7 +893,7 @@ void *_talloc_pooled_object(const void *ctx, * * @param[in] ctx The chunk to be freed. */ -#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0) +#define TALLOC_FREE(ctx) do { if (ctx != NULL) { talloc_free(ctx); ctx=NULL; } } while(0) /* @} ******************************************************************/ -- 1.9.1 From 476d00cb2306bcee00398b1990ac599ee7c5b26b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 5 Dec 2013 08:36:13 +0100 Subject: [PATCH 37/47] talloc: check for TALLOC_GET_TYPE_ABORT_NOOP Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit eb95fc8866dd1710b4cc2f4a4e1dc9867424def2) --- lib/talloc/talloc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h index 0d47d23..5ece54d 100644 --- a/lib/talloc/talloc.h +++ b/lib/talloc/talloc.h @@ -761,7 +761,11 @@ type *talloc_get_type(const void *ptr, #type); */ void *talloc_get_type_abort(const void *ptr, #type); #else +#ifdef TALLOC_GET_TYPE_ABORT_NOOP +#define talloc_get_type_abort(ptr, type) (type *)(ptr) +#else #define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__) +#endif void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location); #endif -- 1.9.1 From ccfe15462922495e7baa550cc49d3d3a6ba18b44 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 20 Nov 2013 09:58:09 +0100 Subject: [PATCH 38/47] talloc: fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids the following warning when using: CFLAGS="-O3 -g -fstrict-overflow -Wstrict-overflow=5" ../talloc.c: In Funktion »talloc_is_parent«: ../talloc.c:2658:21: Warnung: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2 [-Wstrict-overflow] Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit de822b58476093dc43c27577d2f7074541113cc5) --- lib/talloc/talloc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 3b8cb81..fa56ea5 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -2655,7 +2655,10 @@ static int _talloc_is_parent(const void *context, const void *ptr, int depth) } tc = talloc_chunk_from_ptr(context); - while (tc && depth > 0) { + while (tc) { + if (depth <= 0) { + return 0; + } if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; while (tc && tc->prev) tc = tc->prev; if (tc) { -- 1.9.1 From ca5237dbd78440f4b1b5d36220eaf163a1fd82f9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 27 Feb 2014 09:28:02 +0100 Subject: [PATCH 39/47] talloc/tests: avoid some unused variable warnings Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 8fbb81923ddf3449b4ad1fa1a562c9fab8c74103) --- lib/talloc/testsuite.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index 888d260..a878278 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -141,6 +141,7 @@ static bool test_ref1(void) CHECK_BLOCKS("ref1", p1, 5); CHECK_BLOCKS("ref1", p2, 1); + CHECK_BLOCKS("ref1", ref, 1); CHECK_BLOCKS("ref1", r1, 2); fprintf(stderr, "Freeing p2\n"); @@ -249,6 +250,7 @@ static bool test_ref3(void) CHECK_BLOCKS("ref3", p1, 2); CHECK_BLOCKS("ref3", p2, 2); CHECK_BLOCKS("ref3", r1, 1); + CHECK_BLOCKS("ref3", ref, 1); fprintf(stderr, "Freeing p1\n"); talloc_free(p1); @@ -291,6 +293,7 @@ static bool test_ref4(void) CHECK_BLOCKS("ref4", p1, 5); CHECK_BLOCKS("ref4", p2, 1); + CHECK_BLOCKS("ref4", ref, 1); CHECK_BLOCKS("ref4", r1, 2); fprintf(stderr, "Freeing r1\n"); @@ -341,6 +344,7 @@ static bool test_unlink1(void) CHECK_BLOCKS("unlink", p1, 7); CHECK_BLOCKS("unlink", p2, 1); + CHECK_BLOCKS("unlink", ref, 1); CHECK_BLOCKS("unlink", r1, 2); fprintf(stderr, "Unreferencing r1\n"); @@ -409,6 +413,8 @@ static bool test_misc(void) name = talloc_set_name(p1, "my name is %s", "foo"); torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo", "failed: wrong name after talloc_set_name(my name is foo)"); + torture_assert_str_equal("misc", talloc_get_name(p1), name, + "failed: wrong name after talloc_set_name(my name is foo)"); CHECK_BLOCKS("misc", p1, 2); CHECK_BLOCKS("misc", root, 3); @@ -617,6 +623,7 @@ static bool test_realloc_child(void) el2 = talloc(el1->list, struct el2); el2 = talloc(el1->list2, struct el2); el2 = talloc(el1->list3, struct el2); + (void)el2; el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100); el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200); @@ -829,6 +836,8 @@ static bool test_speed(void) p1 = talloc_size(ctx, loop % 100); p2 = talloc_strdup(p1, "foo bar"); p3 = talloc_size(p1, 300); + (void)p2; + (void)p3; talloc_free(p1); } count += 3 * loop; @@ -848,6 +857,8 @@ static bool test_speed(void) p1 = talloc_size(ctx, loop % 100); p2 = talloc_strdup(p1, "foo bar"); p3 = talloc_size(p1, 300); + (void)p2; + (void)p3; talloc_free(p1); } count += 3 * loop; @@ -1380,6 +1391,7 @@ static bool test_free_children(void) root = talloc_new(NULL); p1 = talloc_strdup(root, "foo1"); p2 = talloc_strdup(p1, "foo2"); + (void)p2; talloc_set_name(p1, "%s", "testname"); talloc_free_children(p1); @@ -1404,6 +1416,7 @@ static bool test_free_children(void) name2 = talloc_get_name(p1); /* but this does */ talloc_free_children(p1); + (void)name2; torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname2") == 0, "wrong name"); CHECK_BLOCKS("name1", p1, 1); -- 1.9.1 From 617a5f1320cba411d41fa1664f67ba633e21f271 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 May 2014 14:53:49 +0200 Subject: [PATCH 40/47] talloc: version 2.1.1 Changes: - documentation updates - a fix for pytalloc-util.pc - performance improvements here and there - fixed compiler warnings Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Fri May 16 19:51:26 CEST 2014 on sn-devel-104 (cherry picked from commit b8e5b68de3cff8d16e4be07fdc2e780d2c3c5750) --- lib/talloc/ABI/pytalloc-util-2.1.1.sigs | 6 ++++ lib/talloc/ABI/talloc-2.1.1.sigs | 64 +++++++++++++++++++++++++++++++++ lib/talloc/wscript | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 lib/talloc/ABI/pytalloc-util-2.1.1.sigs create mode 100644 lib/talloc/ABI/talloc-2.1.1.sigs diff --git a/lib/talloc/ABI/pytalloc-util-2.1.1.sigs b/lib/talloc/ABI/pytalloc-util-2.1.1.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.1.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/talloc-2.1.1.sigs b/lib/talloc/ABI/talloc-2.1.1.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.1.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/wscript b/lib/talloc/wscript index 1ca41f6..9df64d9 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'talloc' -VERSION = '2.1.0' +VERSION = '2.1.1' blddir = 'bin' -- 1.9.1 From 57fb19ef597cdf6ddce9b3ed8c6e0c13bb6a0b51 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 20 Jun 2014 18:04:44 +0200 Subject: [PATCH 41/47] talloc:build: improve detection of srcdir Signed-off-by: Michael Adam Reviewed-by: Amitay Isaacs (cherry picked from commit cc86b4107acebf56c7bb17f59dd358615aed57b7) --- lib/talloc/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/talloc/wscript b/lib/talloc/wscript index 9df64d9..986492c 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -12,7 +12,7 @@ import os, sys # find the buildtools directory srcdir = '.' while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5: - srcdir = '../' + srcdir + srcdir = srcdir + '/..' sys.path.insert(0, srcdir + '/buildtools/wafsamba') import sys -- 1.9.1 From 0b702df708b9496ab6408d1bb6a789f44c3bb82b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 5 Mar 2015 12:48:47 -0800 Subject: [PATCH 42/47] lib: talloc: Fix bug when calling a destructor. If the destructor itself calls talloc_set_destructor() and returns -1, the new destructor set is overwritten by talloc. Dectect that and leave the new destructor in place. Signed-off-by: Jeremy Allison Reviewed-by: Ira Cooper (cherry picked from commit 3289a5d84f73bf044e5767a6c47a3f7bf8357c08) --- lib/talloc/talloc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index fa56ea5..1ccb039 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -991,7 +991,13 @@ static inline int _talloc_free_internal(void *ptr, const char *location) } tc->destructor = (talloc_destructor_t)-1; if (d(ptr) == -1) { - tc->destructor = d; + /* + * Only replace the destructor pointer if + * calling the destructor didn't modify it. + */ + if (tc->destructor == (talloc_destructor_t)-1) { + tc->destructor = d; + } return -1; } tc->destructor = NULL; -- 1.9.1 From 024dd8368da2b2e01754f9ca7339a24b47ba0dd7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 3 Mar 2015 17:02:47 -0800 Subject: [PATCH 43/47] lib: talloc: Allow destructors to reparent the object they're called on. If a destructor returns failure (-1) when freeing a child, talloc must then reparent the child. Firstly it tries the owner of any reference, next the parent of the current object calling _talloc_free_children_internal(), and finally the null context in the last resort. If a destructor reparented its own object, which can be a very desirable thing to do (a destructor can make a decision it isn't time to die yet, and as the parent may be going away it might want to move itself to longer-term storage) then this new parent gets overwritten by the existing reparenting logic. This patch checks when freeing a child if it already reparented itself, and if it did doesn't then overwrite the new parent. Makes destructors more flexible. Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke Reviewed-by: Ira Cooper (cherry picked from commit cc4e5481ea060db7f6d8a83619d859b2e002eb90) --- lib/talloc/talloc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 1ccb039..46f10f4 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1470,6 +1470,13 @@ static inline void _talloc_free_children_internal(struct talloc_chunk *tc, if (p) new_parent = TC_PTR_FROM_CHUNK(p); } if (unlikely(_talloc_free_internal(child, location) == -1)) { + if (talloc_parent_chunk(child) != tc) { + /* + * Destructor already reparented this child. + * No further reparenting needed. + */ + return; + } if (new_parent == null_context) { struct talloc_chunk *p = talloc_parent_chunk(ptr); if (p) new_parent = TC_PTR_FROM_CHUNK(p); -- 1.9.1 From 450adcc9a8c539615204d931e5fe52fdf4110091 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 3 Mar 2015 17:12:32 -0800 Subject: [PATCH 44/47] lib: talloc: Test suite for the new destructor reparent logic. Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke Reviewed-by: Ira Cooper Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Sun Mar 8 20:52:43 CET 2015 on sn-devel-104 (cherry picked from commit 6b0cecee1b864a0589836caf9f5f2892f8cb6926) --- lib/talloc/testsuite.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index a878278..eb3e13d 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -981,6 +981,84 @@ static bool test_free_parent_deny_child(void) return true; } +struct new_parent { + void *new_parent; + char val[20]; +}; + +static int reparenting_destructor(struct new_parent *np) +{ + talloc_set_destructor(np, NULL); + (void)talloc_move(np->new_parent, &np); + return -1; +} + +static bool test_free_parent_reparent_child(void) +{ + void *top = talloc_new(NULL); + char *level1; + char *alternate_level1; + char *level2; + struct new_parent *level3; + + printf("test: free_parent_reparent_child\n# " + "TALLOC FREE PARENT REPARENT CHILD\n"); + + level1 = talloc_strdup(top, "level1"); + alternate_level1 = talloc_strdup(top, "alternate_level1"); + level2 = talloc_strdup(level1, "level2"); + level3 = talloc(level2, struct new_parent); + level3->new_parent = alternate_level1; + memset(level3->val, 'x', sizeof(level3->val)); + + talloc_set_destructor(level3, reparenting_destructor); + talloc_free(level1); + + CHECK_PARENT("free_parent_reparent_child", + level3, alternate_level1); + + talloc_free(top); + + printf("success: free_parent_reparent_child\n"); + return true; +} + +static bool test_free_parent_reparent_child_in_pool(void) +{ + void *top = talloc_new(NULL); + char *level1; + char *alternate_level1; + char *level2; + void *pool; + struct new_parent *level3; + + printf("test: free_parent_reparent_child_in_pool\n# " + "TALLOC FREE PARENT REPARENT CHILD IN POOL\n"); + + pool = talloc_pool(top, 1024); + level1 = talloc_strdup(pool, "level1"); + alternate_level1 = talloc_strdup(top, "alternate_level1"); + level2 = talloc_strdup(level1, "level2"); + level3 = talloc(level2, struct new_parent); + level3->new_parent = alternate_level1; + memset(level3->val, 'x', sizeof(level3->val)); + + talloc_set_destructor(level3, reparenting_destructor); + talloc_free(level1); + talloc_set_destructor(level3, NULL); + + CHECK_PARENT("free_parent_reparent_child_in_pool", + level3, alternate_level1); + + /* Even freeing alternate_level1 should leave pool alone. */ + talloc_free(alternate_level1); + talloc_free(top); + + printf("success: free_parent_reparent_child_in_pool\n"); + return true; +} + + static bool test_talloc_ptrtype(void) { void *top = talloc_new(NULL); @@ -1674,6 +1752,10 @@ bool torture_local_talloc(struct torture_context *tctx) test_reset(); ret &= test_free_parent_deny_child(); test_reset(); + ret &= test_free_parent_reparent_child(); + test_reset(); + ret &= test_free_parent_reparent_child_in_pool(); + test_reset(); ret &= test_talloc_ptrtype(); test_reset(); ret &= test_talloc_free_in_destructor(); -- 1.9.1 From c2e19b274bde08392c2326ce89946ab61837a6d5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 27 Jan 2015 13:07:34 +0100 Subject: [PATCH 45/47] talloc: fix _talloc_total_limit_size prototype Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 3929abfc6b5a3ae8a27da57d4dbee9524e3585e3) --- lib/talloc/talloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index 46f10f4..c10fd53 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1064,7 +1064,7 @@ static inline int _talloc_free_internal(void *ptr, const char *location) return 0; } -static size_t _talloc_total_limit_size(const void *ptr, +static inline size_t _talloc_total_limit_size(const void *ptr, struct talloc_memlimit *old_limit, struct talloc_memlimit *new_limit); -- 1.9.1 From 77e8f20e41df54fcbaa7ad56d59d932299052e9f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Mar 2015 09:07:24 +0100 Subject: [PATCH 46/47] talloc: version 2.1.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Allow destructors to reparent the object - Allow destructors to remove itself - Build improvements Signed-off-by: Stefan Metzmacher Reviewed-by: Günther Deschner (cherry picked from commit 7bef5e4f0e5ff4a4187f3d63e51a1725ff32b771) --- lib/talloc/ABI/pytalloc-util-2.1.2.sigs | 6 ++++ lib/talloc/ABI/talloc-2.1.2.sigs | 64 +++++++++++++++++++++++++++++++++ lib/talloc/wscript | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 lib/talloc/ABI/pytalloc-util-2.1.2.sigs create mode 100644 lib/talloc/ABI/talloc-2.1.2.sigs diff --git a/lib/talloc/ABI/pytalloc-util-2.1.2.sigs b/lib/talloc/ABI/pytalloc-util-2.1.2.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.2.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/talloc-2.1.2.sigs b/lib/talloc/ABI/talloc-2.1.2.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.2.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/wscript b/lib/talloc/wscript index 986492c..97c52c3 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'talloc' -VERSION = '2.1.1' +VERSION = '2.1.2' blddir = 'bin' -- 1.9.1 From aa72bd59060f42a979cc9c739484105e055fa74e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 10 Mar 2015 10:51:11 +0100 Subject: [PATCH 47/47] s3:configure: require external talloc >= 2.1.2 Signed-off-by: Stefan Metzmacher --- source3/configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/configure.in b/source3/configure.in index f4403e1..d71d2d6 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -1837,7 +1837,7 @@ AC_ARG_ENABLE(external_libtalloc, if test "x$enable_external_libtalloc" != xno then - PKG_CHECK_MODULES(LIBTALLOC, talloc >= 2.0.1, + PKG_CHECK_MODULES(LIBTALLOC, talloc >= 2.1.2, [ enable_external_libtalloc=yes ], [ if test x$enable_external_libtalloc = xyes; then AC_MSG_ERROR([Unable to find libtalloc]) -- 1.9.1