1 /* Licensed under LGPL - see LICENSE file for details */
2 #include <ccan/tal/talloc/talloc.h>
3 #include <ccan/take/take.h>
7 static void (*errorfn)(const char *msg) = (void *)abort;
9 static void COLD call_error(const char *msg)
14 static void *error_on_null(void *p, const char *msg)
21 void *tal_talloc_(const tal_t *ctx, size_t bytes, bool clear,
27 ret = _talloc_zero(ctx, bytes, label);
29 ret = talloc_named_const(ctx, bytes, label);
31 return error_on_null(ret, "allocation failure");
34 void *tal_talloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear,
40 ret = _talloc_zero_array(ctx, bytes, count, label);
42 ret = _talloc_array(ctx, bytes, count, label);
44 return error_on_null(ret, "array allocation failure");
47 void *tal_talloc_free_(const tal_t *ctx)
49 int saved_errno = errno;
50 talloc_free((void *)ctx);
55 bool tal_talloc_set_name_(tal_t *ctx, const char *name, bool literal)
58 name = talloc_strdup(ctx, name);
60 call_error("set_name allocation failure");
64 talloc_set_name_const(ctx, name);
68 const char *tal_talloc_name_(const tal_t *ctx)
70 const char *p = talloc_get_name(ctx);
71 if (p && unlikely(strcmp(p, "UNNAMED") == 0))
76 static bool adjust_size(size_t *size, size_t count)
78 /* Multiplication wrap */
79 if (count && unlikely(*size * count / *size != count))
84 /* Make sure we don't wrap adding header. */
85 if (*size + 1024 < 1024)
89 call_error("allocation size overflow");
93 void *tal_talloc_dup_(const tal_t *ctx, const void *p, size_t size,
94 size_t n, size_t extra, const char *label)
99 if (!adjust_size(&nbytes, n)) {
105 /* Beware addition overflow! */
107 call_error("dup size overflow");
116 if (unlikely(!tal_talloc_resize_((void **)&p, size, n + extra)))
118 if (unlikely(!tal_steal(ctx, p)))
123 ret = tal_talloc_arr_(ctx, size, n + extra, false, label);
125 memcpy(ret, p, nbytes);
129 bool tal_talloc_resize_(tal_t **ctxp, size_t size, size_t count)
133 if (unlikely(count == 0)) {
135 newp = talloc_size(talloc_parent(*ctxp), 0);
137 call_error("Resize failure");
144 newp = _talloc_realloc_array(NULL, *ctxp, size, count, NULL);
146 call_error("Resize failure");
153 bool tal_talloc_expand_(tal_t **ctxp, const void *src, size_t size, size_t count)
156 size_t old_count = talloc_get_size(*ctxp) / size;
158 /* Check for additive overflow */
159 if (old_count + count < count) {
160 call_error("dup size overflow");
164 /* Don't point src inside thing we're expanding! */
166 || (char *)src >= (char *)(*ctxp) + (size * old_count));
168 if (!tal_talloc_resize_(ctxp, size, old_count + count))
171 memcpy((char *)*ctxp + size * old_count, src, count * size);
180 /* Sucky inline hash table implementation, to avoid deps. */
181 #define HTABLE_BITS 10
183 struct destructor *next;
185 void (*destroy)(void *me);
187 static struct destructor *destr_hash[1 << HTABLE_BITS];
189 static unsigned int hash_ptr(const void *p)
191 unsigned long h = (unsigned long)p / sizeof(void *);
193 return (h ^ (h >> HTABLE_BITS)) & ((1 << HTABLE_BITS) - 1);
196 static int tal_talloc_destroy(const tal_t *ctx)
198 struct destructor **d = &destr_hash[hash_ptr(ctx)];
200 if ((*d)->ctx == ctx) {
201 struct destructor *this = *d;
202 this->destroy((void *)ctx);
210 bool tal_talloc_add_destructor_(const tal_t *ctx, void (*destroy)(void *me))
212 struct destructor *d = talloc(ctx, struct destructor);
216 d->next = destr_hash[hash_ptr(ctx)];
218 d->destroy = destroy;
219 destr_hash[hash_ptr(ctx)] = d;
220 talloc_set_destructor(ctx, tal_talloc_destroy);
224 bool tal_talloc_del_destructor_(const tal_t *ctx, void (*destroy)(void *me))
226 struct destructor **d = &destr_hash[hash_ptr(ctx)];
229 if ((*d)->ctx == ctx && (*d)->destroy == destroy) {
230 struct destructor *this = *d;
240 void tal_talloc_set_backend_(void *(*alloc_fn)(size_t size),
241 void *(*resize_fn)(void *, size_t size),
242 void (*free_fn)(void *),
243 void (*error_fn)(const char *msg))
249 talloc_set_abort_fn(error_fn);
252 bool tal_talloc_check_(const tal_t *ctx, const char *errorstr)
254 /* We can't really check, but this iterates (and may abort). */
255 return !ctx || talloc_total_blocks(ctx) >= 1;