From: Rusty Russell Date: Wed, 15 Mar 2017 03:40:08 +0000 (+1030) Subject: take: add labels when CCAN_TAKE_DEBUG set, return in taken_any(). X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=cbabfa8c8bd4757091c7fdb566b97388be890a74 take: add labels when CCAN_TAKE_DEBUG set, return in taken_any(). Signed-off-by: Rusty Russell --- diff --git a/ccan/take/_info b/ccan/take/_info index fcb4f318..d013838a 100644 --- a/ccan/take/_info +++ b/ccan/take/_info @@ -53,6 +53,7 @@ int main(int argc, char *argv[]) if (strcmp(argv[1], "depends") == 0) { printf("ccan/likely\n"); + printf("ccan/str\n"); return 0; } diff --git a/ccan/take/take.c b/ccan/take/take.c index 73e5c29d..c628aac0 100644 --- a/ccan/take/take.c +++ b/ccan/take/take.c @@ -1,16 +1,22 @@ /* CC0 (Public domain) - see LICENSE file for details */ #include #include +#include #include #include static const void **takenarr; +static const char **labelarr; static size_t max_taken, num_taken; static size_t allocfail; static void (*allocfailfn)(const void *p); -void *take_(const void *p) +void *take_(const void *p, const char *label) { + /* Overallocate: it's better than risking calloc returning NULL! */ + if (unlikely(label && !labelarr)) + labelarr = calloc(max_taken+1, sizeof(*labelarr)); + if (unlikely(num_taken == max_taken)) { const void **new; @@ -25,9 +31,16 @@ void *take_(const void *p) return (void *)p; } takenarr = new; + /* Once labelarr is set, we maintain it. */ + if (labelarr) + labelarr = realloc(labelarr, + sizeof(*labelarr) * (max_taken+1)); max_taken++; } + if (unlikely(labelarr)) + labelarr[num_taken] = label; takenarr[num_taken++] = p; + return (void *)p; } @@ -68,9 +81,23 @@ bool is_taken(const void *p) return find_taken(p) > 0; } -bool taken_any(void) +const char *taken_any(void) { - return num_taken != 0; + static char pointer_buf[32]; + + if (num_taken == 0) + return NULL; + + /* We're *allowed* to have some with labels, some without. */ + if (labelarr) { + size_t i; + for (i = 0; i < num_taken; i++) + if (labelarr[i]) + return labelarr[i]; + } + + sprintf(pointer_buf, "%p", takenarr[0]); + return pointer_buf; } void take_cleanup(void) @@ -78,6 +105,8 @@ void take_cleanup(void) max_taken = num_taken = 0; free(takenarr); takenarr = NULL; + free(labelarr); + labelarr = NULL; } void take_allocfail(void (*fn)(const void *p)) diff --git a/ccan/take/take.h b/ccan/take/take.h index b6ac4a9f..e0db2902 100644 --- a/ccan/take/take.h +++ b/ccan/take/take.h @@ -3,6 +3,13 @@ #define CCAN_TAKE_H #include "config.h" #include +#include + +#ifdef CCAN_TAKE_DEBUG +#define TAKE_LABEL(p) __FILE__ ":" stringify(__LINE__) ":" stringify(p) +#else +#define TAKE_LABEL(p) NULL +#endif /** * take - record a pointer to be consumed by the function its handed to. @@ -12,7 +19,7 @@ * which is extremely useful for chaining functions. It works on * NULL, for pass-through error handling. */ -#define take(p) (take_typeof(p) take_((p))) +#define take(p) (take_typeof(p) take_((p), TAKE_LABEL(p))) /** * taken - check (and un-take) a pointer was passed with take() @@ -60,7 +67,9 @@ bool is_taken(const void *p); /** * taken_any - are there any taken pointers? * - * Mainly useful for debugging take() leaks. + * Mainly useful for debugging take() leaks. With CCAN_TAKE_DEBUG, returns + * the label where the pointer was passed to take(), otherwise returns + * a static char buffer with the pointer value in it. NULL if none are taken. * * Example: * static void cleanup(void) @@ -68,7 +77,7 @@ bool is_taken(const void *p); * assert(!taken_any()); * } */ -bool taken_any(void); +const char *taken_any(void); /** * take_cleanup - remove all taken pointers from list. @@ -112,5 +121,5 @@ void take_allocfail(void (*fn)(const void *p)); #define take_typeof(ptr) #endif -void *take_(const void *p); +void *take_(const void *p, const char *label); #endif /* CCAN_TAKE_H */ diff --git a/ccan/take/test/run-debug.c b/ccan/take/test/run-debug.c new file mode 100644 index 00000000..a9dda6e2 --- /dev/null +++ b/ccan/take/test/run-debug.c @@ -0,0 +1,34 @@ +#include +#include + +#define CCAN_TAKE_DEBUG 1 +#include +#include +#include + +int main(void) +{ + const char *p = "hi"; + + plan_tests(14); + + /* We can take NULL. */ + ok1(take(NULL) == NULL); + ok1(is_taken(NULL)); + ok1(strstr(taken_any(), "run-debug.c:16:")); + ok1(taken(NULL)); /* Undoes take() */ + ok1(!is_taken(NULL)); + ok1(!taken(NULL)); + ok1(!taken_any()); + + /* We can take a real pointer. */ + ok1(take(p) == p); + ok1(is_taken(p)); + ok1(strends(taken_any(), "run-debug.c:25:p")); + ok1(taken(p)); /* Undoes take() */ + ok1(!is_taken(p)); + ok1(!taken(p)); + ok1(!taken_any()); + + return exit_status(); +}