From d904b6e06704fe449c861bae282a2cb185d68751 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:36:23 -0700 Subject: [PATCH 01/37] 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 9ca81454177087c3166fae011499f1cc3d036543 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:43:50 -0700 Subject: [PATCH 02/37] 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 e684b8993082caaf22cfc5de517219f37af2eadb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:46:09 -0700 Subject: [PATCH 03/37] 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 69e80d924f0d5d2a8842ad34c151242ea7c0639e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:49:00 -0700 Subject: [PATCH 04/37] 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 a96bdd421e18d963aec4f491c9c5d2472281acca Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:51:20 -0700 Subject: [PATCH 05/37] 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 5766bd9760dd540814400c91f070236f3d1586ad Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:54:38 -0700 Subject: [PATCH 06/37] 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 888df605ac59a66fe8d63a17b005ac8da4512929 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:57:43 -0700 Subject: [PATCH 07/37] 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 96817ea2db25010aeb5a78f36a6b832c1ec48b67 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 12:59:04 -0700 Subject: [PATCH 08/37] 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 14fd63bff0efc5a510d2b77bf4378cf5b8a96cfe Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:03:27 -0700 Subject: [PATCH 09/37] 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 d2a2a7cb6f08f34bbaad6a434e39248dfcc34fe8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:07:04 -0700 Subject: [PATCH 10/37] 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 3df8fdbe7193322ba8dd996e421ade8841a76fc1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:08:33 -0700 Subject: [PATCH 11/37] 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 27e4daa7dc6509863068a0d006ea550e44ee2655 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:09:03 -0700 Subject: [PATCH 12/37] 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 3b011b2e65c9308ccf0fcae78eb0e4b458f7a420 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Aug 2013 13:20:43 -0700 Subject: [PATCH 13/37] 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 d474e014f883ad6a46e364ce84a40c13448260a1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 10:54:43 -0700 Subject: [PATCH 14/37] 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 5bf2a271e58a12a61d7fe01f1b53bbcd43d41bd4 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 12:18:26 -0700 Subject: [PATCH 15/37] 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 63c44d6d79b10861f0f85b80131d73c44390841f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 14:08:43 -0700 Subject: [PATCH 16/37] 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 5f85abbca1bcf28e575a4057363d6ea2775712a2 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 14:20:20 -0700 Subject: [PATCH 17/37] 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 fa19e66294a2c5c2c4cb443c4a886429ab30d0df Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 14:52:28 -0700 Subject: [PATCH 18/37] 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 85331e2af211fd40e178ec231150c93be4d3b7b7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 15:15:32 -0700 Subject: [PATCH 19/37] 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 544a81e8d7632291c683addda0dc7627cfd33b77 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Sep 2013 15:30:38 -0700 Subject: [PATCH 20/37] 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 7f5e5a8af49158de22b73052bcf9df11594f6c53 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 14 Oct 2013 13:17:12 +0200 Subject: [PATCH 21/37] 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 11a9da40dd8191fe63fbf41d98193e2a16aba04c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 27 Nov 2013 02:12:02 +0000 Subject: [PATCH 22/37] 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 a9e6e0385cfb1d3694f422dd6b65341e4fea13ba Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Fri, 4 Apr 2014 13:29:39 +0200 Subject: [PATCH 23/37] 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 f3ce5c6f0ddc229debb0a1ad573a3d619dfe63df Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 10 Jan 2014 10:45:22 +0100 Subject: [PATCH 24/37] 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 c506efc82bee05ed07bee0b7f9ddb461649274cb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 20 Nov 2013 09:57:58 +0100 Subject: [PATCH 25/37] 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 9146302673766353c7787e22b556bdb85e3a4de2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Dec 2013 23:22:04 +0100 Subject: [PATCH 26/37] 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 270c7316cfdb0e0659f9df84c3aaf15d47644b8a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Dec 2013 15:35:37 +0100 Subject: [PATCH 27/37] 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 beb3026791ef107882ee3c844c1cb6f588697999 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 5 Dec 2013 08:36:13 +0100 Subject: [PATCH 28/37] 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 0f8edd30f852cc04b86509791b6b08b05aea4cb3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 20 Nov 2013 09:58:09 +0100 Subject: [PATCH 29/37] 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 fe7288f02e0f933010541e876e94547aeb479305 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 27 Feb 2014 09:28:02 +0100 Subject: [PATCH 30/37] 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 a00bb5f1fe6b049e96d7f4179306eff48ffd2fda Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 May 2014 14:53:49 +0200 Subject: [PATCH 31/37] 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 0be72c47607393d79cf40608c86a90273409e856 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 20 Jun 2014 18:04:44 +0200 Subject: [PATCH 32/37] 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 d5eee82bf6552d802db9ef6be1478fc1d4d7d6bb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 5 Mar 2015 12:48:47 -0800 Subject: [PATCH 33/37] 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 160dc967c9d9cc0e18cd9755bb8c85e78995e5ee Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 3 Mar 2015 17:02:47 -0800 Subject: [PATCH 34/37] 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 40a066d7d7282c3e4a892f1c40b044680ef047d5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 3 Mar 2015 17:12:32 -0800 Subject: [PATCH 35/37] 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 4b2ec8506b5471ac34e6739a1c9ed4130fef4d59 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 27 Jan 2015 13:07:34 +0100 Subject: [PATCH 36/37] 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 d2fa99a6e13451aa20ddfef893cafd08f3deec79 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Mar 2015 09:07:24 +0100 Subject: [PATCH 37/37] 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