Browse Source
These tal submodules got pulled in initially by an overzealous copy. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
27 changed files with 0 additions and 1719 deletions
@ -1 +0,0 @@ |
|||||
../../../licenses/BSD-MIT |
|
@ -1,139 +0,0 @@ |
|||||
#include "config.h" |
|
||||
#include <stdio.h> |
|
||||
#include <string.h> |
|
||||
|
|
||||
/** |
|
||||
* tal/link - link helper for tal |
|
||||
* |
|
||||
* Tal does not support talloc-style references. In the cases where |
|
||||
* an object needs multiple parents, all parents need to be aware of |
|
||||
* the situation; thus tal/link is a helper where all "parents" |
|
||||
* tal_link an object they agree to share ownership of. |
|
||||
* |
|
||||
* Example: |
|
||||
* // Silly program which keeps a cache of uppercased strings. |
|
||||
* // The cache wants to keep strings around even after they may have |
|
||||
* // been "freed" by the caller. |
|
||||
* // Given "hello" outputs "1 cache hits HELLO \n" |
|
||||
* // Given "hello hello there" outputs "4 cache hits HELLO HELLO THERE \n" |
|
||||
* #include <stdio.h> |
|
||||
* #include <err.h> |
|
||||
* #include <string.h> |
|
||||
* #include <ctype.h> |
|
||||
* #include <ccan/tal/link/link.h> |
|
||||
* #include <ccan/tal/str/str.h> |
|
||||
* |
|
||||
* struct upcache { |
|
||||
* const char *str; |
|
||||
* const char *upstr; |
|
||||
* }; |
|
||||
* |
|
||||
* static struct upcache *cache; |
|
||||
* static unsigned int cache_hits = 0; |
|
||||
* #define CACHE_SIZE 4 |
|
||||
* static void init_upcase(void) |
|
||||
* { |
|
||||
* cache = tal_arrz(NULL, struct upcache, CACHE_SIZE); |
|
||||
* } |
|
||||
* |
|
||||
* static struct upcache *lookup_upcase(const char *str) |
|
||||
* { |
|
||||
* unsigned int i; |
|
||||
* for (i = 0; i < CACHE_SIZE; i++) |
|
||||
* if (cache[i].str && !strcmp(cache[i].str, str)) { |
|
||||
* cache_hits++; |
|
||||
* return &cache[i]; |
|
||||
* } |
|
||||
* return NULL; |
|
||||
* } |
|
||||
* |
|
||||
* static struct upcache *new_upcase(const char *str) |
|
||||
* { |
|
||||
* unsigned int i; |
|
||||
* char *upstr; |
|
||||
* |
|
||||
* upstr = tal_linkable(tal_strdup(NULL, str)); |
|
||||
* i = random() % CACHE_SIZE; |
|
||||
* |
|
||||
* // Throw out old: works fine if cache[i].upstr is NULL. |
|
||||
* tal_delink(cache, cache[i].upstr); |
|
||||
* |
|
||||
* // Replace with new. |
|
||||
* cache[i].str = str; |
|
||||
* cache[i].upstr = tal_link(cache, upstr); |
|
||||
* while (*upstr) { |
|
||||
* *upstr = toupper(*upstr); |
|
||||
* upstr++; |
|
||||
* } |
|
||||
* return &cache[i]; |
|
||||
* } |
|
||||
* |
|
||||
* // If you want to keep the result, tal_link it. |
|
||||
* static const char *get_upcase(const char *str) |
|
||||
* { |
|
||||
* struct upcache *uc = lookup_upcase(str); |
|
||||
* if (!uc) |
|
||||
* uc = new_upcase(str); |
|
||||
* if (!uc) |
|
||||
* return NULL; |
|
||||
* return uc->upstr; |
|
||||
* } |
|
||||
* |
|
||||
* static void exit_upcase(void) |
|
||||
* { |
|
||||
* tal_free(cache); |
|
||||
* printf("%u cache hits ", cache_hits); |
|
||||
* } |
|
||||
* |
|
||||
* int main(int argc, char *argv[]) |
|
||||
* { |
|
||||
* unsigned int i; |
|
||||
* const char **values; |
|
||||
* |
|
||||
* // Initialize cache. |
|
||||
* init_upcase(); |
|
||||
* |
|
||||
* // Throw values in. |
|
||||
* values = tal_arr(NULL, const char *, argc); |
|
||||
* for (i = 1; i < argc; i++) |
|
||||
* values[i-1] = tal_link(values, get_upcase(argv[i])); |
|
||||
* |
|
||||
* // This will free all the values, but cache will still work. |
|
||||
* tal_free(values); |
|
||||
* |
|
||||
* // Repeat! |
|
||||
* values = tal_arr(NULL, const char *, argc); |
|
||||
* for (i = 1; i < argc; i++) |
|
||||
* values[i-1] = tal_link(values, get_upcase(argv[i])); |
|
||||
* |
|
||||
* // This will remove cache links, but we still have a link. |
|
||||
* exit_upcase(); |
|
||||
* |
|
||||
* // Show values, so we output something. |
|
||||
* for (i = 0; i < argc - 1; i++) |
|
||||
* printf("%s ", values[i]); |
|
||||
* printf("\n"); |
|
||||
* |
|
||||
* // This will finally free the upcase strings (last link). |
|
||||
* tal_free(values); |
|
||||
* |
|
||||
* return 0; |
|
||||
* } |
|
||||
* |
|
||||
* License: BSD-MIT |
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
|
||||
*/ |
|
||||
int main(int argc, char *argv[]) |
|
||||
{ |
|
||||
if (argc != 2) |
|
||||
return 1; |
|
||||
|
|
||||
if (strcmp(argv[1], "depends") == 0) { |
|
||||
printf("ccan/container_of\n"); |
|
||||
printf("ccan/list\n"); |
|
||||
printf("ccan/tal\n"); |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
return 1; |
|
||||
} |
|
@ -1,105 +0,0 @@ |
|||||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|
||||
#include <ccan/tal/link/link.h> |
|
||||
#include <ccan/container_of/container_of.h> |
|
||||
#include <ccan/list/list.h> |
|
||||
#include <assert.h> |
|
||||
|
|
||||
/* Our linkable parent. */ |
|
||||
struct linkable { |
|
||||
struct list_head links; |
|
||||
}; |
|
||||
|
|
||||
struct link { |
|
||||
struct list_node list; |
|
||||
}; |
|
||||
|
|
||||
static void linkable_notifier(tal_t *linkable, |
|
||||
enum tal_notify_type type, |
|
||||
void *info) |
|
||||
{ |
|
||||
struct linkable *l = tal_parent(linkable); |
|
||||
assert(type == TAL_NOTIFY_STEAL || type == TAL_NOTIFY_FREE); |
|
||||
|
|
||||
/* We let you free it if you haven't linked it yet. */ |
|
||||
if (type == TAL_NOTIFY_FREE && list_empty(&l->links)) { |
|
||||
tal_free(l); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
/* Don't try to steal or free this: it has multiple links! */ |
|
||||
abort(); |
|
||||
} |
|
||||
|
|
||||
void *tal_linkable_(tal_t *newobj) |
|
||||
{ |
|
||||
struct linkable *l; |
|
||||
|
|
||||
/* Must be a fresh object. */ |
|
||||
assert(!tal_parent(newobj)); |
|
||||
|
|
||||
l = tal(NULL, struct linkable); |
|
||||
if (!l) |
|
||||
goto fail; |
|
||||
list_head_init(&l->links); |
|
||||
|
|
||||
if (!tal_steal(l, newobj)) |
|
||||
goto fail; |
|
||||
|
|
||||
if (!tal_add_notifier(newobj, TAL_NOTIFY_STEAL|TAL_NOTIFY_FREE, |
|
||||
linkable_notifier)) { |
|
||||
tal_steal(NULL, newobj); |
|
||||
goto fail; |
|
||||
} |
|
||||
|
|
||||
return (void *)newobj; |
|
||||
|
|
||||
fail: |
|
||||
tal_free(l); |
|
||||
return NULL; |
|
||||
} |
|
||||
|
|
||||
static void destroy_link(struct link *lnk) |
|
||||
{ |
|
||||
struct linkable *l; |
|
||||
|
|
||||
/* Only true if we're first in list! */ |
|
||||
l = container_of(lnk->list.prev, struct linkable, links.n); |
|
||||
|
|
||||
list_del(&lnk->list); |
|
||||
|
|
||||
if (list_empty(&l->links)) |
|
||||
tal_free(l); |
|
||||
} |
|
||||
|
|
||||
void *tal_link_(const tal_t *ctx, const tal_t *link) |
|
||||
{ |
|
||||
struct linkable *l = tal_parent(link); |
|
||||
struct link *lnk = tal(ctx, struct link); |
|
||||
|
|
||||
if (!lnk) |
|
||||
return NULL; |
|
||||
if (!tal_add_destructor(lnk, destroy_link)) { |
|
||||
tal_free(lnk); |
|
||||
return NULL; |
|
||||
} |
|
||||
list_add(&l->links, &lnk->list); |
|
||||
return (void *)link; |
|
||||
} |
|
||||
|
|
||||
void tal_delink_(const tal_t *ctx, const tal_t *link) |
|
||||
{ |
|
||||
struct linkable *l = tal_parent(link); |
|
||||
struct link *i; |
|
||||
|
|
||||
if (!link) |
|
||||
return; |
|
||||
|
|
||||
/* FIXME: slow, but hopefully unusual. */ |
|
||||
list_for_each(&l->links, i, list) { |
|
||||
if (tal_parent(i) == ctx) { |
|
||||
tal_free(i); |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
abort(); |
|
||||
} |
|
@ -1,69 +0,0 @@ |
|||||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|
||||
#ifndef TAL_LINK_H |
|
||||
#define TAL_LINK_H |
|
||||
#include "config.h" |
|
||||
#include <ccan/tal/tal.h> |
|
||||
|
|
||||
/**
|
|
||||
* tal_linkable - set up a tal object to be linkable. |
|
||||
* @newobj - the newly allocated object (with a NULL parent) |
|
||||
* |
|
||||
* The object will be freed when @newobj is freed or the last tal_link() |
|
||||
* is tal_delink'ed. |
|
||||
* |
|
||||
* Returns @newobj or NULL (if an allocation fails). |
|
||||
* |
|
||||
* Example: |
|
||||
* int *shared_count; |
|
||||
* |
|
||||
* shared_count = tal_linkable(talz(NULL, int)); |
|
||||
* assert(shared_count); |
|
||||
*/ |
|
||||
#define tal_linkable(newobj) \ |
|
||||
(tal_typeof(newobj) tal_linkable_((newobj))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_link - add a(nother) link to a linkable object. |
|
||||
* @ctx - the context to link to (parent of the resulting link) |
|
||||
* @obj - the object previously made linkable with tal_linked(). |
|
||||
* |
|
||||
* If @ctx is non-NULL, the link will be a child of @ctx, and this freed |
|
||||
* when @ctx is. |
|
||||
* |
|
||||
* Returns NULL on failure (out of memory). |
|
||||
* |
|
||||
* Example: |
|
||||
* void *my_ctx = NULL; |
|
||||
* |
|
||||
* tal_link(my_ctx, shared_count); |
|
||||
*/ |
|
||||
#if HAVE_STATEMENT_EXPR |
|
||||
/* Weird macro avoids gcc's 'warning: value computed is not used'. */ |
|
||||
#define tal_link(ctx, obj) \ |
|
||||
({ tal_typeof(obj) tal_link_((ctx), (obj)); }) |
|
||||
#else |
|
||||
#define tal_link(ctx, obj) \ |
|
||||
(tal_typeof(obj) tal_link_((ctx), (obj))) |
|
||||
#endif |
|
||||
|
|
||||
/**
|
|
||||
* tal_delink - explicitly remove a link from a linkable object. |
|
||||
* @ctx - the context to link to (parent of the resulting link) |
|
||||
* @obj - the object previously made linkable with tal_linked(). |
|
||||
* |
|
||||
* Explicitly remove a link: normally it is implied by freeing @ctx. |
|
||||
* Removing the last link frees the object. If @obj is NULL, nothing |
|
||||
* is done. |
|
||||
* |
|
||||
* Example: |
|
||||
* tal_delink(my_ctx, shared_count); |
|
||||
*/ |
|
||||
#define tal_delink(ctx, obj) \ |
|
||||
tal_delink_((ctx), (obj)) |
|
||||
|
|
||||
/* Internal helpers. */ |
|
||||
void *tal_linkable_(tal_t *newobj); |
|
||||
void *tal_link_(const tal_t *ctx, const tal_t *dest); |
|
||||
void tal_delink_(const tal_t *ctx, const tal_t *dest); |
|
||||
|
|
||||
#endif /* TAL_LINK_H */ |
|
@ -1,73 +0,0 @@ |
|||||
#include <ccan/tal/link/link.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
#include <stdlib.h> |
|
||||
#include <err.h> |
|
||||
|
|
||||
static unsigned int destroy_count = 0; |
|
||||
static void destroy_obj(void *obj) |
|
||||
{ |
|
||||
destroy_count++; |
|
||||
} |
|
||||
|
|
||||
int main(int argc, char *argv[]) |
|
||||
{ |
|
||||
char *linkable, *p1, *p2, *p3; |
|
||||
void **voidpp; |
|
||||
|
|
||||
plan_tests(23); |
|
||||
|
|
||||
linkable = tal(NULL, char); |
|
||||
ok1(tal_linkable(linkable) == linkable); |
|
||||
ok1(tal_add_destructor(linkable, destroy_obj)); |
|
||||
/* First, free it immediately. */ |
|
||||
tal_free(linkable); |
|
||||
ok1(destroy_count == 1); |
|
||||
|
|
||||
/* Now create and remove a single link. */ |
|
||||
linkable = tal_linkable(tal(NULL, char)); |
|
||||
ok1(tal_add_destructor(linkable, destroy_obj)); |
|
||||
ok1(p1 = tal_link(NULL, linkable)); |
|
||||
ok1(p1 == linkable); |
|
||||
tal_delink(NULL, linkable); |
|
||||
ok1(destroy_count == 2); |
|
||||
|
|
||||
/* Two links.*/ |
|
||||
linkable = tal_linkable(tal(NULL, char)); |
|
||||
ok1(tal_add_destructor(linkable, destroy_obj)); |
|
||||
ok1(p1 = tal_link(NULL, linkable)); |
|
||||
ok1(p1 == linkable); |
|
||||
ok1(p2 = tal_link(NULL, linkable)); |
|
||||
ok1(p2 == linkable); |
|
||||
tal_delink(NULL, linkable); |
|
||||
tal_delink(NULL, linkable); |
|
||||
ok1(destroy_count == 3); |
|
||||
|
|
||||
/* Three links.*/ |
|
||||
linkable = tal_linkable(tal(NULL, char)); |
|
||||
ok1(tal_add_destructor(linkable, destroy_obj)); |
|
||||
ok1(p1 = tal_link(NULL, linkable)); |
|
||||
ok1(p1 == linkable); |
|
||||
ok1(p2 = tal_link(NULL, linkable)); |
|
||||
ok1(p2 == linkable); |
|
||||
ok1(p3 = tal_link(NULL, linkable)); |
|
||||
ok1(p3 == linkable); |
|
||||
tal_delink(NULL, linkable); |
|
||||
tal_delink(NULL, linkable); |
|
||||
tal_delink(NULL, linkable); |
|
||||
ok1(destroy_count == 4); |
|
||||
|
|
||||
/* Now, indirectly. */ |
|
||||
voidpp = tal(NULL, void *); |
|
||||
linkable = tal_linkable(tal(NULL, char)); |
|
||||
ok1(tal_add_destructor(linkable, destroy_obj)); |
|
||||
/* Suppress gratuitous warning with tests_compile_without_features */ |
|
||||
#if HAVE_STATEMENT_EXPR |
|
||||
tal_link(voidpp, linkable); |
|
||||
#else |
|
||||
(void)tal_link(voidpp, linkable); |
|
||||
#endif |
|
||||
tal_free(voidpp); |
|
||||
ok1(destroy_count == 5); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1 +0,0 @@ |
|||||
../../../licenses/BSD-MIT |
|
@ -1,68 +0,0 @@ |
|||||
#include "config.h" |
|
||||
#include <stdio.h> |
|
||||
#include <string.h> |
|
||||
|
|
||||
/** |
|
||||
* tal/stack - stack of tal contextes (inspired by talloc_stack) |
|
||||
* |
|
||||
* Implement a stack of tal contexts. A new (empty) context is pushed on top |
|
||||
* of the stack using tal_newframe and it is popped/freed using tal_free(). |
|
||||
* tal_curframe() can be used to get the stack's top context. |
|
||||
* |
|
||||
* tal_stack can be used to implement per-function temporary allocation context |
|
||||
* to help mitigating memory leaks, but unlike the plain tal approach it does not |
|
||||
* require the caller to pass a destination context for returning allocated |
|
||||
* values. Instead, allocated values are moved to the parent context using |
|
||||
* tal_steal(tal_parent(tmp_ctx), ptr). |
|
||||
* |
|
||||
* Example: |
|
||||
* #include <assert.h> |
|
||||
* #include <ccan/tal/stack/stack.h> |
|
||||
* |
|
||||
* static int *do_work(void) |
|
||||
* { |
|
||||
* int *retval = NULL; |
|
||||
* tal_t *tmp_ctx = tal_newframe(); |
|
||||
* |
|
||||
* int *val = talz(tmp_ctx, int); |
|
||||
* assert(val != NULL); |
|
||||
* |
|
||||
* // ... do something with val ... |
|
||||
* |
|
||||
* if (retval >= 0) { |
|
||||
* // steal to parent cxt so it survives tal_free() |
|
||||
* tal_steal(tal_parent(tmp_ctx), val); |
|
||||
* retval = val; |
|
||||
* } |
|
||||
* tal_free(tmp_ctx); |
|
||||
* return retval; |
|
||||
* } |
|
||||
* |
|
||||
* int main(int argc, char *argv[]) |
|
||||
* { |
|
||||
* tal_t *tmp_ctx = tal_newframe(); |
|
||||
* int *val = do_work(); |
|
||||
* if (val) { |
|
||||
* // ... do something with val ... |
|
||||
* } |
|
||||
* // val is eventually freed |
|
||||
* tal_free(tmp_ctx); |
|
||||
* return 0; |
|
||||
* } |
|
||||
* |
|
||||
* License: BSD-MIT |
|
||||
* Author: Delio Brignoli <brignoli.delio@gmail.com> |
|
||||
*/ |
|
||||
int main(int argc, char *argv[]) |
|
||||
{ |
|
||||
/* Expect exactly one argument */ |
|
||||
if (argc != 2) |
|
||||
return 1; |
|
||||
|
|
||||
if (strcmp(argv[1], "depends") == 0) { |
|
||||
printf("ccan/tal\n"); |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
return 1; |
|
||||
} |
|
@ -1,24 +0,0 @@ |
|||||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|
||||
|
|
||||
#include <ccan/tal/stack/stack.h> |
|
||||
#include <assert.h> |
|
||||
|
|
||||
static tal_t *h = NULL; |
|
||||
|
|
||||
static void _free_frame(tal_t *o) |
|
||||
{ |
|
||||
h = tal_parent(o); |
|
||||
} |
|
||||
|
|
||||
tal_t *tal_newframe_(const char *label) |
|
||||
{ |
|
||||
h = tal_alloc_(h, 0, false, label); |
|
||||
assert(h != NULL); |
|
||||
tal_add_destructor(h, _free_frame); |
|
||||
return h; |
|
||||
} |
|
||||
|
|
||||
tal_t *tal_curframe(void) |
|
||||
{ |
|
||||
return h; |
|
||||
} |
|
@ -1,34 +0,0 @@ |
|||||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|
||||
#ifndef CCAN_TAL_STACK_H |
|
||||
#define CCAN_TAL_STACK_H |
|
||||
|
|
||||
#include <ccan/tal/tal.h> |
|
||||
|
|
||||
/**
|
|
||||
* tal_newframe - allocate and return a new nested tal context |
|
||||
* |
|
||||
* Allocates and push a new tal context on top of the stack. |
|
||||
* The context must be freed using tal_free() which will also pop it |
|
||||
* off the stack, which will also free all its nested contextes, if any. |
|
||||
* |
|
||||
* NOTE: this function is not threadsafe. |
|
||||
* |
|
||||
* Example: |
|
||||
* tal_t *ctx = tal_newframe(); |
|
||||
* // ... do something with ctx ...
|
|
||||
* tal_free(ctx); |
|
||||
*/ |
|
||||
#define tal_newframe(void) tal_newframe_(TAL_LABEL(tal_stack, "")); |
|
||||
|
|
||||
tal_t *tal_newframe_(const char *label); |
|
||||
|
|
||||
/**
|
|
||||
* tal_curframe - return the current 'tal_stack frame' |
|
||||
* |
|
||||
* Returns the context currently on top of the stack. The initial context |
|
||||
* (before any tal_newframe() call) is the tal 'NULL' context. |
|
||||
* |
|
||||
* NOTE: this function is not threadsafe. |
|
||||
*/ |
|
||||
tal_t *tal_curframe(void); |
|
||||
#endif /* CCAN_TAL_STACK_H */ |
|
@ -1,35 +0,0 @@ |
|||||
#include <ccan/tal/stack/stack.h> |
|
||||
#include <ccan/tal/stack/stack.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
tal_t *parent, *cur; |
|
||||
|
|
||||
plan_tests(8); |
|
||||
|
|
||||
/* initial frame is NULL */ |
|
||||
ok1(tal_curframe() == NULL); |
|
||||
|
|
||||
/* create new frame and make sure all is OK */ |
|
||||
cur = tal_newframe(); |
|
||||
ok1(tal_curframe() == cur); |
|
||||
ok1(tal_parent(cur) == NULL); |
|
||||
|
|
||||
/* create another frame */ |
|
||||
parent = cur; |
|
||||
cur = tal_newframe(); |
|
||||
ok1(tal_curframe() == cur); |
|
||||
ok1(tal_parent(cur) == parent); |
|
||||
|
|
||||
/* unwind */ |
|
||||
tal_free(cur); |
|
||||
ok1(tal_curframe() == parent); |
|
||||
cur = tal_curframe(); |
|
||||
ok1(tal_parent(cur) == NULL); |
|
||||
tal_free(cur); |
|
||||
ok1(tal_curframe() == NULL); |
|
||||
|
|
||||
tal_cleanup(); |
|
||||
return exit_status(); |
|
||||
} |
|
@ -1 +0,0 @@ |
|||||
../../../licenses/LGPL-3 |
|
@ -1,43 +0,0 @@ |
|||||
#include "config.h" |
|
||||
#include <stdio.h> |
|
||||
#include <string.h> |
|
||||
|
|
||||
/** |
|
||||
* tal/talloc - an implementation of the tal interface in terms of talloc. |
|
||||
* |
|
||||
* Tal and talloc are both hierarchical allocators, but have different APIs. |
|
||||
* The tal API is mostly a subset of talloc, but if your project already |
|
||||
* uses talloc then having both tal and talloc pointers is confusing, and |
|
||||
* a waste of resources. |
|
||||
* |
|
||||
* The standard convention to tell ccan modules to use this instead of |
|
||||
* ccan/tal is to define TAL_USE_TALLOC, usually on the commandline. |
|
||||
* |
|
||||
* Bugs: |
|
||||
* tal_first() and tal_next() can't be implemented. |
|
||||
* tal_set_backend() can only change the error function. |
|
||||
* |
|
||||
* License: LGPL |
|
||||
*/ |
|
||||
int main(int argc, char *argv[]) |
|
||||
{ |
|
||||
if (argc != 2) |
|
||||
return 1; |
|
||||
|
|
||||
if (strcmp(argv[1], "depends") == 0) { |
|
||||
printf("ccan/take\n"); |
|
||||
printf("ccan/typesafe_cb\n"); |
|
||||
printf("ccan/compiler\n"); |
|
||||
printf("ccan/likely\n"); |
|
||||
printf("ccan/str\n"); |
|
||||
printf("talloc\n"); |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
if (strcmp(argv[1], "libs") == 0) { |
|
||||
printf("talloc\n"); |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
return 1; |
|
||||
} |
|
@ -1,263 +0,0 @@ |
|||||
/* Licensed under LGPL - see LICENSE file for details */ |
|
||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/take/take.h> |
|
||||
#include <errno.h> |
|
||||
#include <assert.h> |
|
||||
|
|
||||
static void (*errorfn)(const char *msg) = (void *)abort; |
|
||||
|
|
||||
static void COLD call_error(const char *msg) |
|
||||
{ |
|
||||
errorfn(msg); |
|
||||
} |
|
||||
|
|
||||
static void *error_on_null(void *p, const char *msg) |
|
||||
{ |
|
||||
if (!p) |
|
||||
call_error(msg); |
|
||||
return p; |
|
||||
} |
|
||||
|
|
||||
void *tal_talloc_(const tal_t *ctx, size_t bytes, bool clear, |
|
||||
const char *label) |
|
||||
{ |
|
||||
void *ret; |
|
||||
|
|
||||
if (clear) |
|
||||
ret = _talloc_zero(ctx, bytes, label); |
|
||||
else |
|
||||
ret = talloc_named_const(ctx, bytes, label); |
|
||||
|
|
||||
return error_on_null(ret, "allocation failure"); |
|
||||
} |
|
||||
|
|
||||
void *tal_talloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear, |
|
||||
const char *label) |
|
||||
{ |
|
||||
void *ret; |
|
||||
|
|
||||
if (clear) |
|
||||
ret = _talloc_zero_array(ctx, bytes, count, label); |
|
||||
else |
|
||||
ret = _talloc_array(ctx, bytes, count, label); |
|
||||
|
|
||||
return error_on_null(ret, "array allocation failure"); |
|
||||
} |
|
||||
|
|
||||
void *tal_talloc_free_(const tal_t *ctx) |
|
||||
{ |
|
||||
int saved_errno = errno; |
|
||||
talloc_free((void *)ctx); |
|
||||
errno = saved_errno; |
|
||||
return NULL; |
|
||||
} |
|
||||
|
|
||||
bool tal_talloc_set_name_(tal_t *ctx, const char *name, bool literal) |
|
||||
{ |
|
||||
if (!literal) { |
|
||||
name = talloc_strdup(ctx, name); |
|
||||
if (!name) { |
|
||||
call_error("set_name allocation failure"); |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
talloc_set_name_const(ctx, name); |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
const char *tal_talloc_name_(const tal_t *ctx) |
|
||||
{ |
|
||||
const char *p = talloc_get_name(ctx); |
|
||||
if (p && unlikely(strcmp(p, "UNNAMED") == 0)) |
|
||||
p = NULL; |
|
||||
return p; |
|
||||
} |
|
||||
|
|
||||
static bool adjust_size(size_t *size, size_t count) |
|
||||
{ |
|
||||
/* Multiplication wrap */ |
|
||||
if (count && unlikely(*size * count / *size != count)) |
|
||||
goto overflow; |
|
||||
|
|
||||
*size *= count; |
|
||||
|
|
||||
/* Make sure we don't wrap adding header. */ |
|
||||
if (*size + 1024 < 1024) |
|
||||
goto overflow; |
|
||||
return true; |
|
||||
overflow: |
|
||||
call_error("allocation size overflow"); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
void *tal_talloc_dup_(const tal_t *ctx, const void *p, size_t size, |
|
||||
size_t n, size_t extra, const char *label) |
|
||||
{ |
|
||||
void *ret; |
|
||||
size_t nbytes = size; |
|
||||
|
|
||||
if (!adjust_size(&nbytes, n)) { |
|
||||
if (taken(p)) |
|
||||
tal_free(p); |
|
||||
return NULL; |
|
||||
} |
|
||||
|
|
||||
/* Beware addition overflow! */ |
|
||||
if (n + extra < n) { |
|
||||
call_error("dup size overflow"); |
|
||||
if (taken(p)) |
|
||||
tal_free(p); |
|
||||
return NULL; |
|
||||
} |
|
||||
|
|
||||
if (taken(p)) { |
|
||||
if (unlikely(!p)) |
|
||||
return NULL; |
|
||||
if (unlikely(!tal_talloc_resize_((void **)&p, size, n + extra))) |
|
||||
return tal_free(p); |
|
||||
if (unlikely(!tal_steal(ctx, p))) |
|
||||
return tal_free(p); |
|
||||
return (void *)p; |
|
||||
} |
|
||||
|
|
||||
ret = tal_talloc_arr_(ctx, size, n + extra, false, label); |
|
||||
if (ret) |
|
||||
memcpy(ret, p, nbytes); |
|
||||
return ret; |
|
||||
} |
|
||||
|
|
||||
bool tal_talloc_resize_(tal_t **ctxp, size_t size, size_t count) |
|
||||
{ |
|
||||
tal_t *newp; |
|
||||
|
|
||||
if (unlikely(count == 0)) { |
|
||||
/* Don't free it! */ |
|
||||
newp = talloc_size(talloc_parent(*ctxp), 0); |
|
||||
if (!newp) { |
|
||||
call_error("Resize failure"); |
|
||||
return false; |
|
||||
} |
|
||||
talloc_free(*ctxp); |
|
||||
*ctxp = newp; |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
/* count is unsigned, not size_t, so check for overflow here! */ |
|
||||
if ((unsigned)count != count) { |
|
||||
call_error("Resize overflos"); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
newp = _talloc_realloc_array(NULL, *ctxp, size, count, NULL); |
|
||||
if (!newp) { |
|
||||
call_error("Resize failure"); |
|
||||
return false; |
|
||||
} |
|
||||
*ctxp = newp; |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
bool tal_talloc_expand_(tal_t **ctxp, const void *src, size_t size, size_t count) |
|
||||
{ |
|
||||
bool ret = false; |
|
||||
size_t old_count = talloc_get_size(*ctxp) / size; |
|
||||
|
|
||||
/* Check for additive overflow */ |
|
||||
if (old_count + count < count) { |
|
||||
call_error("dup size overflow"); |
|
||||
goto out; |
|
||||
} |
|
||||
|
|
||||
/* Don't point src inside thing we're expanding! */ |
|
||||
assert(src < *ctxp |
|
||||
|| (char *)src >= (char *)(*ctxp) + (size * old_count)); |
|
||||
|
|
||||
if (!tal_talloc_resize_(ctxp, size, old_count + count)) |
|
||||
goto out; |
|
||||
|
|
||||
memcpy((char *)*ctxp + size * old_count, src, count * size); |
|
||||
ret = true; |
|
||||
|
|
||||
out: |
|
||||
if (taken(src)) |
|
||||
tal_free(src); |
|
||||
return ret; |
|
||||
} |
|
||||
|
|
||||
/* Sucky inline hash table implementation, to avoid deps. */ |
|
||||
#define HTABLE_BITS 10 |
|
||||
struct destructor { |
|
||||
struct destructor *next; |
|
||||
const tal_t *ctx; |
|
||||
void (*destroy)(void *me); |
|
||||
}; |
|
||||
static struct destructor *destr_hash[1 << HTABLE_BITS]; |
|
||||
|
|
||||
static unsigned int hash_ptr(const void *p) |
|
||||
{ |
|
||||
unsigned long h = (unsigned long)p / sizeof(void *); |
|
||||
|
|
||||
return (h ^ (h >> HTABLE_BITS)) & ((1 << HTABLE_BITS) - 1); |
|
||||
} |
|
||||
|
|
||||
static int tal_talloc_destroy(const tal_t *ctx) |
|
||||
{ |
|
||||
struct destructor **d = &destr_hash[hash_ptr(ctx)]; |
|
||||
while (*d) { |
|
||||
if ((*d)->ctx == ctx) { |
|
||||
struct destructor *this = *d; |
|
||||
this->destroy((void *)ctx); |
|
||||
*d = this->next; |
|
||||
talloc_free(this); |
|
||||
} |
|
||||
} |
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
bool tal_talloc_add_destructor_(const tal_t *ctx, void (*destroy)(void *me)) |
|
||||
{ |
|
||||
struct destructor *d = talloc(ctx, struct destructor); |
|
||||
if (!d) |
|
||||
return false; |
|
||||
|
|
||||
d->next = destr_hash[hash_ptr(ctx)]; |
|
||||
d->ctx = ctx; |
|
||||
d->destroy = destroy; |
|
||||
destr_hash[hash_ptr(ctx)] = d; |
|
||||
talloc_set_destructor(ctx, tal_talloc_destroy); |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
bool tal_talloc_del_destructor_(const tal_t *ctx, void (*destroy)(void *me)) |
|
||||
{ |
|
||||
struct destructor **d = &destr_hash[hash_ptr(ctx)]; |
|
||||
|
|
||||
while (*d) { |
|
||||
if ((*d)->ctx == ctx && (*d)->destroy == destroy) { |
|
||||
struct destructor *this = *d; |
|
||||
*d = this->next; |
|
||||
talloc_free(this); |
|
||||
return true; |
|
||||
} |
|
||||
d = &(*d)->next; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
void tal_talloc_set_backend_(void *(*alloc_fn)(size_t size), |
|
||||
void *(*resize_fn)(void *, size_t size), |
|
||||
void (*free_fn)(void *), |
|
||||
void (*error_fn)(const char *msg)) |
|
||||
{ |
|
||||
assert(!alloc_fn); |
|
||||
assert(!resize_fn); |
|
||||
assert(!free_fn); |
|
||||
errorfn = error_fn; |
|
||||
talloc_set_abort_fn(error_fn); |
|
||||
} |
|
||||
|
|
||||
bool tal_talloc_check_(const tal_t *ctx, const char *errorstr) |
|
||||
{ |
|
||||
/* We can't really check, but this iterates (and may abort). */ |
|
||||
return !ctx || talloc_total_blocks(ctx) >= 1; |
|
||||
} |
|
@ -1,316 +0,0 @@ |
|||||
/* Licensed under LGPL - see LICENSE file for details */ |
|
||||
#ifndef CCAN_TAL_TALLOC_H |
|
||||
#define CCAN_TAL_TALLOC_H |
|
||||
#include "config.h" |
|
||||
#include <ccan/compiler/compiler.h> |
|
||||
#include <ccan/likely/likely.h> |
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h> |
|
||||
#include <ccan/str/str.h> |
|
||||
#include <talloc.h> |
|
||||
#include <stdlib.h> |
|
||||
#include <stdbool.h> |
|
||||
#include <stdarg.h> |
|
||||
|
|
||||
/**
|
|
||||
* tal_t - convenient alias for void to mark tal pointers. |
|
||||
* |
|
||||
* Since any pointer can be a tal-allocated pointer, it's often |
|
||||
* useful to use this typedef to mark them explicitly. |
|
||||
*/ |
|
||||
typedef TALLOC_CTX tal_t; |
|
||||
|
|
||||
/**
|
|
||||
* tal - basic allocator function |
|
||||
* @ctx: NULL, or tal allocated object to be parent. |
|
||||
* @type: the type to allocate. |
|
||||
* |
|
||||
* Allocates a specific type, with a given parent context. The name |
|
||||
* of the object is a string of the type, but if CCAN_TAL_DEBUG is |
|
||||
* defined it also contains the file and line which allocated it. |
|
||||
* |
|
||||
* Example: |
|
||||
* int *p = tal(NULL, int); |
|
||||
* *p = 1; |
|
||||
*/ |
|
||||
#define tal(ctx, type) \ |
|
||||
((type *)tal_talloc_((ctx), sizeof(type), false, \ |
|
||||
TAL_LABEL(type, ""))) |
|
||||
|
|
||||
/**
|
|
||||
* talz - zeroing allocator function |
|
||||
* @ctx: NULL, or tal allocated object to be parent. |
|
||||
* @type: the type to allocate. |
|
||||
* |
|
||||
* Equivalent to tal() followed by memset() to zero. |
|
||||
* |
|
||||
* Example: |
|
||||
* p = talz(NULL, int); |
|
||||
* assert(*p == 0); |
|
||||
*/ |
|
||||
#define talz(ctx, type) \ |
|
||||
((type *)tal_talloc_((ctx), sizeof(type), true, \ |
|
||||
TAL_LABEL(type, ""))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_free - free a tal-allocated pointer. |
|
||||
* @p: NULL, or tal allocated object to free. |
|
||||
* |
|
||||
* This calls the destructors for p (if any), then does the same for all its |
|
||||
* children (recursively) before finally freeing the memory. It returns |
|
||||
* NULL, for convenience. |
|
||||
* |
|
||||
* Note: errno is preserved by this call. |
|
||||
* |
|
||||
* Example: |
|
||||
* p = tal_free(p); |
|
||||
*/ |
|
||||
#define tal_free(p) tal_talloc_free_(p) |
|
||||
|
|
||||
/**
|
|
||||
* tal_arr - allocate an array of objects. |
|
||||
* @ctx: NULL, or tal allocated object to be parent. |
|
||||
* @type: the type to allocate. |
|
||||
* @count: the number to allocate. |
|
||||
* |
|
||||
* Note that an object allocated with tal_arr() has a length property; |
|
||||
* see tal_count(). |
|
||||
* |
|
||||
* Example: |
|
||||
* p = tal_arr(NULL, int, 2); |
|
||||
* p[0] = 0; |
|
||||
* p[1] = 1; |
|
||||
*/ |
|
||||
#define tal_arr(ctx, type, count) \ |
|
||||
((type *)tal_talloc_arr_((ctx), sizeof(type), (count), false, \ |
|
||||
TAL_LABEL(type, "[]"))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_arrz - allocate an array of zeroed objects. |
|
||||
* @ctx: NULL, or tal allocated object to be parent. |
|
||||
* @type: the type to allocate. |
|
||||
* @count: the number to allocate. |
|
||||
* |
|
||||
* Note that an object allocated with tal_arrz() has a length property; |
|
||||
* see tal_count(). |
|
||||
* |
|
||||
* Example: |
|
||||
* p = tal_arrz(NULL, int, 2); |
|
||||
* assert(p[0] == 0 && p[1] == 0); |
|
||||
*/ |
|
||||
#define tal_arrz(ctx, type, count) \ |
|
||||
((type *)tal_talloc_arr_((ctx), sizeof(type), (count), true, \ |
|
||||
TAL_LABEL(type, "[]"))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_resize - enlarge or reduce a tal_arr[z]. |
|
||||
* @p: A pointer to the tal allocated array to resize. |
|
||||
* @count: the number to allocate. |
|
||||
* |
|
||||
* This returns true on success (and may move *@p), or false on failure. |
|
||||
* If @p has a length property, it is updated on success. |
|
||||
* |
|
||||
* Example: |
|
||||
* tal_resize(&p, 100); |
|
||||
*/ |
|
||||
#define tal_resize(p, count) \ |
|
||||
tal_talloc_resize_((void **)(p), sizeof**(p), (count)) |
|
||||
|
|
||||
/**
|
|
||||
* tal_steal - change the parent of a tal-allocated pointer. |
|
||||
* @ctx: The new parent. |
|
||||
* @ptr: The tal allocated object to move. |
|
||||
* |
|
||||
* This may need to perform an allocation, in which case it may fail; thus |
|
||||
* it can return NULL, otherwise returns @ptr. |
|
||||
*/ |
|
||||
#define tal_steal(ctx, ptr) talloc_steal((ctx), (ptr)) |
|
||||
|
|
||||
/**
|
|
||||
* tal_add_destructor - add a callback function when this context is destroyed. |
|
||||
* @ptr: The tal allocated object. |
|
||||
* @function: the function to call before it's freed. |
|
||||
* |
|
||||
* This is a more convenient form of tal_add_notifier(@ptr, |
|
||||
* TAL_NOTIFY_FREE, ...), in that the function prototype takes only @ptr. |
|
||||
*/ |
|
||||
#define tal_add_destructor(ptr, function) \ |
|
||||
tal_talloc_add_destructor_((ptr), typesafe_cb(void, void *, \ |
|
||||
(function), (ptr))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_del_destructor - remove a destructor callback function. |
|
||||
* @ptr: The tal allocated object. |
|
||||
* @function: the function to call before it's freed. |
|
||||
* |
|
||||
* If @function has not been successfully added as a destructor, this returns |
|
||||
* false. |
|
||||
* |
|
||||
* Note: you can't add more than one destructor with the talloc backend! |
|
||||
*/ |
|
||||
#define tal_del_destructor(ptr, function) \ |
|
||||
tal_talloc_del_destructor_((ptr), typesafe_cb(void, void *, \ |
|
||||
(function), (ptr))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_set_name - attach a name to a tal pointer. |
|
||||
* @ptr: The tal allocated object. |
|
||||
* @name: The name to use. |
|
||||
* |
|
||||
* The name is copied, unless we're certain it's a string literal. |
|
||||
*/ |
|
||||
#define tal_set_name(ptr, name) \ |
|
||||
tal_talloc_set_name_((ptr), (name), TAL_TALLOC_IS_LITERAL(name)) |
|
||||
|
|
||||
/**
|
|
||||
* tal_name - get the name for a tal pointer. |
|
||||
* @ptr: The tal allocated object. |
|
||||
* |
|
||||
* Returns NULL if no name has been set. |
|
||||
*/ |
|
||||
#define tal_name(ptr) \ |
|
||||
tal_talloc_name_(ptr) |
|
||||
|
|
||||
/**
|
|
||||
* tal_count - get the count of objects in a tal_arr. |
|
||||
* @ptr: The tal allocated object array. |
|
||||
*/ |
|
||||
#define tal_count(ptr) talloc_array_length(ptr) |
|
||||
|
|
||||
/**
|
|
||||
* tal_parent - get the parent of a tal object. |
|
||||
* @ctx: The tal allocated object. |
|
||||
* |
|
||||
* Returns the parent, which may be NULL. Returns NULL if @ctx is NULL. |
|
||||
*/ |
|
||||
#define tal_parent(ctx) talloc_parent(ctx) |
|
||||
|
|
||||
/**
|
|
||||
* tal_dup - duplicate an object. |
|
||||
* @ctx: The tal allocated object to be parent of the result (may be NULL). |
|
||||
* @type: the type (should match type of @p!) |
|
||||
* @p: the object to copy (or reparented if take()) |
|
||||
*/ |
|
||||
#define tal_dup(ctx, type, p) \ |
|
||||
((type *)tal_talloc_dup_((ctx), tal_talloc_typechk_(p, type *), \ |
|
||||
sizeof(type), 1, 0, \ |
|
||||
TAL_LABEL(type, ""))) |
|
||||
|
|
||||
/**
|
|
||||
* tal_dup_arr - duplicate an array. |
|
||||
* @ctx: The tal allocated object to be parent of the result (may be NULL). |
|
||||
* @type: the type (should match type of @p!) |
|
||||
* @p: the array to copy (or resized & reparented if take()) |
|
||||
* @n: the number of sizeof(type) entries to copy. |
|
||||
* @extra: the number of extra sizeof(type) entries to allocate. |
|
||||
*/ |
|
||||
#define tal_dup_arr(ctx, type, p, n, extra) \ |
|
||||
((type *)tal_talloc_dup_((ctx), tal_talloc_typechk_(p, type *), \ |
|
||||
sizeof(type), (n), (extra), \ |
|
||||
TAL_LABEL(type, "[]"))) |
|
||||
|
|
||||
|
|
||||
/**
|
|
||||
* tal_set_backend - set the allocation or error functions to use |
|
||||
* @alloc_fn: NULL |
|
||||
* @resize_fn: NULL |
|
||||
* @free_fn: NULL |
|
||||
* @error_fn: called on errors or NULL (default is abort) |
|
||||
* |
|
||||
* The defaults are set up so tal functions never return NULL, but you |
|
||||
* can override error_fn to change that. error_fn can return, and is |
|
||||
* called if malloc or realloc fail. |
|
||||
*/ |
|
||||
#define tal_set_backend(alloc_fn, resize_fn, free_fn, error_fn) \ |
|
||||
tal_talloc_set_backend_((alloc_fn), (resize_fn), (free_fn), (error_fn)) |
|
||||
|
|
||||
/**
|
|
||||
* tal_expand - expand a tal array with contents. |
|
||||
* @a1p: a pointer to the tal array to expand. |
|
||||
* @a2: the second array (can be take()). |
|
||||
* @num2: the number of elements in the second array. |
|
||||
* |
|
||||
* Note that *@a1 and @a2 should be the same type. tal_count(@a1) will |
|
||||
* be increased by @num2. |
|
||||
* |
|
||||
* Example: |
|
||||
* int *arr1 = tal_arrz(NULL, int, 2); |
|
||||
* int arr2[2] = { 1, 3 }; |
|
||||
* |
|
||||
* tal_expand(&arr1, arr2, 2); |
|
||||
* assert(tal_count(arr1) == 4); |
|
||||
* assert(arr1[2] == 1); |
|
||||
* assert(arr1[3] == 3); |
|
||||
*/ |
|
||||
#define tal_expand(a1p, a2, num2) \ |
|
||||
tal_talloc_expand_((void **)(a1p), (a2), sizeof**(a1p), \ |
|
||||
(num2) + 0*sizeof(*(a1p) == (a2))) |
|
||||
|
|
||||
|
|
||||
/**
|
|
||||
* tal_check - set the allocation or error functions to use |
|
||||
* @ctx: a tal context, or NULL. |
|
||||
* @errorstr: a string to prepend calls to error_fn, or NULL. |
|
||||
* |
|
||||
* This sanity-checks a tal tree (unless NDEBUG is defined, in which case |
|
||||
* it simply returns true). If errorstr is not null, error_fn is called |
|
||||
* when a problem is found, otherwise it is not. |
|
||||
*/ |
|
||||
#define tal_check(ctx, errorstr) \ |
|
||||
tal_talloc_check_((ctx), (errorstr)) |
|
||||
|
|
||||
|
|
||||
/* Internal support functions */ |
|
||||
#ifndef TAL_TALLOC_LABEL |
|
||||
#ifdef CCAN_TAL_NO_LABELS |
|
||||
#define TAL_LABEL(type, arr) NULL |
|
||||
#else |
|
||||
#ifdef CCAN_TAL_DEBUG |
|
||||
#define TAL_LABEL(type, arr) \ |
|
||||
__FILE__ ":" stringify(__LINE__) ":" stringify(type) arr |
|
||||
#else |
|
||||
#define TAL_LABEL(type, arr) stringify(type) arr |
|
||||
#endif /* CCAN_TAL_DEBUG */ |
|
||||
#endif |
|
||||
#endif |
|
||||
|
|
||||
#if HAVE_BUILTIN_CONSTANT_P |
|
||||
#define TAL_TALLOC_IS_LITERAL(str) __builtin_constant_p(str) |
|
||||
#else |
|
||||
#define TAL_TALLOC_IS_LITERAL(str) false |
|
||||
#endif |
|
||||
|
|
||||
#if HAVE_TYPEOF && HAVE_STATEMENT_EXPR |
|
||||
/* Careful: ptr can be const foo *, ptype is foo *. Also, ptr could
|
|
||||
* be an array, eg "hello". */ |
|
||||
#define tal_talloc_typechk_(ptr, ptype) ({ __typeof__((ptr)+0) _p = (ptype)(ptr); _p; }) |
|
||||
#else |
|
||||
#define tal_talloc_typechk_(ptr, ptype) (ptr) |
|
||||
#endif |
|
||||
|
|
||||
void *tal_talloc_(const tal_t *ctx, size_t bytes, bool clear, |
|
||||
const char *label); |
|
||||
void *tal_talloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear, |
|
||||
const char *label); |
|
||||
void *tal_talloc_free_(const tal_t *ctx); |
|
||||
const char *tal_talloc_name_(const tal_t *ctx); |
|
||||
bool tal_talloc_set_name_(tal_t *ctx, const char *name, bool literal); |
|
||||
|
|
||||
bool tal_talloc_add_destructor_(const tal_t *ctx, void (*destroy)(void *me)); |
|
||||
bool tal_talloc_del_destructor_(const tal_t *ctx, void (*destroy)(void *me)); |
|
||||
|
|
||||
/* ccan/tal/str uses this, so define it. */ |
|
||||
#define tal_dup_(ctx, p, size, n, extra, add_count, label) \ |
|
||||
tal_talloc_dup_((ctx), (p), (size), (n), (extra), (label)) |
|
||||
void *tal_talloc_dup_(const tal_t *ctx, const void *p, size_t size, |
|
||||
size_t n, size_t extra, const char *label); |
|
||||
|
|
||||
bool tal_talloc_resize_(tal_t **ctxp, size_t size, size_t count); |
|
||||
bool tal_talloc_expand_(tal_t **ctxp, const void *src, size_t size, size_t count); |
|
||||
bool tal_talloc_check_(const tal_t *ctx, const char *errorstr); |
|
||||
|
|
||||
void tal_talloc_set_backend_(void *(*alloc_fn)(size_t size), |
|
||||
void *(*resize_fn)(void *, size_t size), |
|
||||
void (*free_fn)(void *), |
|
||||
void (*error_fn)(const char *msg)); |
|
||||
|
|
||||
#endif /* CCAN_TAL_TALLOC_H */ |
|
@ -1,46 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *parent, *c[4]; |
|
||||
int i; |
|
||||
|
|
||||
plan_tests(11); |
|
||||
|
|
||||
parent = tal(NULL, char); |
|
||||
ok1(parent); |
|
||||
|
|
||||
/* Zeroing allocations. */ |
|
||||
for (i = 0; i < 4; i++) { |
|
||||
c[i] = talz(parent, char); |
|
||||
ok1(*c[i] == '\0'); |
|
||||
tal_free(c[i]); |
|
||||
} |
|
||||
|
|
||||
/* Array allocation. */ |
|
||||
for (i = 0; i < 4; i++) { |
|
||||
c[i] = tal_arr(parent, char, 4); |
|
||||
strcpy(c[i], "abc"); |
|
||||
tal_free(c[i]); |
|
||||
} |
|
||||
|
|
||||
/* Zeroing array allocation. */ |
|
||||
for (i = 0; i < 4; i++) { |
|
||||
c[i] = tal_arrz(parent, char, 4); |
|
||||
ok1(!c[i][0] && !c[i][1] && !c[i][2] && !c[i][3]); |
|
||||
strcpy(c[i], "abc"); |
|
||||
tal_free(c[i]); |
|
||||
} |
|
||||
|
|
||||
/* Resizing. */ |
|
||||
c[0] = tal_arrz(parent, char, 4); |
|
||||
ok1(tal_resize(&c[0], 6)); |
|
||||
strcpy(c[0], "hello"); |
|
||||
tal_free(c[0]); |
|
||||
ok1(talloc_total_blocks(parent) == 1); |
|
||||
tal_free(parent); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,33 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *p1, *p2; |
|
||||
|
|
||||
plan_tests(12); |
|
||||
|
|
||||
p1 = tal(NULL, char); |
|
||||
ok1(p1); |
|
||||
ok1(tal_count(p1) == 1); |
|
||||
|
|
||||
p2 = tal_arr(p1, char, 1); |
|
||||
ok1(p2); |
|
||||
ok1(tal_count(p2) == 1); |
|
||||
ok1(tal_resize(&p2, 2)); |
|
||||
ok1(tal_count(p2) == 2); |
|
||||
ok1(tal_check(NULL, NULL)); |
|
||||
tal_free(p2); |
|
||||
|
|
||||
p2 = tal_arrz(p1, char, 7); |
|
||||
ok1(p2); |
|
||||
ok1(tal_count(p2) == 7); |
|
||||
ok1(tal_resize(&p2, 0)); |
|
||||
ok1(tal_count(p2) == 0); |
|
||||
ok1(tal_check(NULL, NULL)); |
|
||||
tal_free(p2); |
|
||||
tal_free(p1); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,67 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
static char *parent, *child; |
|
||||
static int destroy_count; |
|
||||
|
|
||||
/* Parent gets destroyed first. */ |
|
||||
static void destroy_parent(char *p) |
|
||||
{ |
|
||||
ok1(p == parent); |
|
||||
ok1(destroy_count == 0); |
|
||||
/* Can still access child. */ |
|
||||
*child = '1'; |
|
||||
destroy_count++; |
|
||||
} |
|
||||
|
|
||||
static void destroy_child(char *p) |
|
||||
{ |
|
||||
ok1(p == child); |
|
||||
ok1(destroy_count == 1); |
|
||||
/* Can still access parent (though destructor has been called). */ |
|
||||
*parent = '1'; |
|
||||
destroy_count++; |
|
||||
} |
|
||||
|
|
||||
static void destroy_inc(char *p) |
|
||||
{ |
|
||||
destroy_count++; |
|
||||
} |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *child2; |
|
||||
|
|
||||
plan_tests(18); |
|
||||
|
|
||||
destroy_count = 0; |
|
||||
parent = tal(NULL, char); |
|
||||
child = tal(parent, char); |
|
||||
ok1(tal_add_destructor(parent, destroy_parent)); |
|
||||
ok1(tal_add_destructor(child, destroy_child)); |
|
||||
tal_free(parent); |
|
||||
ok1(destroy_count == 2); |
|
||||
|
|
||||
destroy_count = 0; |
|
||||
parent = tal(NULL, char); |
|
||||
child = tal(parent, char); |
|
||||
ok1(tal_add_destructor(parent, destroy_parent)); |
|
||||
ok1(tal_add_destructor(child, destroy_child)); |
|
||||
ok1(tal_del_destructor(child, destroy_child)); |
|
||||
tal_free(parent); |
|
||||
ok1(destroy_count == 1); |
|
||||
|
|
||||
destroy_count = 0; |
|
||||
parent = tal(NULL, char); |
|
||||
child = tal(parent, char); |
|
||||
child2 = tal(parent, char); |
|
||||
ok1(tal_add_destructor(parent, destroy_inc)); |
|
||||
ok1(tal_add_destructor(parent, destroy_inc)); |
|
||||
ok1(tal_add_destructor(child, destroy_inc)); |
|
||||
ok1(tal_add_destructor(child2, destroy_inc)); |
|
||||
tal_free(parent); |
|
||||
ok1(destroy_count == 4); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,35 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
int *a; |
|
||||
const int arr[] = { 1, 2 }; |
|
||||
|
|
||||
plan_tests(14); |
|
||||
talloc_enable_null_tracking_no_autofree(); |
|
||||
|
|
||||
a = tal_arrz(NULL, int, 1); |
|
||||
ok1(a); |
|
||||
|
|
||||
ok1(tal_expand(&a, arr, 2)); |
|
||||
ok1(tal_count(a) == 3); |
|
||||
ok1(a[0] == 0); |
|
||||
ok1(a[1] == 1); |
|
||||
ok1(a[2] == 2); |
|
||||
|
|
||||
ok1(tal_expand(&a, take(tal_arrz(NULL, int, 1)), 1)); |
|
||||
ok1(tal_count(a) == 4); |
|
||||
ok1(a[0] == 0); |
|
||||
ok1(a[1] == 1); |
|
||||
ok1(a[2] == 2); |
|
||||
ok1(a[3] == 0); |
|
||||
ok1(talloc_total_blocks(NULL) == 2); |
|
||||
ok1(talloc_total_blocks(a) == 1); |
|
||||
|
|
||||
tal_free(a); |
|
||||
|
|
||||
talloc_disable_null_tracking(); |
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,26 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
#include <errno.h> |
|
||||
|
|
||||
static void destroy_errno(char *p) |
|
||||
{ |
|
||||
errno = ENOENT; |
|
||||
} |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *p; |
|
||||
|
|
||||
plan_tests(2); |
|
||||
|
|
||||
p = tal(NULL, char); |
|
||||
ok1(tal_add_destructor(p, destroy_errno)); |
|
||||
|
|
||||
/* Errno save/restored across free. */ |
|
||||
errno = EINVAL; |
|
||||
tal_free(p); |
|
||||
ok1(errno == EINVAL); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,34 +0,0 @@ |
|||||
#define CCAN_TAL_DEBUG |
|
||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
int *p; |
|
||||
char name[] = "test name"; |
|
||||
|
|
||||
plan_tests(6); |
|
||||
|
|
||||
p = tal(NULL, int); |
|
||||
ok1(strcmp(tal_name(p), __FILE__ ":13:int") == 0); |
|
||||
|
|
||||
tal_set_name(p, "some literal"); |
|
||||
ok1(strcmp(tal_name(p), "some literal") == 0); |
|
||||
|
|
||||
tal_set_name(p, name); |
|
||||
ok1(strcmp(tal_name(p), name) == 0); |
|
||||
/* You can't reuse my pointer though! */ |
|
||||
ok1(tal_name(p) != name); |
|
||||
|
|
||||
tal_set_name(p, "some other literal"); |
|
||||
ok1(strcmp(tal_name(p), "some other literal") == 0); |
|
||||
|
|
||||
tal_free(p); |
|
||||
|
|
||||
p = tal_arr(NULL, int, 2); |
|
||||
ok1(strcmp(tal_name(p), __FILE__ ":29:int[]") == 0); |
|
||||
tal_free(p); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,30 +0,0 @@ |
|||||
#define CCAN_TAL_NO_LABELS |
|
||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
int *p; |
|
||||
char name[] = "test name"; |
|
||||
|
|
||||
plan_tests(5); |
|
||||
|
|
||||
p = tal(NULL, int); |
|
||||
ok1(tal_name(p) == NULL); |
|
||||
|
|
||||
tal_set_name(p, "some literal"); |
|
||||
ok1(strcmp(tal_name(p), "some literal") == 0); |
|
||||
|
|
||||
tal_set_name(p, name); |
|
||||
ok1(strcmp(tal_name(p), name) == 0); |
|
||||
/* You can't reuse my pointer though! */ |
|
||||
ok1(tal_name(p) != name); |
|
||||
|
|
||||
tal_set_name(p, "some other literal"); |
|
||||
ok1(strcmp(tal_name(p), "some other literal") == 0); |
|
||||
|
|
||||
tal_free(p); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,33 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
int *p; |
|
||||
char name[] = "test name"; |
|
||||
|
|
||||
plan_tests(6); |
|
||||
|
|
||||
p = tal(NULL, int); |
|
||||
ok1(strcmp(tal_name(p), "int") == 0); |
|
||||
|
|
||||
tal_set_name(p, "some literal"); |
|
||||
ok1(strcmp(tal_name(p), "some literal") == 0); |
|
||||
|
|
||||
tal_set_name(p, name); |
|
||||
ok1(strcmp(tal_name(p), name) == 0); |
|
||||
/* You can't reuse my pointer though! */ |
|
||||
ok1(tal_name(p) != name); |
|
||||
|
|
||||
tal_set_name(p, "some other literal"); |
|
||||
ok1(strcmp(tal_name(p), "some other literal") == 0); |
|
||||
|
|
||||
tal_free(p); |
|
||||
|
|
||||
p = tal_arr(NULL, int, 2); |
|
||||
ok1(strcmp(tal_name(p), "int[]") == 0); |
|
||||
tal_free(p); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,100 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
static int error_count; |
|
||||
|
|
||||
static void my_error(const char *msg) |
|
||||
{ |
|
||||
error_count++; |
|
||||
} |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
void *p; |
|
||||
int *pi, *origpi; |
|
||||
char *cp; |
|
||||
|
|
||||
plan_tests(30); |
|
||||
|
|
||||
tal_set_backend(NULL, NULL, NULL, my_error); |
|
||||
talloc_enable_null_tracking_no_autofree(); |
|
||||
|
|
||||
p = tal_arr(NULL, int, (size_t)-1); |
|
||||
ok1(!p); |
|
||||
ok1(error_count == 1); |
|
||||
|
|
||||
p = tal_arr(NULL, char, (size_t)-2); |
|
||||
ok1(!p); |
|
||||
ok1(error_count == 2); |
|
||||
|
|
||||
/* Now try overflow cases for tal_dup. */ |
|
||||
error_count = 0; |
|
||||
origpi = tal_arr(NULL, int, 100); |
|
||||
ok1(origpi); |
|
||||
ok1(error_count == 0); |
|
||||
pi = tal_dup_arr(NULL, int, origpi, (size_t)-1, 0); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 1); |
|
||||
pi = tal_dup_arr(NULL, int, origpi, 0, (size_t)-1); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 2); |
|
||||
|
|
||||
pi = tal_dup_arr(NULL, int, origpi, (size_t)-1UL / sizeof(int), |
|
||||
(size_t)-1UL / sizeof(int)); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 3); |
|
||||
/* This will still overflow when tal_hdr is added. */ |
|
||||
pi = tal_dup_arr(NULL, int, origpi, (size_t)-1UL / sizeof(int) / 2, |
|
||||
(size_t)-1UL / sizeof(int) / 2); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 4); |
|
||||
ok1(talloc_total_blocks(NULL) == 2); |
|
||||
tal_free(origpi); |
|
||||
|
|
||||
/* Now, check that with taltk() we free old one on failure. */ |
|
||||
origpi = tal_arr(NULL, int, 100); |
|
||||
error_count = 0; |
|
||||
pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1, 0); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 1); |
|
||||
|
|
||||
origpi = tal_arr(NULL, int, 100); |
|
||||
error_count = 0; |
|
||||
pi = tal_dup_arr(NULL, int, take(origpi), 0, (size_t)-1); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 1); |
|
||||
ok1(talloc_total_blocks(NULL) == 1); |
|
||||
|
|
||||
origpi = tal_arr(NULL, int, 100); |
|
||||
error_count = 0; |
|
||||
pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1UL / sizeof(int), |
|
||||
(size_t)-1UL / sizeof(int)); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 1); |
|
||||
ok1(talloc_total_blocks(NULL) == 1); |
|
||||
|
|
||||
origpi = tal_arr(NULL, int, 100); |
|
||||
error_count = 0; |
|
||||
/* This will still overflow when tal_hdr is added. */ |
|
||||
pi = tal_dup_arr(NULL, int, take(origpi), (size_t)-1UL / sizeof(int) / 2, |
|
||||
(size_t)-1UL / sizeof(int) / 2); |
|
||||
ok1(!pi); |
|
||||
ok1(error_count == 1); |
|
||||
ok1(talloc_total_blocks(NULL) == 1); |
|
||||
|
|
||||
/* Overflow on expand addition. */ |
|
||||
cp = tal_arr(p, char, 100); |
|
||||
ok1(!tal_expand(&cp, NULL, (size_t)-99UL)); |
|
||||
ok1(error_count == 2); |
|
||||
tal_free(cp); |
|
||||
|
|
||||
/* Overflow when multiplied by size */ |
|
||||
origpi = tal_arr(NULL, int, 100); |
|
||||
ok1(!tal_expand(&origpi, NULL, (size_t)-1UL / sizeof(int))); |
|
||||
ok1(error_count == 3); |
|
||||
tal_free(origpi); |
|
||||
|
|
||||
talloc_disable_null_tracking(); |
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,40 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *p[5]; |
|
||||
unsigned int i; |
|
||||
|
|
||||
plan_tests(9); |
|
||||
|
|
||||
p[0] = tal(NULL, char); |
|
||||
for (i = 1; i < 5; i++) |
|
||||
p[i] = tal(p[i-1], char); |
|
||||
|
|
||||
tal_check(NULL, "check"); |
|
||||
/* Steal node with no children. */ |
|
||||
ok1(tal_steal(p[0], p[4]) == p[4]); |
|
||||
tal_check(NULL, "check"); |
|
||||
/* Noop steal. */ |
|
||||
ok1(tal_steal(p[0], p[4]) == p[4]); |
|
||||
tal_check(NULL, "check"); |
|
||||
/* Steal with children. */ |
|
||||
ok1(tal_steal(p[0], p[1]) == p[1]); |
|
||||
tal_check(NULL, "check"); |
|
||||
/* Noop steal. */ |
|
||||
ok1(tal_steal(p[0], p[1]) == p[1]); |
|
||||
tal_check(NULL, "check"); |
|
||||
/* Steal from direct child. */ |
|
||||
ok1(tal_steal(p[0], p[2]) == p[2]); |
|
||||
tal_check(NULL, "check"); |
|
||||
|
|
||||
ok1(tal_parent(p[1]) == p[0]); |
|
||||
ok1(tal_parent(p[2]) == p[0]); |
|
||||
ok1(tal_parent(p[3]) == p[2]); |
|
||||
ok1(tal_parent(p[4]) == p[0]); |
|
||||
tal_free(p[0]); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,56 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *parent, *c; |
|
||||
|
|
||||
plan_tests(21); |
|
||||
|
|
||||
/* We can take NULL. */ |
|
||||
ok1(take(NULL) == NULL); |
|
||||
ok1(is_taken(NULL)); |
|
||||
ok1(taken(NULL)); /* Undoes take() */ |
|
||||
ok1(!is_taken(NULL)); |
|
||||
ok1(!taken(NULL)); |
|
||||
|
|
||||
parent = tal(NULL, char); |
|
||||
ok1(parent); |
|
||||
|
|
||||
ok1(take(parent) == parent); |
|
||||
ok1(is_taken(parent)); |
|
||||
ok1(taken(parent)); /* Undoes take() */ |
|
||||
ok1(!is_taken(parent)); |
|
||||
ok1(!taken(parent)); |
|
||||
|
|
||||
c = tal(parent, char); |
|
||||
*c = 'h'; |
|
||||
c = tal_dup(parent, char, take(c)); |
|
||||
ok1(c[0] == 'h'); |
|
||||
ok1(tal_parent(c) == parent); |
|
||||
|
|
||||
c = tal_dup_arr(parent, char, take(c), 1, 2); |
|
||||
ok1(c[0] == 'h'); |
|
||||
strcpy(c, "hi"); |
|
||||
ok1(tal_parent(c) == parent); |
|
||||
|
|
||||
/* dup must reparent child. */ |
|
||||
c = tal_dup(NULL, char, take(c)); |
|
||||
ok1(c[0] == 'h'); |
|
||||
ok1(tal_parent(c) == NULL); |
|
||||
|
|
||||
/* No leftover allocations. */ |
|
||||
tal_free(c); |
|
||||
ok1(talloc_total_blocks(parent) == 1); |
|
||||
|
|
||||
tal_free(parent); |
|
||||
ok1(!taken_any()); |
|
||||
|
|
||||
/* NULL pass-through. */ |
|
||||
c = NULL; |
|
||||
ok1(tal_dup_arr(NULL, char, take(c), 5, 5) == NULL); |
|
||||
ok1(!taken_any()); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
@ -1,44 +0,0 @@ |
|||||
#include <ccan/tal/talloc/talloc.h> |
|
||||
#include <ccan/tal/talloc/talloc.c> |
|
||||
#include <ccan/tap/tap.h> |
|
||||
|
|
||||
int main(void) |
|
||||
{ |
|
||||
char *parent, *c[4]; |
|
||||
int i, j; |
|
||||
|
|
||||
plan_tests(9); |
|
||||
|
|
||||
/* tal_free(NULL) works. */ |
|
||||
ok1(tal_free(NULL) == NULL); |
|
||||
|
|
||||
parent = tal(NULL, char); |
|
||||
ok1(parent); |
|
||||
ok1(tal_parent(parent) == NULL); |
|
||||
ok1(tal_parent(NULL) == NULL); |
|
||||
|
|
||||
for (i = 0; i < 4; i++) |
|
||||
c[i] = tal(parent, char); |
|
||||
|
|
||||
for (i = 0; i < 4; i++) |
|
||||
ok1(tal_parent(c[i]) == parent); |
|
||||
|
|
||||
/* Free parent. */ |
|
||||
ok1(tal_free(parent) == NULL); |
|
||||
|
|
||||
parent = tal(NULL, char); |
|
||||
|
|
||||
/* Test freeing in every order */ |
|
||||
for (i = 0; i < 4; i++) { |
|
||||
for (j = 0; j < 4; j++) |
|
||||
c[j] = tal(parent, char); |
|
||||
|
|
||||
tal_free(c[i]); |
|
||||
tal_free(c[(i+1) % 4]); |
|
||||
tal_free(c[(i+2) % 4]); |
|
||||
tal_free(c[(i+3) % 4]); |
|
||||
} |
|
||||
tal_free(parent); |
|
||||
|
|
||||
return exit_status(); |
|
||||
} |
|
Loading…
Reference in new issue