Browse Source

take: add labels when CCAN_TAKE_DEBUG set, return in taken_any().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 9 years ago
parent
commit
cbabfa8c8b
4 changed files with 80 additions and 7 deletions
  1. 1 0
      ccan/take/_info
  2. 32 3
      ccan/take/take.c
  3. 13 4
      ccan/take/take.h
  4. 34 0
      ccan/take/test/run-debug.c

+ 1 - 0
ccan/take/_info

@@ -53,6 +53,7 @@ int main(int argc, char *argv[])
 
 
 	if (strcmp(argv[1], "depends") == 0) {
 	if (strcmp(argv[1], "depends") == 0) {
 		printf("ccan/likely\n");
 		printf("ccan/likely\n");
+		printf("ccan/str\n");
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 32 - 3
ccan/take/take.c

@@ -1,16 +1,22 @@
 /* CC0 (Public domain) - see LICENSE file for details */
 /* CC0 (Public domain) - see LICENSE file for details */
 #include <ccan/take/take.h>
 #include <ccan/take/take.h>
 #include <ccan/likely/likely.h>
 #include <ccan/likely/likely.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
 static const void **takenarr;
 static const void **takenarr;
+static const char **labelarr;
 static size_t max_taken, num_taken;
 static size_t max_taken, num_taken;
 static size_t allocfail;
 static size_t allocfail;
 static void (*allocfailfn)(const void *p);
 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)) {
 	if (unlikely(num_taken == max_taken)) {
 		const void **new;
 		const void **new;
 
 
@@ -25,9 +31,16 @@ void *take_(const void *p)
 			return (void *)p;
 			return (void *)p;
 		}
 		}
 		takenarr = new;
 		takenarr = new;
+		/* Once labelarr is set, we maintain it. */
+		if (labelarr)
+			labelarr = realloc(labelarr,
+					   sizeof(*labelarr) * (max_taken+1));
 		max_taken++;
 		max_taken++;
 	}
 	}
+	if (unlikely(labelarr))
+		labelarr[num_taken] = label;
 	takenarr[num_taken++] = p;
 	takenarr[num_taken++] = p;
+
 	return (void *)p;
 	return (void *)p;
 }
 }
 
 
@@ -68,9 +81,23 @@ bool is_taken(const void *p)
 	return find_taken(p) > 0;
 	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)
 void take_cleanup(void)
@@ -78,6 +105,8 @@ void take_cleanup(void)
 	max_taken = num_taken = 0;
 	max_taken = num_taken = 0;
 	free(takenarr);
 	free(takenarr);
 	takenarr = NULL;
 	takenarr = NULL;
+	free(labelarr);
+	labelarr = NULL;
 }
 }
 
 
 void take_allocfail(void (*fn)(const void *p))
 void take_allocfail(void (*fn)(const void *p))

+ 13 - 4
ccan/take/take.h

@@ -3,6 +3,13 @@
 #define CCAN_TAKE_H
 #define CCAN_TAKE_H
 #include "config.h"
 #include "config.h"
 #include <stdbool.h>
 #include <stdbool.h>
+#include <ccan/str/str.h>
+
+#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.
  * 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
  * which is extremely useful for chaining functions.  It works on
  * NULL, for pass-through error handling.
  * 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()
  * 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?
  * 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:
  * Example:
  *	static void cleanup(void)
  *	static void cleanup(void)
@@ -68,7 +77,7 @@ bool is_taken(const void *p);
  *		assert(!taken_any());
  *		assert(!taken_any());
  *	}
  *	}
  */
  */
-bool taken_any(void);
+const char *taken_any(void);
 
 
 /**
 /**
  * take_cleanup - remove all taken pointers from list.
  * take_cleanup - remove all taken pointers from list.
@@ -112,5 +121,5 @@ void take_allocfail(void (*fn)(const void *p));
 #define take_typeof(ptr)
 #define take_typeof(ptr)
 #endif
 #endif
 
 
-void *take_(const void *p);
+void *take_(const void *p, const char *label);
 #endif /* CCAN_TAKE_H */
 #endif /* CCAN_TAKE_H */

+ 34 - 0
ccan/take/test/run-debug.c

@@ -0,0 +1,34 @@
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define CCAN_TAKE_DEBUG 1
+#include <ccan/take/take.h>
+#include <ccan/take/take.c>
+#include <ccan/tap/tap.h>
+
+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();
+}