From f933b8c3246e3fbfe362cb1db73a4ef774725709 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 12 Jan 2009 00:21:39 +1030 Subject: [PATCH] Seriously revisit locking required for antithread. Remove test that never ran properly anyway (still bug in current talloc testsuite). --- ccan/talloc/talloc.c | 135 ++++++++------ ccan/talloc/talloc.h | 29 +-- ccan/talloc/test/run-external-alloc.c | 20 +- ccan/talloc/test/run.c | 251 ++++++++++++++++++-------- 4 files changed, 273 insertions(+), 162 deletions(-) diff --git a/ccan/talloc/talloc.c b/ccan/talloc/talloc.c index 815f255f..1424748e 100644 --- a/ccan/talloc/talloc.c +++ b/ccan/talloc/talloc.c @@ -83,9 +83,8 @@ static void *null_context; static pid_t *autofree_context; static void *(*tc_external_realloc)(const void *parent, void *ptr, size_t size); -static void (*tc_lock)(void *); -static void (*tc_unlock)(void *); -static void *tc_lock_data; +static void (*tc_lock)(const void *ctx); +static void (*tc_unlock)(void); struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; @@ -150,16 +149,27 @@ do { \ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ } while (0) -static inline void lock(void) +static int locked; +static inline void lock(const void *p) { - if (tc_lock) - tc_lock(tc_lock_data); + if (tc_lock && p) { + struct talloc_chunk *tc = talloc_chunk_from_ptr(p); + + if (tc->flags & TALLOC_FLAG_EXT_ALLOC) { + if (locked) + TALLOC_ABORT("nested locking"); + tc_lock(tc); + locked = 1; + } + } } static inline void unlock(void) { - if (tc_lock) - tc_unlock(tc_lock_data); + if (locked) { + tc_unlock(); + locked = 0; + } } /* @@ -179,14 +189,23 @@ static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr) return tc->parent; } -void *talloc_parent(const void *ptr) +/* This version doesn't do locking, so you must already have it. */ +static void *talloc_parent_nolock(const void *ptr) { struct talloc_chunk *tc; - lock(); tc = talloc_parent_chunk(ptr); + return tc ? TC_PTR_FROM_CHUNK(tc) : NULL; +} + +void *talloc_parent(const void *ptr) +{ + void *parent; + + lock(ptr); + parent = talloc_parent_nolock(ptr); unlock(); - return tc? TC_PTR_FROM_CHUNK(tc) : NULL; + return parent; } /* @@ -196,7 +215,7 @@ const char *talloc_parent_name(const void *ptr) { struct talloc_chunk *tc; - lock(); + lock(ptr); tc = talloc_parent_chunk(ptr); unlock(); @@ -346,7 +365,7 @@ void *_talloc_reference(const void *context, const void *ptr) struct talloc_reference_handle *handle; if (unlikely(ptr == NULL)) return NULL; - lock(); + lock(context); tc = talloc_chunk_from_ptr(ptr); handle = (struct talloc_reference_handle *)_talloc_named_const(context, sizeof(struct talloc_reference_handle), @@ -497,7 +516,7 @@ static inline int _talloc_free(void *ptr) } if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) - oldparent = talloc_parent(ptr); + oldparent = talloc_parent_nolock(ptr); if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); @@ -546,7 +565,7 @@ void *_talloc_steal(const void *new_ctx, const void *ptr) { void *p; - lock(); + lock(new_ctx); p = __talloc_steal(new_ctx, ptr); unlock(); return p; @@ -598,7 +617,7 @@ int talloc_unlink(const void *context, void *ptr) context = null_context; } - lock(); + lock(context); if (talloc_unreference(context, ptr) == 0) { unlock(); return 0; @@ -682,7 +701,7 @@ void *talloc_named(const void *context, size_t size, const char *fmt, ...) void *ptr; const char *name; - lock(); + lock(context); ptr = __talloc(context, size); unlock(); if (unlikely(ptr == NULL)) return NULL; @@ -747,9 +766,7 @@ void *talloc_init(const char *fmt, ...) */ talloc_enable_null_tracking(); - lock(); ptr = __talloc(NULL, 0); - unlock(); if (unlikely(ptr == NULL)) return NULL; va_start(ap, fmt); @@ -788,7 +805,7 @@ void talloc_set_name_const(const void *ptr, const char *name) void *talloc_named_const(const void *context, size_t size, const char *name) { void *p; - lock(); + lock(context); p = _talloc_named_const(context, size, name); unlock(); return p; @@ -805,7 +822,8 @@ void *talloc_named_const(const void *context, size_t size, const char *name) int talloc_free(void *ptr) { int saved_errno = errno, ret; - lock(); + + lock(ptr); ret = _talloc_free(ptr); unlock(); if (ret == 0) @@ -846,10 +864,10 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n return NULL; } - lock(); + lock(ptr); if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) { /* need to get parent before setting free flag. */ - void *parent = talloc_parent(ptr); + void *parent = talloc_parent_nolock(ptr); tc->flags |= TALLOC_FLAG_FREE; new_ptr = tc_external_realloc(parent, tc, size + TC_HDR_SIZE); } else { @@ -945,7 +963,7 @@ size_t talloc_total_size(const void *ptr) return 0; } - lock(); + lock(ptr); total = _talloc_total_size(ptr); unlock(); return total; @@ -979,26 +997,34 @@ size_t talloc_total_blocks(const void *ptr) { size_t total; - lock(); + lock(ptr); total = _talloc_total_blocks(ptr); unlock(); return total; } -/* - return the number of external references to a pointer -*/ -size_t talloc_reference_count(const void *ptr) +static size_t _talloc_reference_count(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); struct talloc_reference_handle *h; size_t ret = 0; - lock(); for (h=tc->refs;h;h=h->next) { ret++; } + return ret; +} + +/* + return the number of external references to a pointer +*/ +size_t talloc_reference_count(const void *ptr) +{ + size_t ret; + + lock(talloc_chunk_from_ptr(ptr)); + ret = _talloc_reference_count(ptr); unlock(); return ret; } @@ -1051,7 +1077,7 @@ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, } if (ptr == NULL) return; - lock(); + lock(ptr); _talloc_report_depth_cb(ptr, depth, max_depth, callback, private_data); unlock(); } @@ -1069,17 +1095,17 @@ static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_ if (depth == 0) { fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", (max_depth < 0 ? "full " :""), name, - (unsigned long)talloc_total_size(ptr), - (unsigned long)talloc_total_blocks(ptr)); + (unsigned long)_talloc_total_size(ptr), + (unsigned long)_talloc_total_blocks(ptr)); return; } fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", depth*4, "", name, - (unsigned long)talloc_total_size(ptr), - (unsigned long)talloc_total_blocks(ptr), - (int)talloc_reference_count(ptr), ptr); + (unsigned long)_talloc_total_size(ptr), + (unsigned long)_talloc_total_blocks(ptr), + (int)_talloc_reference_count(ptr), ptr); #if 0 fprintf(f, "content: "); @@ -1149,11 +1175,9 @@ static void talloc_report_null_full(void) */ void talloc_enable_null_tracking(void) { - lock(); if (null_context == NULL) { null_context = _talloc_named_const(NULL, 0, "null_context"); } - unlock(); } /* @@ -1161,10 +1185,8 @@ void talloc_enable_null_tracking(void) */ void talloc_disable_null_tracking(void) { - lock(); _talloc_free(null_context); null_context = NULL; - unlock(); } /* @@ -1192,7 +1214,7 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name) { void *p; - lock(); + lock(ctx); p = _talloc_named_const(ctx, size, name); unlock(); @@ -1210,7 +1232,7 @@ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name { void *newp; - lock(); + lock(t); newp = _talloc_named_const(t, size, name); unlock(); @@ -1273,7 +1295,7 @@ char *talloc_strndup(const void *t, const char *p, size_t n) for (len=0; len= MAX_TALLOC_SIZE/el_size) { return NULL; } - lock(); + lock(ctx); p = _talloc_named_const(ctx, el_size * count, name); unlock(); return p; @@ -1414,9 +1436,7 @@ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } - lock(); p = _talloc_zero(ctx, el_size * count, name); - unlock(); return p; } @@ -1494,7 +1514,7 @@ void *talloc_find_parent_byname(const void *context, const char *name) return NULL; } - lock(); + lock(context); tc = talloc_chunk_from_ptr(context); while (tc) { if (tc->name && strcmp(tc->name, name) == 0) { @@ -1522,7 +1542,7 @@ void talloc_show_parents(const void *context, FILE *file) return; } - lock(); + lock(context); tc = talloc_chunk_from_ptr(context); fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); while (tc) { @@ -1539,19 +1559,20 @@ void talloc_show_parents(const void *context, FILE *file) int talloc_is_parent(const void *context, const void *ptr) { int ret; - lock(); + lock(context); ret = _talloc_is_parent(context, ptr); unlock(); return ret; } void *talloc_add_external(const void *ctx, - void *(*realloc)(const void *, void *, size_t)) + void *(*realloc)(const void *, void *, size_t), + void (*lock)(const void *p), + void (*unlock)(void)) { struct talloc_chunk *tc, *parent; void *p; - lock(); if (tc_external_realloc && tc_external_realloc != realloc) TALLOC_ABORT("talloc_add_external realloc replaced"); tc_external_realloc = realloc; @@ -1564,14 +1585,8 @@ void *talloc_add_external(const void *ctx, tc = tc_external_realloc(ctx, NULL, TC_HDR_SIZE); p = init_talloc(parent, tc, 0, 1); - unlock(); - - return p; -} - -void _talloc_locksafe(void (*lock)(void *), void (*unlock)(void *), void *data) -{ tc_lock = lock; tc_unlock = unlock; - tc_lock_data = data; + + return p; } diff --git a/ccan/talloc/talloc.h b/ccan/talloc/talloc.h index 4efe3b9b..791c98a2 100644 --- a/ccan/talloc/talloc.h +++ b/ccan/talloc/talloc.h @@ -917,6 +917,8 @@ void *talloc_find_parent_byname(const void *ctx, const char *name); * talloc_add_external - create an externally allocated node * @ctx: the parent * @realloc: the realloc() equivalent + * @lock: the call to lock before manipulation of external nodes + * @unlock: the call to unlock after manipulation of external nodes * * talloc_add_external() creates a node which uses a separate allocator. All * children allocated from that node will also use that allocator. @@ -924,29 +926,17 @@ void *talloc_find_parent_byname(const void *ctx, const char *name); * Note: Currently there is only one external allocator, not per-node, * and it is set with this function. * + * @lock is handed a pointer which was previous returned from your realloc + * function; you should use that to figure out which lock to get if you have + * multiple external pools. + * * The parent pointers in realloc is the talloc pointer of the parent, if any. */ void *talloc_add_external(const void *ctx, void *(*realloc)(const void *parent, - void *ptr, size_t)); - -/** - * talloc_locksafe - set locking for talloc on shared memory - * @lock: function to use to lock memory - * @unlock: function to use to unlock memory - * @data: pointer to hand to @lock and @unlock - * - * If talloc is actually dealing with shared memory (threads or shared - * memory using talloc_add_external()) then locking is required on - * allocation and free to avoid corruption. - * - * These hooks allow a very course-grained locking scheme: @lock is - * called before any internal alloc or free, and @unlock is called - * after. */ -#define talloc_locksafe(lock, unlock, data) \ - _talloc_locksafe(typesafe_cb(void, lock, data), \ - typesafe_cb(void, unlock, data), \ - data) + void *ptr, size_t), + void (*lock)(const void *p), + void (*unlock)(void)); /* The following definitions come from talloc.c */ void *_talloc(const void *context, size_t size); @@ -967,6 +957,5 @@ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned void *talloc_realloc_fn(const void *context, void *ptr, size_t size); void talloc_show_parents(const void *context, FILE *file); int talloc_is_parent(const void *context, const void *ptr); -void _talloc_locksafe(void (*lock)(void *), void (*unlock)(void *), void *); #endif /* CCAN_TALLOC_H */ diff --git a/ccan/talloc/test/run-external-alloc.c b/ccan/talloc/test/run-external-alloc.c index fb1e17e9..70f3dacd 100644 --- a/ccan/talloc/test/run-external-alloc.c +++ b/ccan/talloc/test/run-external-alloc.c @@ -2,7 +2,9 @@ #include "tap/tap.h" #include -static int ext_alloc_count, ext_free_count, ext_realloc_count; +/* Much testing already done in run.c */ + +static int ext_alloc_count, ext_free_count, ext_realloc_count, lock_count, unlock_count; static void *expected_parent; static void *ext_realloc(const void *parent, void *ptr, size_t size) @@ -17,13 +19,23 @@ static void *ext_realloc(const void *parent, void *ptr, size_t size) return realloc(ptr, size); } +static void ext_lock(const void *ctx) +{ + lock_count++; +} + +static void ext_unlock(void) +{ + unlock_count++; +} + int main(void) { char *p, *p2, *head; - plan_tests(12); + plan_tests(13); expected_parent = NULL; - head = talloc_add_external(NULL, ext_realloc); + head = talloc_add_external(NULL, ext_realloc, ext_lock, ext_unlock); assert(head); ok1(ext_alloc_count == 1); @@ -50,5 +62,7 @@ int main(void) talloc_free(p); ok1(ext_free_count == 2); + ok1(lock_count == unlock_count); + return exit_status(); } diff --git a/ccan/talloc/test/run.c b/ccan/talloc/test/run.c index 32fe47b5..ad70a51e 100644 --- a/ccan/talloc/test/run.c +++ b/ccan/talloc/test/run.c @@ -30,43 +30,45 @@ #include "tap/tap.h" #define torture_assert(test, expr, str) \ - ok(expr, "failure: %s [\n%s: Expression %s failed: %s\n]\n", \ + ok(expr, "%s [\n%s: Expression %s failed: %s\n]\n", \ test, __location__, #expr, str) #define torture_assert_str_equal(test, arg1, arg2, desc) \ ok(strcmp(arg1, arg2) == 0, \ - "failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \ + "%s [\n%s: Expected %s, got %s: %s\n]\n", \ test, __location__, arg1, arg2, desc) #define CHECK_SIZE(test, ptr, tsize) \ ok(talloc_total_size(ptr) == (tsize), \ - "failed: %s [\nwrong '%s' tree size: got %u expected %u\n]\n", \ + "%s [\nwrong '%s' tree size: got %u expected %u\n]\n", \ test, #ptr, \ (unsigned)talloc_total_size(ptr), \ (unsigned)tsize) #define CHECK_BLOCKS(test, ptr, tblocks) \ ok(talloc_total_blocks(ptr) == (tblocks), \ - "failed: %s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \ + "%s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \ test, #ptr, \ (unsigned)talloc_total_blocks(ptr), \ (unsigned)tblocks) #define CHECK_PARENT(test, ptr, parent) \ ok(talloc_parent(ptr) == (parent), \ - "failed: %s [\n'%s' has wrong parent: got %p expected %p\n]\n", \ + "%s [\n'%s' has wrong parent: got %p expected %p\n]\n", \ test, #ptr, \ talloc_parent(ptr), \ (parent)) +struct torture_context; + /* test references */ -static bool test_ref1(void) +static bool test_ref1(const struct torture_context *ctx) { void *root, *p1, *p2, *ref, *r1; - root = talloc_named_const(NULL, 0, "root"); + root = talloc_named_const(ctx, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); p2 = talloc_named_const(p1, 1, "p2"); talloc_named_const(p1, 1, "x1"); @@ -107,11 +109,11 @@ static bool test_ref1(void) /* test references */ -static bool test_ref2(void) +static bool test_ref2(const struct torture_context *ctx) { void *root, *p1, *p2, *ref, *r1; - root = talloc_named_const(NULL, 0, "root"); + root = talloc_named_const(ctx, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); talloc_named_const(p1, 1, "x1"); talloc_named_const(p1, 1, "x2"); @@ -151,11 +153,11 @@ static bool test_ref2(void) /* test references */ -static bool test_ref3(void) +static bool test_ref3(const struct torture_context *ctx) { void *root, *p1, *p2, *ref, *r1; - root = talloc_named_const(NULL, 0, "root"); + root = talloc_named_const(ctx, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); p2 = talloc_named_const(root, 1, "p2"); r1 = talloc_named_const(p1, 1, "r1"); @@ -182,11 +184,11 @@ static bool test_ref3(void) /* test references */ -static bool test_ref4(void) +static bool test_ref4(const struct torture_context *ctx) { void *root, *p1, *p2, *ref, *r1; - root = talloc_named_const(NULL, 0, "root"); + root = talloc_named_const(ctx, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); talloc_named_const(p1, 1, "x1"); talloc_named_const(p1, 1, "x2"); @@ -222,11 +224,11 @@ static bool test_ref4(void) /* test references */ -static bool test_unlink1(void) +static bool test_unlink1(const struct torture_context *ctx) { void *root, *p1, *p2, *ref, *r1; - root = talloc_named_const(NULL, 0, "root"); + root = talloc_named_const(ctx, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); talloc_named_const(p1, 1, "x1"); talloc_named_const(p1, 1, "x2"); @@ -263,14 +265,14 @@ static int fail_destructor(void *ptr) /* miscellaneous tests to try to get a higher test coverage percentage */ -static bool test_misc(void) +static bool test_misc(const struct torture_context *ctx) { void *root, *p1; char *p2; double *d; const char *name; - root = talloc_new(NULL); + root = talloc_new(ctx); p1 = talloc_size(root, 0x7fffffff); torture_assert("misc", !p1, "failed: large talloc allowed\n"); @@ -404,11 +406,11 @@ static bool test_misc(void) /* test realloc */ -static bool test_realloc(void) +static bool test_realloc(const struct torture_context *ctx) { void *root, *p1, *p2; - root = talloc_new(NULL); + root = talloc_new(ctx); p1 = talloc_size(root, 10); CHECK_SIZE("realloc", p1, 10); @@ -456,7 +458,7 @@ static bool test_realloc(void) /* test realloc with a child */ -static bool test_realloc_child(void) +static bool test_realloc_child(const struct torture_context *ctx) { void *root; struct el2 { @@ -467,7 +469,7 @@ static bool test_realloc_child(void) struct el2 **list, **list2, **list3; } *el1; - root = talloc_new(NULL); + root = talloc_new(ctx); el1 = talloc(root, struct el1); el1->list = talloc(el1, struct el2 *); @@ -498,7 +500,7 @@ static bool test_realloc_child(void) /* test type checking */ -static bool test_type(void) +static bool test_type(const struct torture_context *ctx) { void *root; struct el1 { @@ -509,7 +511,7 @@ static bool test_type(void) }; struct el1 *el1; - root = talloc_new(NULL); + root = talloc_new(ctx); el1 = talloc(root, struct el1); @@ -531,11 +533,11 @@ static bool test_type(void) /* test steal */ -static bool test_steal(void) +static bool test_steal(const struct torture_context *ctx) { void *root, *p1, *p2; - root = talloc_new(NULL); + root = talloc_new(ctx); p1 = talloc_array(root, char, 10); CHECK_SIZE("steal", p1, 10); @@ -579,7 +581,7 @@ static bool test_steal(void) /* test move */ -static bool test_move(void) +static bool test_move(const struct torture_context *ctx) { void *root; struct t_move { @@ -587,7 +589,7 @@ static bool test_move(void) int *x; } *t1, *t2; - root = talloc_new(NULL); + root = talloc_new(ctx); t1 = talloc(root, struct t_move); t2 = talloc(root, struct t_move); @@ -609,11 +611,11 @@ static bool test_move(void) /* test talloc_realloc_fn */ -static bool test_realloc_fn(void) +static bool test_realloc_fn(const struct torture_context *ctx) { void *root, *p1; - root = talloc_new(NULL); + root = talloc_new(ctx); p1 = talloc_realloc_fn(root, NULL, 10); CHECK_BLOCKS("realloc_fn", root, 2); @@ -631,11 +633,11 @@ static bool test_realloc_fn(void) } -static bool test_unref_reparent(void) +static bool test_unref_reparent(const struct torture_context *ctx) { void *root, *p1, *p2, *c1; - root = talloc_named_const(NULL, 0, "root"); + root = talloc_named_const(ctx, 0, "root"); p1 = talloc_named_const(root, 1, "orig parent"); p2 = talloc_named_const(root, 1, "parent by reference"); @@ -658,11 +660,11 @@ static bool test_unref_reparent(void) return true; } -static bool test_lifeless(void) +static bool test_lifeless(const struct torture_context *ctx) { - void *top = talloc_new(NULL); + void *top = talloc_new(ctx); char *parent, *child; - void *child_owner = talloc_new(NULL); + void *child_owner = talloc_new(ctx); parent = talloc_strdup(top, "parent"); child = talloc_strdup(parent, "child"); @@ -685,9 +687,9 @@ static int test_loop_destructor(char *ptr) return 0; } -static bool test_loop(void) +static bool test_loop(const struct torture_context *ctx) { - void *top = talloc_new(NULL); + void *top = talloc_new(ctx); char *parent; struct req1 { char *req2, *req3; @@ -714,9 +716,9 @@ static int fail_destructor_str(char *ptr) return -1; } -static bool test_free_parent_deny_child(void) +static bool test_free_parent_deny_child(const struct torture_context *ctx) { - void *top = talloc_new(NULL); + void *top = talloc_new(ctx); char *level1; char *level2; char *level3; @@ -736,9 +738,9 @@ static bool test_free_parent_deny_child(void) return true; } -static bool test_talloc_ptrtype(void) +static bool test_talloc_ptrtype(const struct torture_context *ctx) { - void *top = talloc_new(NULL); + void *top = talloc_new(ctx); struct struct1 { int foo; int bar; @@ -779,13 +781,15 @@ static bool test_talloc_ptrtype(void) return true; } +static bool test_talloc_free_in_destructor_run; static int _test_talloc_free_in_destructor(void **ptr) { talloc_free(*ptr); + test_talloc_free_in_destructor_run = true; return 0; } -static bool test_talloc_free_in_destructor(void) +static bool test_talloc_free_in_destructor(const struct torture_context *ctx) { void *level0; void *level1; @@ -794,28 +798,32 @@ static bool test_talloc_free_in_destructor(void) void *level4; void **level5; - level0 = talloc_new(NULL); + /* FIXME: Can't do nested destruction with locking, sorry. */ + if (ctx) + return true; + + level0 = talloc_new(ctx); level1 = talloc_new(level0); level2 = talloc_new(level1); level3 = talloc_new(level2); level4 = talloc_new(level3); level5 = talloc(level4, void *); - *level5 = level3; - (void)talloc_reference(level0, level3); - (void)talloc_reference(level3, level3); - (void)talloc_reference(level5, level3); + *level5 = talloc_reference(NULL, level3); + test_talloc_free_in_destructor_run = false; talloc_set_destructor(level5, _test_talloc_free_in_destructor); talloc_free(level1); talloc_free(level0); + ok1(test_talloc_free_in_destructor_run); + return true; } -static bool test_autofree(void) +static bool test_autofree(const struct torture_context *ctx) { /* autofree test would kill smbtorture */ void *p; @@ -828,8 +836,7 @@ static bool test_autofree(void) return true; } -struct torture_context; -static bool torture_local_talloc(struct torture_context *tctx) +static bool torture_local_talloc(const struct torture_context *tctx) { bool ret = true; @@ -838,54 +845,140 @@ static bool torture_local_talloc(struct torture_context *tctx) talloc_disable_null_tracking(); talloc_enable_null_tracking(); - ret &= test_ref1(); - ret &= test_ref2(); - ret &= test_ref3(); - ret &= test_ref4(); - ret &= test_unlink1(); - ret &= test_misc(); - ret &= test_realloc(); - ret &= test_realloc_child(); - ret &= test_steal(); - ret &= test_move(); - ret &= test_unref_reparent(); - ret &= test_realloc_fn(); - ret &= test_type(); - ret &= test_lifeless(); - ret &= test_loop(); - ret &= test_free_parent_deny_child(); - ret &= test_talloc_ptrtype(); - ret &= test_talloc_free_in_destructor(); - ret &= test_autofree(); + ret &= test_ref1(tctx); + ret &= test_ref2(tctx); + ret &= test_ref3(tctx); + ret &= test_ref4(tctx); + ret &= test_unlink1(tctx); + ret &= test_misc(tctx); + ret &= test_realloc(tctx); + ret &= test_realloc_child(tctx); + ret &= test_steal(tctx); + ret &= test_move(tctx); + ret &= test_unref_reparent(tctx); + ret &= test_realloc_fn(tctx); + ret &= test_type(tctx); + ret &= test_lifeless(tctx); + ret &= test_loop(tctx); + ret &= test_free_parent_deny_child(tctx); + ret &= test_talloc_ptrtype(tctx); + ret &= test_talloc_free_in_destructor(tctx); + ret &= test_autofree(tctx); return ret; } -static int lock_failed = 0, unlock_failed = 0; -static void test_lock(int *locked) +static int lock_failed = 0, unlock_failed = 0, lock_bad = 0; +static int locked; + +#define MAX_ALLOCATIONS 100 +static void *allocations[MAX_ALLOCATIONS]; +static int num_allocs, num_frees, num_reallocs; + +static unsigned int find_ptr(const void *p) { - if (*locked) + unsigned int i; + + for (i = 0; i < MAX_ALLOCATIONS; i++) + if (allocations[i] == p) + break; + return i; +} + +static unsigned int allocations_used(void) +{ + unsigned int i, ret = 0; + + for (i = 0; i < MAX_ALLOCATIONS; i++) + if (allocations[i]) + ret++; + return ret; +} + +static void test_lock(const void *ctx) +{ + if (find_ptr(ctx) == MAX_ALLOCATIONS) + lock_bad++; + + if (locked) lock_failed++; - *locked = 1; + locked = 1; } -static void test_unlock(int *locked) +static void test_unlock(void) { - if (!*locked) + if (!locked) unlock_failed++; - *locked = 0; + locked = 0; +} + +static int realloc_called, realloc_bad; + +static void *normal_realloc(const void *parent, void *ptr, size_t size) +{ + unsigned int i = find_ptr(ptr); + + realloc_called++; + if (ptr && size) + num_reallocs++; + else if (ptr) + num_frees++; + else if (size) + num_allocs++; + else + abort(); + + if (i == MAX_ALLOCATIONS) { + if (ptr) { + realloc_bad++; + i = find_ptr(NULL); + } else + abort(); + } + + allocations[i] = realloc(ptr, size); + /* Not guarenteed by realloc. */ + if (!size) + allocations[i] = NULL; + + return allocations[i]; } int main(void) { - int locked = 0; + struct torture_context *ctx; - plan_tests(136); - talloc_locksafe(test_lock, test_unlock, &locked); + plan_tests(284); + ctx = talloc_add_external(NULL, normal_realloc, test_lock, test_unlock); torture_local_talloc(NULL); + ok(!lock_bad, "%u locks on bad pointer", lock_bad); + ok(!lock_failed, "lock_failed count %u should be zero", lock_failed); + ok(!unlock_failed, "unlock_failed count %u should be zero", + unlock_failed); + ok(realloc_called == 1, "our realloc should not be called again"); + + torture_local_talloc(ctx); + ok(!lock_bad, "%u locks on bad pointer", lock_bad); ok(!lock_failed, "lock_failed count %u should be zero", lock_failed); - ok(!unlock_failed, "unlock_failed count %u should be zero", unlock_failed); + ok(!unlock_failed, "unlock_failed count %u should be zero", + unlock_failed); + ok(realloc_called, "our realloc should be called"); + ok(!realloc_bad, "our realloc given unknown pointer %u times", + realloc_bad); + + talloc_free(ctx); + ok(!lock_bad, "%u locks on bad pointer", lock_bad); + ok(!lock_failed, "lock_failed count %u should be zero", lock_failed); + ok(!unlock_failed, "unlock_failed count %u should be zero", + unlock_failed); + ok(realloc_called, "our realloc should be called"); + ok(!realloc_bad, "our realloc given unknown pointer %u times", + realloc_bad); + + ok(allocations_used() == 0, "%u allocations still used?", + allocations_used()); + return exit_status(); } -- 2.39.2