It may interfere with other at_exit() calls, so let them call it manually.
Also, use memset to zero, which really does make valgrind notice any leaks.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
19 files changed:
static void *(*resizefn)(void *, size_t size) = realloc;
static void (*freefn)(void *) = free;
static void (*errorfn)(const char *msg) = (void *)abort;
static void *(*resizefn)(void *, size_t size) = realloc;
static void (*freefn)(void *) = free;
static void (*errorfn)(const char *msg) = (void *)abort;
-static bool initialized = false;
/* Count on non-destrutor notifiers; often stays zero. */
static size_t notifiers = 0;
/* Count on non-destrutor notifiers; often stays zero. */
static size_t notifiers = 0;
}
/* This means valgrind can see leaks. */
}
/* This means valgrind can see leaks. */
-static void tal_cleanup(void)
- while ((i = list_top(&null_parent.c.children, struct tal_hdr, list)))
+ while ((i = list_top(&null_parent.c.children, struct tal_hdr, list))) {
+ memset(i, 0, sizeof(*i));
+ }
/* Cleanup any taken pointers. */
take_cleanup();
}
/* Cleanup any taken pointers. */
take_cleanup();
}
-/* For allocation failures inside ccan/take */
-static void take_alloc_failed(const void *p)
-{
- tal_free(p);
-}
-
/* We carefully start all real properties with a zero byte. */
static bool is_literal(const struct prop_hdr *prop)
{
/* We carefully start all real properties with a zero byte. */
static bool is_literal(const struct prop_hdr *prop)
{
struct children *children = find_property(parent, CHILDREN);
if (!children) {
struct children *children = find_property(parent, CHILDREN);
if (!children) {
- if (unlikely(!initialized)) {
- atexit(tal_cleanup);
- take_allocfail(take_alloc_failed);
- initialized = true;
- }
children = add_child_property(parent, child);
if (!children)
return false;
children = add_child_property(parent, child);
if (!children)
return false;
tal_expand_((void **)(a1p), (a2), sizeof**(a1p), \
(num2) + 0*sizeof(*(a1p) == (a2)))
tal_expand_((void **)(a1p), (a2), sizeof**(a1p), \
(num2) + 0*sizeof(*(a1p) == (a2)))
+/**
+ * tal_cleanup - remove pointers from NULL node
+ *
+ * Internally, tal keeps a list of nodes allocated from @ctx NULL; this
+ * prevents valgrind from noticing memory leaks. This re-initializes
+ * that list to empty.
+ *
+ * It also calls take_cleanup() for you.
+ */
+void tal_cleanup(void);
+
/**
* tal_check - set the allocation or error functions to use
/**
* tal_check - set the allocation or error functions to use
ok1(err_count == when_to_fail - 1);
tal_free(p);
ok1(err_count == when_to_fail - 1);
tal_free(p);
ok1(tal_first(parent) == NULL);
tal_free(parent);
ok1(tal_first(parent) == NULL);
tal_free(parent);
tal_free(p2);
tal_free(p1);
}
tal_free(p2);
tal_free(p1);
}
tal_free(parent);
ok1(destroy_count == 4);
tal_free(parent);
ok1(destroy_count == 4);
tal_free(p);
ok1(errno == EINVAL);
tal_free(p);
ok1(errno == EINVAL);
/* We can expect some residue from having any child, but limited! */
ok1(num_allocated <= allocated_after_first);
/* We can expect some residue from having any child, but limited! */
ok1(num_allocated <= allocated_after_first);
+ tal_free(p);
+ tal_cleanup();
ok1(*p[i] == '1');
tal_free(p[i]);
}
ok1(*p[i] == '1');
tal_free(p[i]);
}
ok1(strcmp(tal_name(p), __FILE__ ":29:int[]") == 0);
tal_free(p);
ok1(strcmp(tal_name(p), __FILE__ ":29:int[]") == 0);
tal_free(p);
ok1(strcmp(tal_name(p), "int[]") == 0);
tal_free(p);
ok1(strcmp(tal_name(p), "int[]") == 0);
tal_free(p);
tal_del_notifier(new_ctx, resize_notifier);
tal_free(new_ctx);
tal_del_notifier(new_ctx, resize_notifier);
tal_free(new_ctx);
ok1(error_count == 3);
tal_free(origpi);
ok1(error_count == 3);
tal_free(origpi);
ok1(tal_parent(p[4]) == p[0]);
tal_free(p[0]);
ok1(tal_parent(p[4]) == p[0]);
tal_free(p[0]);
ok1(tal_dup(NULL, char, take(c), 5, 5) == NULL);
ok1(!taken_any());
ok1(tal_dup(NULL, char, take(c), 5, 5) == NULL);
ok1(!taken_any());
/* Finally, free the parent. */
tal_free(p);
/* Finally, free the parent. */
tal_free(p);