summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--ta/README39
-rw-r--r--ta/ta.c439
-rw-r--r--ta/ta.h146
-rw-r--r--ta/ta_talloc.c75
-rw-r--r--ta/ta_talloc.h74
-rw-r--r--ta/ta_utils.c320
-rw-r--r--talloc.c1751
-rw-r--r--talloc.h176
9 files changed, 1098 insertions, 1928 deletions
diff --git a/Makefile b/Makefile
index 54d354ffc4..ad358f6642 100644
--- a/Makefile
+++ b/Makefile
@@ -137,8 +137,7 @@ endif
SOURCES-$(DLOPEN) += video/filter/vf_dlopen.c
-SOURCES = talloc.c \
- audio/audio.c \
+SOURCES = audio/audio.c \
audio/chmap.c \
audio/chmap_sel.c \
audio/fmt-conversion.c \
@@ -241,6 +240,9 @@ SOURCES = talloc.c \
sub/sd_srt.c \
sub/spudec.c \
sub/sub.c \
+ ta/ta.c \
+ ta/ta_utils.c \
+ ta/ta_talloc.c \
video/csputils.c \
video/fmt-conversion.c \
video/image_writer.c \
diff --git a/ta/README b/ta/README
new file mode 100644
index 0000000000..cd98c1a5ae
--- /dev/null
+++ b/ta/README
@@ -0,0 +1,39 @@
+TA ("Tree Allocator") is a wrapper around malloc() and related functions,
+adding features like automatically free sub-trees of memory allocations if
+a parent allocation is freed.
+
+Generally, the idea is that every TA allocation can have a parent (indicated
+by the ta_parent argument in allocation function calls). If a parent is freed,
+its child allocations are automatically freed as well. It's also allowed the
+free a child before the parent, or to move a child to another parent with
+ta_set_parent().
+
+It also provides a bunch of convenience macros and debugging facilities.
+
+The TA functions are documented in the implementation files (ta.c, ta_utils.c).
+
+TA is intended to be useable as library independent from mpv. It doesn't
+depend on anything mpv specific.
+
+Note:
+-----
+
+mpv doesn't use the TA API yet for two reasons: first, the TA API is not
+necessarily finalized yet. Second, it should be easily possible to revert
+the commit adding TA, and changing all the code would not allow this.
+
+Especially the naming schema for some TA functions is still somewhat
+undecided. (The talloc naming is a bit verbose at times.)
+
+For now, mpv goes through a talloc wrapper, which maps the talloc API to TA.
+New code should still use talloc as well. At one point, all talloc calls
+will be replaced with TA calls, and the talloc wrapper will be removed.
+
+Documentation for the talloc API is here:
+
+ http://git.samba.org/?p=samba.git;a=blob;f=lib/talloc/talloc.h;hb=HEAD
+
+There are some minor differences with mpv's talloc bridge. mpv calls abort()
+on allocation failures, and the talloc_set_destructor() signature is slightly
+different. libtalloc also has a weird 256MB limit per allocation. The talloc
+wrapper supports only a strict subset of libtalloc functionality used by mpv.
diff --git a/ta/ta.c b/ta/ta.c
new file mode 100644
index 0000000000..568f6d5f1b
--- /dev/null
+++ b/ta/ta.c
@@ -0,0 +1,439 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define TA_NO_WRAPPERS
+#include "ta.h"
+
+// Note: the actual minimum alignment is dictated by malloc(). It doesn't
+// make sense to set this value higher than malloc's alignment.
+#define MIN_ALIGN 16
+
+#ifndef NDEBUG
+#define TA_MEMORY_DEBUGGING
+#endif
+
+struct ta_header {
+ size_t size; // size of the user allocation
+ struct ta_header *prev; // ring list containing siblings
+ struct ta_header *next;
+ struct ta_ext_header *ext;
+#ifdef TA_MEMORY_DEBUGGING
+ unsigned int canary;
+ struct ta_header *leak_next;
+ struct ta_header *leak_prev;
+ const char *name;
+#endif
+};
+
+#define CANARY 0xD3ADB3EF
+
+union aligned_header {
+ struct ta_header ta;
+ // Make sure to satisfy typical alignment requirements
+ void *align_ptr;
+ int align_int;
+ double align_d;
+ long long align_ll;
+ char align_min[(sizeof(struct ta_header) + MIN_ALIGN - 1) & ~(MIN_ALIGN - 1)];
+};
+
+#define PTR_TO_HEADER(ptr) (&((union aligned_header *)(ptr) - 1)->ta)
+#define PTR_FROM_HEADER(h) ((void *)((union aligned_header *)(h) + 1))
+
+#define MAX_ALLOC (((size_t)-1) - sizeof(union aligned_header))
+
+// Needed for non-leaf allocations, or extended features such as destructors.
+struct ta_ext_header {
+ struct ta_header *header; // points back to normal header
+ struct ta_header children; // list of children, with this as sentinel
+ void (*destructor)(void *);
+};
+
+// ta_ext_header.children.size is set to this
+#define CHILDREN_SENTINEL ((size_t)-1)
+
+static void ta_dbg_add(struct ta_header *h);
+static void ta_dbg_check_header(struct ta_header *h);
+static void ta_dbg_remove(struct ta_header *h);
+
+static struct ta_header *get_header(void *ptr)
+{
+ struct ta_header *h = ptr ? PTR_TO_HEADER(ptr) : NULL;
+ ta_dbg_check_header(h);
+ return h;
+}
+
+static struct ta_ext_header *get_or_alloc_ext_header(void *ptr)
+{
+ struct ta_header *h = get_header(ptr);
+ if (!h)
+ return NULL;
+ if (!h->ext) {
+ h->ext = malloc(sizeof(struct ta_ext_header));
+ if (!h->ext)
+ return NULL;
+ *h->ext = (struct ta_ext_header) {
+ .header = h,
+ .children = {
+ .next = &h->ext->children,
+ .prev = &h->ext->children,
+ // Needed by ta_find_parent():
+ .size = CHILDREN_SENTINEL,
+ .ext = h->ext,
+ },
+ };
+ }
+ return h->ext;
+}
+
+/* Set the parent allocation of ptr. If parent==NULL, remove the parent.
+ * Setting parent==NULL (with ptr!=NULL) always succeeds, and unsets the
+ * parent of ptr. Operations ptr==NULL always succeed and do nothing.
+ * Returns true on success, false on OOM.
+ */
+bool ta_set_parent(void *ptr, void *ta_parent)
+{
+ struct ta_header *ch = get_header(ptr);
+ if (!ch)
+ return true;
+ struct ta_ext_header *parent_eh = get_or_alloc_ext_header(ta_parent);
+ if (ta_parent && !parent_eh) // do nothing on OOM
+ return false;
+ // Unlink from previous parent
+ if (ch->next) {
+ ch->next->prev = ch->prev;
+ ch->prev->next = ch->next;
+ ch->next = ch->prev = NULL;
+ }
+ // Link to new parent - insert at end of list (possibly orders destructors)
+ if (parent_eh) {
+ struct ta_header *children = &parent_eh->children;
+ ch->next = children;
+ ch->prev = children->prev;
+ children->prev->next = ch;
+ children->prev = ch;
+ }
+ return true;
+}
+
+/* Allocate size bytes of memory. If ta_parent is not NULL, this is used as
+ * parent allocation (if ta_parent is freed, this allocation is automatically
+ * freed as well). size==0 allocates a block of size 0 (i.e. returns non-NULL).
+ * Returns NULL on OOM.
+ */
+void *ta_alloc_size(void *ta_parent, size_t size)
+{
+ if (size >= MAX_ALLOC)
+ return NULL;
+ struct ta_header *h = malloc(sizeof(union aligned_header) + size);
+ if (!h)
+ return NULL;
+ *h = (struct ta_header) {.size = size};
+ ta_dbg_add(h);
+ void *ptr = PTR_FROM_HEADER(h);
+ if (!ta_set_parent(ptr, ta_parent)) {
+ ta_free(ptr);
+ return NULL;
+ }
+ return ptr;
+}
+
+/* Exactly the same as ta_alloc_size(), but the returned memory block is
+ * initialized to 0.
+ */
+void *ta_zalloc_size(void *ta_parent, size_t size)
+{
+ if (size >= MAX_ALLOC)
+ return NULL;
+ struct ta_header *h = calloc(1, sizeof(union aligned_header) + size);
+ if (!h)
+ return NULL;
+ *h = (struct ta_header) {.size = size};
+ ta_dbg_add(h);
+ void *ptr = PTR_FROM_HEADER(h);
+ if (!ta_set_parent(ptr, ta_parent)) {
+ ta_free(ptr);
+ return NULL;
+ }
+ return ptr;
+}
+
+/* Reallocate the allocation given by ptr and return a new pointer. Much like
+ * realloc(), the returned pointer can be different, and on OOM, NULL is
+ * returned.
+ *
+ * size==0 is equivalent to ta_free(ptr).
+ * ptr==NULL is equivalent to ta_alloc_size(ta_parent, size).
+ *
+ * ta_parent is used only in the ptr==NULL case.
+ *
+ * Returns NULL if the operation failed.
+ * NULL is also returned if size==0.
+ */
+void *ta_realloc_size(void *ta_parent, void *ptr, size_t size)
+{
+ if (size >= MAX_ALLOC)
+ return NULL;
+ if (!size) {
+ ta_free(ptr);
+ return NULL;
+ }
+ if (!ptr)
+ return ta_alloc_size(ta_parent, size);
+ struct ta_header *h = get_header(ptr);
+ struct ta_header *old_h = h;
+ if (h->size == size)
+ return ptr;
+ ta_dbg_remove(h);
+ h = realloc(h, sizeof(union aligned_header) + size);
+ ta_dbg_add(h ? h : old_h);
+ if (!h)
+ return NULL;
+ h->size = size;
+ if (h != old_h) {
+ if (h->next) {
+ // Relink siblings
+ h->next->prev = h;
+ h->prev->next = h;
+ }
+ if (h->ext) {
+ // Relink children
+ h->ext->header = h;
+ h->ext->children.next->prev = &h->ext->children;
+ h->ext->children.prev->next = &h->ext->children;
+ }
+ }
+ return PTR_FROM_HEADER(h);
+}
+
+/* Return the allocated size of ptr. This returns the size parameter of the
+ * most recent ta_alloc.../ta_realloc... call.
+ * If ptr==NULL, return 0.
+ */
+size_t ta_get_size(void *ptr)
+{
+ struct ta_header *h = get_header(ptr);
+ return h ? h->size : 0;
+}
+
+/* Free all allocations that (recursively) have ptr as parent allocation, but
+ * do not free ptr itself.
+ */
+void ta_free_children(void *ptr)
+{
+ struct ta_header *h = get_header(ptr);
+ struct ta_ext_header *eh = h ? h->ext : NULL;
+ if (!eh)
+ return;
+ while (eh->children.next != &eh->children)
+ ta_free(PTR_FROM_HEADER(eh->children.next));
+}
+
+/* Free the given allocation, and all of its direct and indirect children.
+ */
+void ta_free(void *ptr)
+{
+ struct ta_header *h = get_header(ptr);
+ if (!h)
+ return;
+ if (h->ext && h->ext->destructor)
+ h->ext->destructor(ptr);
+ ta_free_children(ptr);
+ if (h->next) {
+ // Unlink from sibling list
+ h->next->prev = h->prev;
+ h->prev->next = h->next;
+ }
+ ta_dbg_remove(h);
+ free(h->ext);
+ free(h);
+}
+
+/* Set a destructor that is to be called when the given allocation is freed.
+ * (Whether the allocation is directly freed with ta_free() or indirectly by
+ * freeing its parent does not matter.) There is only one destructor. If an
+ * destructor was already set, it's overwritten.
+ *
+ * The destructor will be called with ptr as argument. The destructor can do
+ * almost anything, but it must not attempt to free or realloc ptr. The
+ * destructor is run before the allocation's children are freed (also, before
+ * their destructors are run).
+ *
+ * Returns false if ptr==NULL, or on OOM.
+ */
+bool ta_set_destructor(void *ptr, void (*destructor)(void *))
+{
+ struct ta_ext_header *eh = get_or_alloc_ext_header(ptr);
+ if (!eh)
+ return false;
+ eh->destructor = destructor;
+ return true;
+}
+
+/* Return the ptr's parent allocation, or NULL if there isn't any.
+ *
+ * Warning: this has O(N) runtime complexity with N sibling allocations!
+ */
+void *ta_find_parent(void *ptr)
+{
+ struct ta_header *h = get_header(ptr);
+ if (!h || !h->next)
+ return NULL;
+ for (struct ta_header *cur = h->next; cur != h; cur = cur->next) {
+ if (cur->size == CHILDREN_SENTINEL)
+ return PTR_FROM_HEADER(cur->ext->header);
+ }
+ return NULL;
+}
+
+#ifdef TA_MEMORY_DEBUGGING
+
+#include <pthread.h>
+
+static pthread_mutex_t ta_dbg_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool enable_leak_check; // pretty much constant
+static struct ta_header leak_node;
+static char allocation_is_string;
+
+static void ta_dbg_add(struct ta_header *h)
+{
+ h->canary = CANARY;
+ if (enable_leak_check) {
+ pthread_mutex_lock(&ta_dbg_mutex);
+ h->leak_next = &leak_node;
+ h->leak_prev = leak_node.leak_prev;
+ leak_node.leak_prev->leak_next = h;
+ leak_node.leak_prev = h;
+ pthread_mutex_unlock(&ta_dbg_mutex);
+ }
+}
+
+static void ta_dbg_check_header(struct ta_header *h)
+{
+ if (h)
+ assert(h->canary == CANARY);
+}
+
+static void ta_dbg_remove(struct ta_header *h)
+{
+ ta_dbg_check_header(h);
+ if (h->leak_next) { // assume checking for !=NULL invariant ok without lock
+ pthread_mutex_lock(&ta_dbg_mutex);
+ h->leak_next->leak_prev = h->leak_prev;
+ h->leak_prev->leak_next = h->leak_next;
+ pthread_mutex_unlock(&ta_dbg_mutex);
+ h->leak_next = h->leak_prev = NULL;
+ }
+ h->canary = 0;
+}
+
+static size_t get_children_size(struct ta_header *h)
+{
+ size_t size = 0;
+ if (h->ext) {
+ struct ta_header *s;
+ for (s = h->ext->children.next; s != &h->ext->children; s = s->next)
+ size += s->size + get_children_size(s);
+ }
+ return size;
+}
+
+static void print_leak_report(void)
+{
+ pthread_mutex_lock(&ta_dbg_mutex);
+ if (leak_node.leak_next && leak_node.leak_next != &leak_node) {
+ size_t size = 0;
+ size_t num_blocks = 0;
+ fprintf(stderr, "Blocks not freed:\n");
+ fprintf(stderr, " %-20s %10s %10s %s\n",
+ "Ptr", "Bytes", "C. Bytes", "Name");
+ while (leak_node.leak_next != &leak_node) {
+ struct ta_header *cur = leak_node.leak_next;
+ // Don't list those with parent; logically, only parents are listed
+ if (!cur->next) {
+ size_t c_size = get_children_size(cur);
+ char name[30] = {0};
+ if (cur->name)
+ snprintf(name, sizeof(name), "%s", cur->name);
+ if (cur->name == &allocation_is_string) {
+ snprintf(name, sizeof(name), "'%.*s'",
+ (int)cur->size, (char *)PTR_FROM_HEADER(cur));
+ }
+ for (int n = 0; n < sizeof(name); n++) {
+ if (name[n] && name[n] < 0x20)
+ name[n] = '.';
+ }
+ fprintf(stderr, " %-20p %10zu %10zu %s\n",
+ cur, cur->size, c_size, name);
+ }
+ size += cur->size;
+ num_blocks += 1;
+ // Unlink, and don't confuse valgrind by leaving live pointers.
+ cur->leak_next->leak_prev = cur->leak_prev;
+ cur->leak_prev->leak_next = cur->leak_next;
+ cur->leak_next = cur->leak_prev = NULL;
+ }
+ fprintf(stderr, "%zu bytes in %zu blocks.\n", size, num_blocks);
+ }
+ pthread_mutex_unlock(&ta_dbg_mutex);
+}
+
+void ta_enable_leak_report(void)
+{
+ pthread_mutex_lock(&ta_dbg_mutex);
+ enable_leak_check = true;
+ if (!leak_node.leak_prev && !leak_node.leak_next) {
+ leak_node.leak_prev = &leak_node;
+ leak_node.leak_next = &leak_node;
+ atexit(print_leak_report);
+ }
+ pthread_mutex_unlock(&ta_dbg_mutex);
+}
+
+/* Set a (static) string that will be printed if the memory allocation in ptr
+ * shows up on the leak report. The string must stay valid until ptr is freed.
+ * Calling it on ptr==NULL does nothing.
+ * Typically used to set location info.
+ * Always returns ptr (useful for chaining function calls).
+ */
+void *ta_dbg_set_loc(void *ptr, const char *loc)
+{
+ struct ta_header *h = get_header(ptr);
+ if (h)
+ h->name = loc;
+ return ptr;
+}
+
+/* Mark the allocation as string. The leak report will print it literally.
+ */
+void *ta_dbg_mark_as_string(void *ptr)
+{
+ // Specially handled by leak report code.
+ return ta_dbg_set_loc(ptr, &allocation_is_string);
+}
+
+#else
+
+static void ta_dbg_add(struct ta_header *h){}
+static void ta_dbg_check_header(struct ta_header *h){}
+static void ta_dbg_remove(struct ta_header *h){}
+
+void ta_enable_leak_report(void){}
+void *ta_dbg_set_name(void *ptr, const char *name){return ptr;}
+
+#endif
diff --git a/ta/ta.h b/ta/ta.h
new file mode 100644
index 0000000000..1a9738a9f0
--- /dev/null
+++ b/ta/ta.h
@@ -0,0 +1,146 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef TA_H_
+#define TA_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#ifdef __GNUC__
+#define TA_PRF(a1, a2) __attribute__ ((format(printf, a1, a2)))
+#define TA_TYPEOF(t) __typeof__(t)
+#else
+#define TA_PRF(a1, a2)
+#define TA_TYPEOF(t) void *
+#endif
+
+#define TA_STRINGIFY_(x) # x
+#define TA_STRINGIFY(x) TA_STRINGIFY_(x)
+
+#ifdef NDEBUG
+#define TA_LOC ""
+#else
+#define TA_LOC __FILE__ ":" TA_STRINGIFY(__LINE__)
+#endif
+
+// Core functions
+void *ta_alloc_size(void *ta_parent, size_t size);
+void *ta_zalloc_size(void *ta_parent, size_t size);
+void *ta_realloc_size(void *ta_parent, void *ptr, size_t size);
+size_t ta_get_size(void *ptr);
+void ta_free(void *ptr);
+void ta_free_children(void *ptr);
+bool ta_set_destructor(void *ptr, void (*destructor)(void *));
+bool ta_set_parent(void *ptr, void *ta_parent);
+void *ta_find_parent(void *ptr);
+
+// Utility functions
+size_t ta_calc_array_size(size_t element_size, size_t count);
+void *ta_new_context(void *ta_parent);
+void *ta_steal_(void *ta_parent, void *ptr);
+void *ta_memdup(void *ta_parent, void *ptr, size_t size);
+char *ta_strdup(void *ta_parent, const char *str);
+bool ta_strdup_append(char **str, const char *a);
+bool ta_strdup_append_buffer(char **str, const char *a);
+char *ta_strndup(void *ta_parent, const char *str, size_t n);
+bool ta_strndup_append(char **str, const char *a, size_t n);
+bool ta_strndup_append_buffer(char **str, const char *a, size_t n);
+char *ta_asprintf(void *ta_parent, const char *fmt, ...) TA_PRF(2, 3);
+char *ta_vasprintf(void *ta_parent, const char *fmt, va_list ap) TA_PRF(2, 0);
+bool ta_asprintf_append(char **str, const char *fmt, ...) TA_PRF(2, 3);
+bool ta_vasprintf_append(char **str, const char *fmt, va_list ap) TA_PRF(2, 0);
+bool ta_asprintf_append_buffer(char **str, const char *fmt, ...) TA_PRF(2, 3);
+bool ta_vasprintf_append_buffer(char **str, const char *fmt, va_list ap) TA_PRF(2, 0);
+
+#define ta_new(ta_parent, type) (type *)ta_alloc_size(ta_parent, sizeof(type))
+#define ta_znew(ta_parent, type) (type *)ta_zalloc_size(ta_parent, sizeof(type))
+
+#define ta_new_array(ta_parent, type, count) \
+ (type *)ta_alloc_size(ta_parent, ta_calc_array_size(sizeof(type), count))
+
+#define ta_znew_array(ta_parent, type, count) \
+ (type *)ta_zalloc_size(ta_parent, ta_calc_array_size(sizeof(type), count))
+
+#define ta_new_array_size(ta_parent, element_size, count) \
+ ta_alloc_size(ta_parent, ta_calc_array_size(element_size, count))
+
+#define ta_realloc(ta_parent, ptr, type, count) \
+ (type *)ta_realloc_size(ta_parent, ptr, ta_calc_array_size(sizeof(type), count))
+
+#define ta_new_ptrtype(ta_parent, ptr) \
+ (TA_TYPEOF(ptr))ta_alloc_size(ta_parent, sizeof(*ptr))
+
+#define ta_new_array_ptrtype(ta_parent, ptr, count) \
+ (TA_TYPEOF(ptr))ta_new_array_size(ta_parent, sizeof(*(ptr)), count)
+
+#define ta_steal(ta_parent, ptr) (TA_TYPEOF(ptr))ta_steal_(ta_parent, ptr)
+
+// Ugly macros that crash on OOM.
+// All of these mirror real functions (with a 'x' added after the 'ta_'
+// prefix), and the only difference is that they will call abort() on allocation
+// failures (such as out of memory conditions), instead of returning an error
+// code.
+#define ta_xalloc_size(...) ta_oom_p(ta_alloc_size(__VA_ARGS__))
+#define ta_xzalloc_size(...) ta_oom_p(ta_zalloc_size(__VA_ARGS__))
+#define ta_xset_destructor(...) ta_oom_b(ta_set_destructor(__VA_ARGS__))
+#define ta_xset_parent(...) ta_oom_b(ta_set_parent(__VA_ARGS__))
+#define ta_xnew_context(...) ta_oom_p(ta_new_context(__VA_ARGS__))
+#define ta_xstrdup_append(...) ta_oom_b(ta_strdup_append(__VA_ARGS__))
+#define ta_xstrdup_append_buffer(...) ta_oom_b(ta_strdup_append_buffer(__VA_ARGS__))
+#define ta_xstrndup_append(...) ta_oom_b(ta_strndup_append(__VA_ARGS__))
+#define ta_xstrndup_append_buffer(...) ta_oom_b(ta_strndup_append_buffer(__VA_ARGS__))
+#define ta_xasprintf(...) ta_oom_s(ta_asprintf(__VA_ARGS__))
+#define ta_xvasprintf(...) ta_oom_s(ta_vasprintf(__VA_ARGS__))
+#define ta_xasprintf_append(...) ta_oom_b(ta_asprintf_append(__VA_ARGS__))
+#define ta_xvasprintf_append(...) ta_oom_b(ta_vasprintf_append(__VA_ARGS__))
+#define ta_xasprintf_append_buffer(...) ta_oom_b(ta_asprintf_append_buffer(__VA_ARGS__))
+#define ta_xvasprintf_append_buffer(...) ta_oom_b(ta_vasprintf_append_buffer(__VA_ARGS__))
+#define ta_xnew(...) ta_oom_g(ta_new(__VA_ARGS__))
+#define ta_xznew(...) ta_oom_g(ta_znew(__VA_ARGS__))
+#define ta_xnew_array(...) ta_oom_g(ta_new_array(__VA_ARGS__))
+#define ta_xznew_array(...) ta_oom_g(ta_znew_array(__VA_ARGS__))
+#define ta_xnew_array_size(...) ta_oom_p(ta_new_array_size(__VA_ARGS__))
+#define ta_xnew_ptrtype(...) ta_oom_g(ta_new_ptrtype(__VA_ARGS__))
+#define ta_xnew_array_ptrtype(...) ta_oom_g(ta_new_array_ptrtype(__VA_ARGS__))
+
+#define ta_xsteal(ta_parent, ptr) (TA_TYPEOF(ptr))ta_xsteal_(ta_parent, ptr)
+#define ta_xrealloc(ta_parent, ptr, type, count) \
+ (type *)ta_xrealloc_size(ta_parent, ptr, ta_calc_array_size(sizeof(type), count))
+
+// Can't be macros, because the OOM logic is slightly less trivial.
+char *ta_xstrdup(void *ta_parent, const char *str);
+char *ta_xstrndup(void *ta_parent, const char *str, size_t n);
+void *ta_xsteal_(void *ta_parent, void *ptr);
+void *ta_xmemdup(void *ta_parent, void *ptr, size_t size);
+void *ta_xrealloc_size(void *ta_parent, void *ptr, size_t size);
+
+#ifndef TA_NO_WRAPPERS
+#define ta_alloc_size(...) ta_dbg_set_loc(ta_alloc_size(__VA_ARGS__), TA_LOC)
+#define ta_zalloc_size(...) ta_dbg_set_loc(ta_zalloc_size(__VA_ARGS__), TA_LOC)
+#define ta_realloc_size(...) ta_dbg_set_loc(ta_realloc_size(__VA_ARGS__), TA_LOC)
+#define ta_memdup(...) ta_dbg_set_loc(ta_memdup(__VA_ARGS__), TA_LOC)
+#endif
+
+void ta_oom_b(bool b);
+char *ta_oom_s(char *s);
+void *ta_oom_p(void *p);
+// Generic pointer
+#define ta_oom_g(ptr) (TA_TYPEOF(ptr))ta_oom_p(ptr)
+
+void ta_enable_leak_report(void);
+void *ta_dbg_set_loc(void *ptr, const char *name);
+void *ta_dbg_mark_as_string(void *ptr);
+
+#endif
diff --git a/ta/ta_talloc.c b/ta/ta_talloc.c
new file mode 100644
index 0000000000..9c52bbab08
--- /dev/null
+++ b/ta/ta_talloc.c
@@ -0,0 +1,75 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "ta_talloc.h"
+
+char *ta_talloc_strdup_append(char *s, const char *a)
+{
+ ta_xstrdup_append(&s, a);
+ return s;
+}
+
+char *ta_talloc_strdup_append_buffer(char *s, const char *a)
+{
+ ta_xstrdup_append_buffer(&s, a);
+ return s;
+}
+
+char *ta_talloc_strndup_append(char *s, const char *a, size_t n)
+{
+ ta_xstrndup_append(&s, a, n);
+ return s;
+}
+
+char *ta_talloc_strndup_append_buffer(char *s, const char *a, size_t n)
+{
+ ta_xstrndup_append_buffer(&s, a, n);
+ return s;
+}
+
+char *ta_talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+ ta_xvasprintf_append(&s, fmt, ap);
+ return s;
+}
+
+char *ta_talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
+{
+ ta_xvasprintf_append_buffer(&s, fmt, ap);
+ return s;
+}
+
+char *ta_talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+ char *res;
+ va_list ap;
+ va_start(ap, fmt);
+ res = talloc_vasprintf_append(s, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+char *ta_talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
+{
+ char *res;
+ va_list ap;
+ va_start(ap, fmt);
+ res = talloc_vasprintf_append_buffer(s, fmt, ap);
+ va_end(ap);
+ return res;
+}
diff --git a/ta/ta_talloc.h b/ta/ta_talloc.h
new file mode 100644
index 0000000000..cd41e63818
--- /dev/null
+++ b/ta/ta_talloc.h
@@ -0,0 +1,74 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef TA_TALLOC_H_
+#define TA_TALLOC_H_
+
+#include "ta.h"
+
+// Note: all talloc wrappers are wired to the "x" functions, which abort on OOM.
+// libtalloc doesn't do that, but the mplayer2 internal copy of it did.
+
+#define talloc ta_xnew
+#define talloc_zero ta_xznew
+
+#define talloc_array ta_xnew_array
+#define talloc_zero_array ta_xznew_array
+
+#define talloc_array_size ta_xnew_array_size
+#define talloc_realloc ta_xrealloc
+#define talloc_ptrtype ta_xnew_ptrtype
+#define talloc_array_ptrtype ta_xnew_array_ptrtype
+
+#define talloc_steal ta_xsteal
+#define talloc_realloc_size ta_xrealloc_size
+#define talloc_new ta_xnew_context
+#define talloc_set_destructor ta_xset_destructor
+#define talloc_parent ta_find_parent
+#define talloc_enable_leak_report ta_enable_leak_report
+#define talloc_size ta_xalloc_size
+#define talloc_zero_size ta_xzalloc_size
+#define talloc_get_size ta_get_size
+#define talloc_free_children ta_free_children
+#define talloc_free ta_free
+#define talloc_memdup ta_xmemdup
+#define talloc_strdup ta_xstrdup
+#define talloc_strndup ta_xstrndup
+#define talloc_asprintf ta_xasprintf
+#define talloc_vasprintf ta_xvasprintf
+
+// Don't define linker-level symbols, as that would clash with real libtalloc.
+#define talloc_strdup_append ta_talloc_strdup_append
+#define talloc_strdup_append_buffer ta_talloc_strdup_append_buffer
+#define talloc_strndup_append ta_talloc_strndup_append
+#define talloc_strndup_append_buffer ta_talloc_strndup_append_buffer
+#define talloc_vasprintf_append ta_talloc_vasprintf_append
+#define talloc_vasprintf_append_buffer ta_talloc_vasprintf_append_buffer
+#define talloc_asprintf_append ta_talloc_asprintf_append
+#define talloc_asprintf_append_buffer ta_talloc_asprintf_append_buffer
+
+char *ta_talloc_strdup(void *t, const char *p);
+char *ta_talloc_strdup_append(char *s, const char *a);
+char *ta_talloc_strdup_append_buffer(char *s, const char *a);
+
+char *ta_talloc_strndup(void *t, const char *p, size_t n);
+char *ta_talloc_strndup_append(char *s, const char *a, size_t n);
+char *ta_talloc_strndup_append_buffer(char *s, const char *a, size_t n);
+
+char *ta_talloc_vasprintf_append(char *s, const char *fmt, va_list ap) TA_PRF(2, 0);
+char *ta_talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) TA_PRF(2, 0);
+
+char *ta_talloc_asprintf_append(char *s, const char *fmt, ...) TA_PRF(2, 3);
+char *ta_talloc_asprintf_append_buffer(char *s, const char *fmt, ...) TA_PRF(2, 3);
+
+#endif
diff --git a/ta/ta_utils.c b/ta/ta_utils.c
new file mode 100644
index 0000000000..19ab77a733
--- /dev/null
+++ b/ta/ta_utils.c
@@ -0,0 +1,320 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define TA_NO_WRAPPERS
+#include "ta.h"
+
+// Return element_size * count. If it overflows, return (size_t)-1 (SIZE_MAX).
+// I.e. this returns the equivalent of: MIN(element_size * count, SIZE_MAX).
+// The idea is that every real memory allocator will reject (size_t)-1, thus
+// this is a valid way to handle too large array allocation requests.
+size_t ta_calc_array_size(size_t element_size, size_t count)
+{
+ if (count > (((size_t)-1) / element_size))
+ return (size_t)-1;
+ return element_size * count;
+}
+
+static void dummy_dtor(void *p){}
+
+/* Create an empty (size 0) TA allocation, which is prepared in a way such that
+ * using it as parent with ta_set_parent() always succeed. Calling
+ * ta_set_destructor() on it will always succeed as well.
+ */
+void *ta_new_context(void *ta_parent)
+{
+ void *new = ta_alloc_size(ta_parent, 0);
+ // Force it to allocate an extended header.
+ if (!ta_set_destructor(new, dummy_dtor)) {
+ ta_free(new);
+ new = NULL;
+ }
+ return new;
+}
+
+/* Set parent of ptr to ta_parent, return the ptr.
+ * Note that ta_parent==NULL will simply unset the current parent of ptr.
+ * If the operation fails (on OOM), return NULL. (That's pretty bad behavior,
+ * but the only way to signal failure.)
+ */
+void *ta_steal_(void *ta_parent, void *ptr)
+{
+ if (!ta_set_parent(ptr, ta_parent))
+ return NULL;
+ return ptr;
+}
+
+/* Duplicate the memory at ptr with the given size.
+ */
+void *ta_memdup(void *ta_parent, void *ptr, size_t size)
+{
+ if (!ptr) {
+ assert(!size);
+ return NULL;
+ }
+ void *res = ta_alloc_size(ta_parent, size);
+ if (!res)
+ return NULL;
+ memcpy(res, ptr, size);
+ return res;
+}
+
+// *str = *str[0..at] + append[0..append_len]
+// (append_len being a maximum length; shorter if embedded \0s are encountered)
+static bool strndup_append_at(char **str, size_t at, const char *append,
+ size_t append_len)
+{
+ assert(ta_get_size(*str) >= at);
+
+ if (!*str && !append)
+ return true; // stays NULL, but not an OOM condition
+
+ size_t real_len = append ? strnlen(append, append_len) : 0;
+ if (append_len > real_len)
+ append_len = real_len;
+
+ if (ta_get_size(*str) < at + append_len + 1) {
+ char *t = ta_realloc_size(NULL, *str, at + append_len + 1);
+ if (!t)
+ return false;
+ *str = t;
+ }
+
+ memcpy(*str + at, append, append_len);
+ (*str)[at + append_len] = '\0';
+
+ ta_dbg_mark_as_string(*str);
+
+ return true;
+}
+
+/* Return a copy of str.
+ * Returns NULL on OOM.
+ */
+char *ta_strdup(void *ta_parent, const char *str)
+{
+ return ta_strndup(ta_parent, str, str ? strlen(str) : 0);
+}
+
+/* Return a copy of str. If the string is longer than n, copy only n characters
+ * (the returned allocation will be n+1 bytes and contain a terminating '\0').
+ * The returned string will have the length MIN(strlen(str), n)
+ * If str==NULL, return NULL. Returns NULL on OOM as well.
+ */
+char *ta_strndup(void *ta_parent, const char *str, size_t n)
+{
+ if (!str)
+ return NULL;
+ char *new = NULL;
+ strndup_append_at(&new, 0, str, n);
+ if (!ta_set_parent(new, ta_parent)) {
+ ta_free(new);
+ new = NULL;
+ }
+ return new;
+}
+
+/* Append a to *str. If *str is NULL, the string is newly allocated, otherwise
+ * ta_realloc() is used on *str as needed.
+ * Return success or failure (it can fail due to OOM only).
+ */
+bool ta_strdup_append(char **str, const char *a)
+{
+ return strndup_append_at(str, *str ? strlen(*str) : 0, a, (size_t)-1);
+}
+
+/* Like ta_strdup_append(), but use ta_get_size(*str)-1 instead of strlen(*str).
+ * (See also: ta_asprintf_append_buffer())
+ */
+bool ta_strdup_append_buffer(char **str, const char *a)
+{
+ size_t size = ta_get_size(*str);
+ if (size > 0)
+ size -= 1;
+ return strndup_append_at(str, size, a, (size_t)-1);
+}
+
+/* Like ta_strdup_append(), but limit the length of a with n.
+ * (See also: ta_strndup())
+ */
+bool ta_strndup_append(char **str, const char *a, size_t n)
+{
+ return strndup_append_at(str, *str ? strlen(*str) : 0, a, n);
+}
+
+/* Like ta_strdup_append_buffer(), but limit the length of a with n.
+ * (See also: ta_strndup())
+ */
+bool ta_strndup_append_buffer(char **str, const char *a, size_t n)
+{
+ size_t size = ta_get_size(*str);
+ if (size > 0)
+ size -= 1;
+ return strndup_append_at(str, size, a, n);
+}
+
+static bool ta_vasprintf_append_at(char **str, size_t at, const char *fmt,
+ va_list ap)
+{
+ assert(ta_get_size(*str) >= at);
+
+ int size;
+ va_list copy;
+ va_copy(copy, ap);
+ char c;
+ size = vsnprintf(&c, 1, fmt, copy);
+ va_end(copy);
+
+ if (size < 0)
+ return false;
+
+ if (ta_get_size(*str) < at + size + 1) {
+ char *t = ta_realloc_size(NULL, *str, at + size + 1);
+ if (!t)
+ return false;
+ *str = t;
+ }
+ vsnprintf(*str + at, size + 1, fmt, ap);
+
+ ta_dbg_mark_as_string(*str);
+
+ return true;
+}
+
+/* Like snprintf(); returns the formatted string as allocation (or NULL on OOM
+ * or snprintf() errors).
+ */
+char *ta_asprintf(void *ta_parent, const char *fmt, ...)
+{
+ char *res;
+ va_list ap;
+ va_start(ap, fmt);
+ res = ta_vasprintf(ta_parent, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+char *ta_vasprintf(void *ta_parent, const char *fmt, va_list ap)
+{
+ char *res = NULL;
+ ta_vasprintf_append_at(&res, 0, fmt, ap);
+ if (!res || !ta_set_parent(res, ta_parent)) {
+ ta_free(res);
+ return NULL;
+ }
+ return res;
+}
+
+/* Append the formatted string to *str (after strlen(*str)). The allocation is
+ * ta_realloced if needed.
+ * Returns false on OOM or snprintf() errors, with *str left untouched.
+ */
+bool ta_asprintf_append(char **str, const char *fmt, ...)
+{
+ bool res;
+ va_list ap;
+ va_start(ap, fmt);
+ res = ta_vasprintf_append(str, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+bool ta_vasprintf_append(char **str, const char *fmt, va_list ap)
+{
+ return ta_vasprintf_append_at(str, str && *str ? strlen(*str) : 0, fmt, ap);
+}
+
+/* Append the formatted string at the end of the allocation of *str. It
+ * overwrites the last byte of the allocation too (which is assumed to be the
+ * '\0' terminating the sttring). Compared to ta_asprintf_append(), this is
+ * useful if you know that the string ends with the allocation, so that the
+ * extra strlen() can be avoided for better performance.
+ * Returns false on OOM or snprintf() errors, with *str left untouched.
+ */
+bool ta_asprintf_append_buffer(char **str, const char *fmt, ...)
+{
+ bool res;
+ va_list ap;
+ va_start(ap, fmt);
+ res = ta_vasprintf_append_buffer(str, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+bool ta_vasprintf_append_buffer(char **str, const char *fmt, va_list ap)
+{
+ size_t size = ta_get_size(*str);
+ if (size > 0)
+ size -= 1;
+ return ta_vasprintf_append_at(str, size, fmt, ap);
+}
+
+
+void *ta_oom_p(void *p)
+{
+ if (!p)
+ abort();
+ return p;
+}
+
+void ta_oom_b(bool b)
+{
+ if (!b)
+ abort();
+}
+
+char *ta_oom_s(char *s)
+{
+ if (!s)
+ abort();
+ return s;
+}
+
+void *ta_xsteal_(void *ta_parent, void *ptr)
+{
+ ta_oom_b(ta_set_parent(ptr, ta_parent));
+ return ptr;
+}
+
+void *ta_xmemdup(void *ta_parent, void *ptr, size_t size)
+{
+ void *new = ta_memdup(ta_parent, ptr, size);
+ ta_oom_b(new || !ptr);
+ return new;
+}
+
+void *ta_xrealloc_size(void *ta_parent, void *ptr, size_t size)
+{
+ ptr = ta_realloc_size(ta_parent, ptr, size);
+ ta_oom_b(ptr || !size);
+ return ptr;
+}
+
+char *ta_xstrdup(void *ta_parent, const char *str)
+{
+ char *res = ta_strdup(ta_parent, str);
+ ta_oom_b(res || !str);
+ return res;
+}
+
+char *ta_xstrndup(void *ta_parent, const char *str, size_t n)
+{
+ char *res = ta_strndup(ta_parent, str, n);
+ ta_oom_b(res || !str);
+ return res;
+}
diff --git a/talloc.c b/talloc.c
deleted file mode 100644
index ec017d9c89..0000000000
--- a/talloc.c
+++ /dev/null
@@ -1,1751 +0,0 @@
-/*
- Samba Unix SMB/CIFS implementation.
-
- Samba trivial allocation library - new interface
-
- NOTE: Please read talloc_guide.txt for full documentation
-
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*
- inspired by http://swapped.cc/halloc/
-*/
-
-// Hardcode these for MPlayer assuming a working system.
-// Original used autoconf detection with workarounds for broken systems.
-#define HAVE_VA_COPY
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdbool.h>
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#define strnlen rep_strnlen
-static size_t rep_strnlen(const char *s, size_t max)
-{
- size_t len;
-
- for (len = 0; len < max; len++) {
- if (s[len] == '\0') {
- break;
- }
- }
- return len;
-}
-
-
-
-#ifdef _SAMBA_BUILD_
-#include "version.h"
-#if (SAMBA_VERSION_MAJOR<4)
-#include "includes.h"
-/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
- * we trust ourselves... */
-#ifdef malloc
-#undef malloc
-#endif
-#ifdef realloc
-#undef realloc
-#endif
-#define _TALLOC_SAMBA3
-#endif /* (SAMBA_VERSION_MAJOR<4) */
-#endif /* _SAMBA_BUILD_ */
-
-#ifndef _TALLOC_SAMBA3
-// Workarounds for missing standard features, not used in MPlayer
-// #include "replace.h"
-#include "talloc.h"
-#endif /* not _TALLOC_SAMBA3 */
-
-/* use this to force every realloc to change the pointer, to stress test
- code that might not cope */
-#define ALWAYS_REALLOC 0
-
-
-#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0xe814ec70
-#define TALLOC_FLAG_FREE 0x01
-#define TALLOC_FLAG_LOOP 0x02
-#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
-#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */
-#define TALLOC_MAGIC_REFERENCE ((const char *)1)
-
-/* by default we abort when given a bad pointer (such as when talloc_free() is called
- on a pointer that came from malloc() */
-#ifndef TALLOC_ABORT
-#define TALLOC_ABORT(reason) abort()
-#endif
-
-#ifndef discard_const_p
-#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
-#else
-# define discard_const_p(type, ptr) ((type *)(ptr))
-#endif
-#endif
-
-/* these macros gain us a few percent of speed on gcc */
-#if (__GNUC__ >= 3)
-/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
- as its first argument */
-#ifndef likely
-#define likely(x) __builtin_expect(!!(x), 1)
-#endif
-#ifndef unlikely
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#endif
-#else
-#ifndef likely
-#define likely(x) (x)
-#endif
-#ifndef unlikely
-#define unlikely(x) (x)
-#endif
-#endif
-
-/* this null_context is only used if talloc_enable_leak_report() or
- talloc_enable_leak_report_full() is called, otherwise it remains
- NULL
-*/
-static void *null_context;
-static void *autofree_context;
-
-struct talloc_reference_handle {
- struct talloc_reference_handle *next, *prev;
- void *ptr;
-};
-
-typedef void (*talloc_destructor_t)(void *);
-
-struct talloc_chunk {
- struct talloc_chunk *next, *prev;
- struct talloc_chunk *parent, *child;
- struct talloc_reference_handle *refs;
- talloc_destructor_t destructor;
- const char *name;
- size_t size;
- unsigned flags;
-
- /*
- * "pool" has dual use:
- *
- * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
- * marks the end of the currently allocated area.
- *
- * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
- * is a pointer to the struct talloc_chunk of the pool that it was
- * allocated from. This way children can quickly find the pool to chew
- * from.
- */
- void *pool;
-};
-
-/* 16 byte alignment seems to keep everyone happy */
-#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
-#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
-
-static void talloc_abort_double_free(void)
-{
- TALLOC_ABORT("Bad talloc magic value - double free");
-}
-
-static void talloc_abort_unknown_value(void)
-{
- TALLOC_ABORT("Bad talloc magic value - unknown value");
-}
-
-/* panic if we get a bad magic value */
-static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
-{
- const char *pp = (const char *)ptr;
- struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
- if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
- if (tc->flags & TALLOC_FLAG_FREE) {
- talloc_abort_double_free();
- } else {
- talloc_abort_unknown_value();
- }
- }
- return tc;
-}
-
-/* hook into the front of the list */
-#define _TLIST_ADD(list, p) \
-do { \
- if (!(list)) { \
- (list) = (p); \
- (p)->next = (p)->prev = NULL; \
- } else { \
- (list)->prev = (p); \
- (p)->next = (list); \
- (p)->prev = NULL; \
- (list) = (p); \
- }\
-} while (0)
-
-/* remove an element from a list - element doesn't have to be in list. */
-#define _TLIST_REMOVE(list, p) \
-do { \
- if ((p) == (list)) { \
- (list) = (p)->next; \
- if (list) (list)->prev = NULL; \
- } else { \
- if ((p)->prev) (p)->prev->next = (p)->next; \
- if ((p)->next) (p)->next->prev = (p)->prev; \
- } \
- if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
-} while (0)
-
-
-/*
- return the parent chunk of a pointer
-*/
-static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
- while (tc->prev) tc=tc->prev;
-
- return tc->parent;
-}
-
-void *talloc_parent(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
-}
-
-/*
- find parents name
-*/
-const char *talloc_parent_name(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc? tc->name : NULL;
-}
-
-/*
- A pool carries an in-pool object count count in the first 16 bytes.
- bytes. This is done to support talloc_steal() to a parent outside of the
- pool. The count includes the pool itself, so a talloc_free() on a pool will
- only destroy the pool if the count has dropped to zero. A talloc_free() of a
- pool member will reduce the count, and eventually also call free(3) on the
- pool memory.
-
- The object count is not put into "struct talloc_chunk" because it is only
- relevant for talloc pools and the alignment to 16 bytes would increase the
- memory footprint of each talloc chunk by those 16 bytes.
-*/
-
-#define TALLOC_POOL_HDR_SIZE 16
-
-static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
-{
- return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
-}
-
-/*
- Allocate from a pool
-*/
-
-static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
- size_t size)
-{
- struct talloc_chunk *pool_ctx = NULL;
- size_t space_left;
- struct talloc_chunk *result;
- size_t chunk_size;
-
- if (parent == NULL) {
- return NULL;
- }
-
- if (parent->flags & TALLOC_FLAG_POOL) {
- pool_ctx = parent;
- }
- else if (parent->flags & TALLOC_FLAG_POOLMEM) {
- pool_ctx = (struct talloc_chunk *)parent->pool;
- }
-
- if (pool_ctx == NULL) {
- return NULL;
- }
-
- space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
- - ((char *)pool_ctx->pool);
-
- /*
- * Align size to 16 bytes
- */
- chunk_size = ((size + 15) & ~15);
-
- if (space_left < chunk_size) {
- return NULL;
- }
-
- result = (struct talloc_chunk *)pool_ctx->pool;
-
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
- VALGRIND_MAKE_MEM_UNDEFINED(result, size);
-#endif
-
- pool_ctx->pool = (void *)((char *)result + chunk_size);
-
- result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
- result->pool = pool_ctx;
-
- *talloc_pool_objectcount(pool_ctx) += 1;
-
- return result;
-}
-
-/*
- Allocate a bit of memory as a child of an existing pointer
-*/
-static inline void *__talloc(const void *context, size_t size)
-{
- struct talloc_chunk *tc = NULL;
-
- if (unlikely(context == NULL)) {
- context = null_context;
- }
-
- if (unlikely(size >= MAX_TALLOC_SIZE)) {
- abort(); // return NULL;
- }
-
- if (context != NULL) {
- tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
- TC_HDR_SIZE+size);
- }
-
- if (tc == NULL) {
- tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
- if (unlikely(tc == NULL)) abort(); // return NULL;
- tc->flags = TALLOC_MAGIC;
- tc->pool = NULL;
- }
-
- tc->size = size;
- tc->destructor = NULL;
- tc->child = NULL;
- tc->name = NULL;
- tc->refs = NULL;
-
- if (likely(context)) {
- struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
-
- if (parent->child) {
- parent->child->parent = NULL;
- tc->next = parent->child;
- tc->next->prev = tc;
- } else {
- tc->next = NULL;
- }
- tc->parent = parent;
- tc->prev = NULL;
- parent->child = tc;
- } else {
- tc->next = tc->prev = tc->parent = NULL;
- }
-
- return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- * Create a talloc pool
- */
-
-void *talloc_pool(const void *context, size_t size)
-{
- void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
- struct talloc_chunk *tc;
-
- if (unlikely(result == NULL)) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(result);
-
- tc->flags |= TALLOC_FLAG_POOL;
- tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
-
- *talloc_pool_objectcount(tc) = 1;
-
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
- VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
-#endif
-
- return result;
-}
-
-/*
- setup a destructor to be called on free of a pointer
-*/
-void _talloc_set_destructor(const void *ptr, void (*destructor)(void *))
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->destructor = destructor;
-}
-
-/*
- increase the reference count on a piece of memory.
-*/
-int talloc_increase_ref_count(const void *ptr)
-{
- if (unlikely(!talloc_reference(null_context, ptr))) {
- return -1;
- }
- return 0;
-}
-
-/*
- helper for talloc_reference()
-
- this is referenced by a function pointer and should not be inline
-*/
-static void talloc_reference_destructor(void *ptr)
-{
- struct talloc_reference_handle *handle = ptr;
- struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
- _TLIST_REMOVE(ptr_tc->refs, handle);
-}
-
-/*
- more efficient way to add a name to a pointer - the name must point to a
- true string constant
-*/
-static inline void _talloc_set_name_const(const void *ptr, const char *name)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->name = name;
-}
-
-/*
- internal talloc_named_const()
-*/
-static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
-{
- void *ptr;
-
- ptr = __talloc(context, size);
- if (unlikely(ptr == NULL)) {
- return NULL;
- }
-
- _talloc_set_name_const(ptr, name);
-
- return ptr;
-}
-
-/*
- make a secondary reference to a pointer, hanging off the given context.
- the pointer remains valid until both the original caller and this given
- context are freed.
-
- the major use for this is when two different structures need to reference the
- same underlying data, and you want to be able to free the two instances separately,
- and in either order
-*/
-void *_talloc_reference(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc;
- struct talloc_reference_handle *handle;
- if (unlikely(ptr == NULL)) return NULL;
-
- tc = talloc_chunk_from_ptr(ptr);
- handle = (struct talloc_reference_handle *)_talloc_named_const(context,
- sizeof(struct talloc_reference_handle),
- TALLOC_MAGIC_REFERENCE);
- if (unlikely(handle == NULL)) return NULL;
-
- /* note that we hang the destructor off the handle, not the
- main context as that allows the caller to still setup their
- own destructor on the context if they want to */
- talloc_set_destructor(handle, talloc_reference_destructor);
- handle->ptr = discard_const_p(void, ptr);
- _TLIST_ADD(tc->refs, handle);
- return handle->ptr;
-}
-
-
-/*
- internal talloc_free call
-*/
-static inline int _talloc_free(void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return -1;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (unlikely(tc->refs)) {
- int is_child;
- /* check this is a reference from a child or grantchild
- * back to it's parent or grantparent
- *
- * in that case we need to remove the reference and
- * call another instance of talloc_free() on the current
- * pointer.
- */
- is_child = talloc_is_parent(tc->refs, ptr);
- _talloc_free(tc->refs);
- if (is_child) {
- return _talloc_free(ptr);
- }
- return -1;
- }
-
- if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
- /* we have a free loop - stop looping */
- return 0;
- }
-
- if (unlikely(tc->destructor)) {
- talloc_destructor_t d = tc->destructor;
- if (d == (talloc_destructor_t)-1) {
- return -1;
- }
- tc->destructor = (talloc_destructor_t)-1;
- d(ptr);
- tc->destructor = NULL;
- }
-
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- while (tc->child) {
- /* we need to work out who will own an abandoned child
- if it cannot be freed. In priority order, the first
- choice is owner of any remaining reference to this
- pointer, the second choice is our parent, and the
- final choice is the null context. */
- void *child = TC_PTR_FROM_CHUNK(tc->child);
- const void *new_parent = null_context;
- if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- if (unlikely(_talloc_free(child) == -1)) {
- if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- talloc_steal(new_parent, child);
- }
- }
-
- tc->flags |= TALLOC_FLAG_FREE;
-
- if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
- struct talloc_chunk *pool;
- unsigned int *pool_object_count;
-
- pool = (tc->flags & TALLOC_FLAG_POOL)
- ? tc : (struct talloc_chunk *)tc->pool;
-
- pool_object_count = talloc_pool_objectcount(pool);
-
- if (*pool_object_count == 0) {
- TALLOC_ABORT("Pool object count zero!");
- }
-
- *pool_object_count -= 1;
-
- if (*pool_object_count == 0) {
- free(pool);
- }
- }
- else {
- free(tc);
- }
- return 0;
-}
-
-/*
- move a lump of memory from one talloc context to another return the
- ptr on success, or NULL if it could not be transferred.
- passing NULL as ptr will always return NULL with no side effects.
-*/
-void *_talloc_steal(const void *new_ctx, const void *ptr)
-{
- struct talloc_chunk *tc, *new_tc;
-
- if (unlikely(!ptr)) {
- return NULL;
- }
-
- if (unlikely(new_ctx == NULL)) {
- new_ctx = null_context;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (unlikely(new_ctx == NULL)) {
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->parent = tc->next = tc->prev = NULL;
- return discard_const_p(void, ptr);
- }
-
- new_tc = talloc_chunk_from_ptr(new_ctx);
-
- if (unlikely(tc == new_tc || tc->parent == new_tc)) {
- return discard_const_p(void, ptr);
- }
-
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->parent = new_tc;
- if (new_tc->child) new_tc->child->parent = NULL;
- _TLIST_ADD(new_tc->child, tc);
-
- return discard_const_p(void, ptr);
-}
-
-
-
-/*
- remove a secondary reference to a pointer. This undo's what
- talloc_reference() has done. The context and pointer arguments
- must match those given to a talloc_reference()
-*/
-static inline int talloc_unreference(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- struct talloc_reference_handle *h;
-
- if (unlikely(context == NULL)) {
- context = null_context;
- }
-
- for (h=tc->refs;h;h=h->next) {
- struct talloc_chunk *p = talloc_parent_chunk(h);
- if (p == NULL) {
- if (context == NULL) break;
- } else if (TC_PTR_FROM_CHUNK(p) == context) {
- break;
- }
- }
- if (h == NULL) {
- return -1;
- }
-
- return _talloc_free(h);
-}
-
-/*
- remove a specific parent context from a pointer. This is a more
- controlled varient of talloc_free()
-*/
-int talloc_unlink(const void *context, void *ptr)
-{
- struct talloc_chunk *tc_p, *new_p;
- void *new_parent;
-
- if (ptr == NULL) {
- return -1;
- }
-
- if (context == NULL) {
- context = null_context;
- }
-
- if (talloc_unreference(context, ptr) == 0) {
- return 0;
- }
-
- if (context == NULL) {
- if (talloc_parent_chunk(ptr) != NULL) {
- return -1;
- }
- } else {
- if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
- return -1;
- }
- }
-
- tc_p = talloc_chunk_from_ptr(ptr);
-
- if (tc_p->refs == NULL) {
- return _talloc_free(ptr);
- }
-
- new_p = talloc_parent_chunk(tc_p->refs);
- if (new_p) {
- new_parent = TC_PTR_FROM_CHUNK(new_p);
- } else {
- new_parent = NULL;
- }
-
- if (talloc_unreference(new_parent, ptr) != 0) {
- return -1;
- }
-
- talloc_steal(new_parent, ptr);
-
- return 0;
-}
-
-/*
- add a name to an existing pointer - va_list version
-*/
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->name = talloc_vasprintf(ptr, fmt, ap);
- if (likely(tc->name)) {
- _talloc_set_name_const(tc->name, ".name");
- }
- return tc->name;
-}
-
-/*
- add a name to an existing pointer
-*/
-const char *talloc_set_name(const void *ptr, const char *fmt, ...)
-{
- const char *name;
- va_list ap;
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
- return name;
-}
-
-
-/*
- create a named talloc pointer. Any talloc pointer can be named, and
- talloc_named() operates just like talloc() except that it allows you
- to name the pointer.
-*/
-void *talloc_named(const void *context, size_t size, const char *fmt, ...)
-{
- va_list ap;
- void *ptr;
- const char *name;
-
- ptr = __talloc(context, size);
- if (unlikely(ptr == NULL)) return NULL;
-
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
-
- if (unlikely(name == NULL)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- return ptr;
-}
-
-/*
- return the name of a talloc ptr, or "UNNAMED"
-*/
-const char *talloc_get_name(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
- return ".reference";
- }
- if (likely(tc->name)) {
- return tc->name;
- }
- return "UNNAMED";
-}
-
-
-/*
- check if a pointer has the given name. If it does, return the pointer,
- otherwise return NULL
-*/
-void *talloc_check_name(const void *ptr, const char *name)
-{
- const char *pname;
- if (unlikely(ptr == NULL)) return NULL;
- pname = talloc_get_name(ptr);
- if (likely(pname == name || strcmp(pname, name) == 0)) {
- return discard_const_p(void, ptr);
- }
- return NULL;
-}
-
-
-/*
- this is for compatibility with older versions of talloc
-*/
-void *talloc_init(const char *fmt, ...)
-{
- va_list ap;
- void *ptr;
- const char *name;
-
- /*
- * samba3 expects talloc_report_depth_cb(NULL, ...)
- * reports all talloc'ed memory, so we need to enable
- * null_tracking
- */
- talloc_enable_null_tracking();
-
- ptr = __talloc(NULL, 0);
- if (unlikely(ptr == NULL)) return NULL;
-
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
-
- if (unlikely(name == NULL)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- return ptr;
-}
-
-/*
- this is a replacement for the Samba3 talloc_destroy_pool functionality. It
- should probably not be used in new code. It's in here to keep the talloc
- code consistent across Samba 3 and 4.
-*/
-void talloc_free_children(void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- while (tc->child) {
- /* we need to work out who will own an abandoned child
- if it cannot be freed. In priority order, the first
- choice is owner of any remaining reference to this
- pointer, the second choice is our parent, and the
- final choice is the null context. */
- void *child = TC_PTR_FROM_CHUNK(tc->child);
- const void *new_parent = null_context;
- if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- if (unlikely(_talloc_free(child) == -1)) {
- if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- talloc_steal(new_parent, child);
- }
- }
-
- if ((tc->flags & TALLOC_FLAG_POOL)
- && (*talloc_pool_objectcount(tc) == 1)) {
- tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
- VALGRIND_MAKE_MEM_NOACCESS(
- tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
-#endif
- }
-}
-
-/*
- Allocate a bit of memory as a child of an existing pointer
-*/
-void *_talloc(const void *context, size_t size)
-{
- return __talloc(context, size);
-}
-
-/*
- externally callable talloc_set_name_const()
-*/
-void talloc_set_name_const(const void *ptr, const char *name)
-{
- _talloc_set_name_const(ptr, name);
-}
-
-/*
- create a named talloc pointer. Any talloc pointer can be named, and
- talloc_named() operates just like talloc() except that it allows you
- to name the pointer.
-*/
-void *talloc_named_const(const void *context, size_t size, const char *name)
-{
- return _talloc_named_const(context, size, name);
-}
-
-/*
- free a talloc pointer. This also frees all child pointers of this
- pointer recursively
-
- return 0 if the memory is actually freed, otherwise -1. The memory
- will not be freed if the ref_count is > 1 or the destructor (if
- any) returns non-zero
-*/
-int talloc_free(void *ptr)
-{
- return _talloc_free(ptr);
-}
-
-
-
-/*
- A talloc version of realloc. The context argument is only used if
- ptr is NULL
-*/
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
-{
- struct talloc_chunk *tc;
- void *new_ptr;
- bool malloced = false;
-
- /* size zero is equivalent to free() */
- if (unlikely(size == 0)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- if (unlikely(size >= MAX_TALLOC_SIZE)) {
- abort(); // return NULL;
- }
-
- /* realloc(NULL) is equivalent to malloc() */
- if (ptr == NULL) {
- return _talloc_named_const(context, size, name);
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- /* don't allow realloc on referenced pointers */
- if (unlikely(tc->refs)) {
- abort(); // return NULL;
- }
-
- /* don't shrink if we have less than 1k to gain */
- if ((size < tc->size) && ((tc->size - size) < 1024)) {
- tc->size = size;
- return ptr;
- }
-
- /* by resetting magic we catch users of the old memory */
- tc->flags |= TALLOC_FLAG_FREE;
-
-#if ALWAYS_REALLOC
- new_ptr = malloc(size + TC_HDR_SIZE);
- if (new_ptr) {
- memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
- free(tc);
- }
-#else
- if (tc->flags & TALLOC_FLAG_POOLMEM) {
-
- new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
- *talloc_pool_objectcount((struct talloc_chunk *)
- (tc->pool)) -= 1;
-
- if (new_ptr == NULL) {
- new_ptr = malloc(TC_HDR_SIZE+size);
- malloced = true;
- }
-
- if (new_ptr) {
- memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
- }
- }
- else {
- new_ptr = realloc(tc, size + TC_HDR_SIZE);
- }
-#endif
- if (unlikely(!new_ptr)) {
- tc->flags &= ~TALLOC_FLAG_FREE;
- abort(); // return NULL;
- }
-
- tc = (struct talloc_chunk *)new_ptr;
- tc->flags &= ~TALLOC_FLAG_FREE;
- if (malloced) {
- tc->flags &= ~TALLOC_FLAG_POOLMEM;
- }
- if (tc->parent) {
- tc->parent->child = tc;
- }
- if (tc->child) {
- tc->child->parent = tc;
- }
-
- if (tc->prev) {
- tc->prev->next = tc;
- }
- if (tc->next) {
- tc->next->prev = tc;
- }
-
- tc->size = size;
- _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
-
- return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- a wrapper around talloc_steal() for situations where you are moving a pointer
- between two structures, and want the old pointer to be set to NULL
-*/
-void *_talloc_move(const void *new_ctx, const void *_pptr)
-{
- const void **pptr = discard_const_p(const void *,_pptr);
- void *ret = _talloc_steal(new_ctx, *pptr);
- (*pptr) = NULL;
- return ret;
-}
-
-/*
- return the total size of a talloc pool (subtree)
-*/
-size_t talloc_total_size(const void *ptr)
-{
- size_t total = 0;
- struct talloc_chunk *c, *tc;
-
- if (ptr == NULL) {
- ptr = null_context;
- }
- if (ptr == NULL) {
- return 0;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return 0;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- total = tc->size;
- for (c=tc->child;c;c=c->next) {
- total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
- }
-
- tc->flags &= ~TALLOC_FLAG_LOOP;
-
- return total;
-}
-
-/*
- return the total number of blocks in a talloc pool (subtree)
-*/
-size_t talloc_total_blocks(const void *ptr)
-{
- size_t total = 0;
- struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return 0;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- total++;
- for (c=tc->child;c;c=c->next) {
- total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
- }
-
- tc->flags &= ~TALLOC_FLAG_LOOP;
-
- return total;
-}
-
-/*
- return the number of external references to a pointer
-*/
-size_t talloc_reference_count(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- struct talloc_reference_handle *h;
- size_t ret = 0;
-
- for (h=tc->refs;h;h=h->next) {
- ret++;
- }
- return ret;
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
- void (*callback)(const void *ptr,
- int depth, int max_depth,
- int is_ref,
- void *private_data),
- void *private_data)
-{
- struct talloc_chunk *c, *tc;
-
- if (ptr == NULL) {
- ptr = null_context;
- }
- if (ptr == NULL) return;
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return;
- }
-
- callback(ptr, depth, max_depth, 0, private_data);
-
- if (max_depth >= 0 && depth >= max_depth) {
- return;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
- for (c=tc->child;c;c=c->next) {
- if (c->name == TALLOC_MAGIC_REFERENCE) {
- struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
- callback(h->ptr, depth + 1, max_depth, 1, private_data);
- } else {
- talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
- }
- }
- tc->flags &= ~TALLOC_FLAG_LOOP;
-}
-
-static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
-{
- const char *name = talloc_get_name(ptr);
- FILE *f = (FILE *)_f;
-
- if (is_ref) {
- fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
- return;
- }
-
- if (depth == 0) {
- fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
- (max_depth < 0 ? "full " :""), name,
- (unsigned long)talloc_total_size(ptr),
- (unsigned long)talloc_total_blocks(ptr));
- return;
- }
-
- fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
- depth*4, "",
- name,
- (unsigned long)talloc_total_size(ptr),
- (unsigned long)talloc_total_blocks(ptr),
- (int)talloc_reference_count(ptr), ptr);
-
-#if 0
- fprintf(f, "content: ");
- if (talloc_total_size(ptr)) {
- int tot = talloc_total_size(ptr);
- int i;
-
- for (i = 0; i < tot; i++) {
- if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
- fprintf(f, "%c", ((char *)ptr)[i]);
- } else {
- fprintf(f, "~%02x", ((char *)ptr)[i]);
- }
- }
- }
- fprintf(f, "\n");
-#endif
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
-{
- talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
- fflush(f);
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_full(const void *ptr, FILE *f)
-{
- talloc_report_depth_file(ptr, 0, -1, f);
-}
-
-/*
- report on memory usage by all children of a pointer
-*/
-void talloc_report(const void *ptr, FILE *f)
-{
- talloc_report_depth_file(ptr, 0, 1, f);
-}
-
-/*
- report on any memory hanging off the null context
-*/
-static void talloc_report_null(void)
-{
- if (talloc_total_size(null_context) != 0) {
- talloc_report(null_context, stderr);
- }
-}
-
-/*
- report on any memory hanging off the null context
-*/
-static void talloc_report_null_full(void)
-{
- if (talloc_total_size(null_context) != 0) {
- talloc_report_full(null_context, stderr);
- }
-}
-
-/*
- enable tracking of the NULL context
-*/
-void talloc_enable_null_tracking(void)
-{
- if (null_context == NULL) {
- null_context = _talloc_named_const(NULL, 0, "null_context");
- }
-}
-
-/*
- disable tracking of the NULL context
-*/
-void talloc_disable_null_tracking(void)
-{
- _talloc_free(null_context);
- null_context = NULL;
-}
-
-/*
- enable leak reporting on exit
-*/
-void talloc_enable_leak_report(void)
-{
- talloc_enable_null_tracking();
- atexit(talloc_report_null);
-}
-
-/*
- enable full leak reporting on exit
-*/
-void talloc_enable_leak_report_full(void)
-{
- talloc_enable_null_tracking();
- atexit(talloc_report_null_full);
-}
-
-/*
- talloc and zero memory.
-*/
-void *_talloc_zero(const void *ctx, size_t size, const char *name)
-{
- void *p = _talloc_named_const(ctx, size, name);
-
- if (p) {
- memset(p, '\0', size);
- }
-
- return p;
-}
-
-/*
- memdup with a talloc.
-*/
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
-{
- void *newp = _talloc_named_const(t, size, name);
-
- if (likely(newp)) {
- memcpy(newp, p, size);
- }
-
- return newp;
-}
-
-static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
-{
- char *ret;
-
- ret = (char *)__talloc(t, len + 1);
- if (unlikely(!ret)) return NULL;
-
- memcpy(ret, p, len);
- ret[len] = 0;
-
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-/*
- strdup with a talloc
-*/
-char *talloc_strdup(const void *t, const char *p)
-{
- if (unlikely(!p)) return NULL;
- return __talloc_strlendup(t, p, strlen(p));
-}
-
-/*
- strndup with a talloc
-*/
-char *talloc_strndup(const void *t, const char *p, size_t n)
-{
- if (unlikely(!p)) return NULL;
- return __talloc_strlendup(t, p, strnlen(p, n));
-}
-
-static inline char *__talloc_strlendup_append(char *s, size_t slen,
- const char *a, size_t alen)
-{
- char *ret;
-
- ret = talloc_realloc(NULL, s, char, slen + alen + 1);
- if (unlikely(!ret)) return NULL;
-
- /* append the string and the trailing \0 */
- memcpy(&ret[slen], a, alen);
- ret[slen+alen] = 0;
-
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-/*
- * Appends at the end of the string.
- */
-char *talloc_strdup_append(char *s, const char *a)
-{
- if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
-}
-
-/*
- * Appends at the end of the talloc'ed buffer,
- * not the end of the string.
- */
-char *talloc_strdup_append_buffer(char *s, const char *a)
-{
- size_t slen;
-
- if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- slen = talloc_get_size(s);
- if (likely(slen > 0)) {
- slen--;
- }
-
- return __talloc_strlendup_append(s, slen, a, strlen(a));
-}
-
-/*
- * Appends at the end of the string.
- */
-char *talloc_strndup_append(char *s, const char *a, size_t n)
-{
- if (unlikely(!s)) {
- return talloc_strndup(NULL, a, n);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
-}
-
-/*
- * Appends at the end of the talloc'ed buffer,
- * not the end of the string.
- */
-char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
-{
- size_t slen;
-
- if (unlikely(!s)) {
- return talloc_strndup(NULL, a, n);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- slen = talloc_get_size(s);
- if (likely(slen > 0)) {
- slen--;
- }
-
- return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
-}
-
-#ifndef HAVE_VA_COPY
-#ifdef HAVE___VA_COPY
-#define va_copy(dest, src) __va_copy(dest, src)
-#else
-#define va_copy(dest, src) (dest) = (src)
-#endif
-#endif
-
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
-{
- int len;
- char *ret;
- va_list ap2;
- char c;
-
- /* this call looks strange, but it makes it work on older solaris boxes */
- va_copy(ap2, ap);
- len = vsnprintf(&c, 1, fmt, ap2);
- va_end(ap2);
- if (unlikely(len < 0)) {
- abort(); // return NULL;
- }
-
- ret = (char *)__talloc(t, len+1);
- if (unlikely(!ret)) return NULL;
-
- va_copy(ap2, ap);
- vsnprintf(ret, len+1, fmt, ap2);
- va_end(ap2);
-
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-
-/*
- Perform string formatting, and return a pointer to newly allocated
- memory holding the result, inside a memory pool.
- */
-char *talloc_asprintf(const void *t, const char *fmt, ...)
-{
- va_list ap;
- char *ret;
-
- va_start(ap, fmt);
- ret = talloc_vasprintf(t, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
- const char *fmt, va_list ap)
- PRINTF_ATTRIBUTE(3,0);
-
-static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
- const char *fmt, va_list ap)
-{
- ssize_t alen;
- va_list ap2;
- char c;
-
- va_copy(ap2, ap);
- alen = vsnprintf(&c, 1, fmt, ap2);
- va_end(ap2);
-
- if (alen <= 0) {
- /* Either the vsnprintf failed or the format resulted in
- * no characters being formatted. In the former case, we
- * ought to return NULL, in the latter we ought to return
- * the original string. Most current callers of this
- * function expect it to never return NULL.
- */
- return s;
- }
-
- s = talloc_realloc(NULL, s, char, slen + alen + 1);
- if (!s) return NULL;
-
- va_copy(ap2, ap);
- vsnprintf(s + slen, alen + 1, fmt, ap2);
- va_end(ap2);
-
- _talloc_set_name_const(s, s);
- return s;
-}
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved. Good for gradually
- * accumulating output into a string buffer. Appends at the end
- * of the string.
- **/
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
-{
- if (unlikely(!s)) {
- return talloc_vasprintf(NULL, fmt, ap);
- }
-
- return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
-}
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved. Always appends at the
- * end of the talloc'ed buffer, not the end of the string.
- **/
-char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
-{
- size_t slen;
-
- if (unlikely(!s)) {
- return talloc_vasprintf(NULL, fmt, ap);
- }
-
- slen = talloc_get_size(s);
- if (likely(slen > 0)) {
- slen--;
- }
-
- return __talloc_vaslenprintf_append(s, slen, fmt, ap);
-}
-
-/*
- Realloc @p s to append the formatted result of @p fmt and return @p
- s, which may have moved. Good for gradually accumulating output
- into a string buffer.
- */
-char *talloc_asprintf_append(char *s, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- s = talloc_vasprintf_append(s, fmt, ap);
- va_end(ap);
- return s;
-}
-
-/*
- Realloc @p s to append the formatted result of @p fmt and return @p
- s, which may have moved. Good for gradually accumulating output
- into a buffer.
- */
-char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- s = talloc_vasprintf_append_buffer(s, fmt, ap);
- va_end(ap);
- return s;
-}
-
-/*
- alloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- abort(); // return NULL;
- }
- return _talloc_named_const(ctx, el_size * count, name);
-}
-
-/*
- alloc an zero array, checking for integer overflow in the array size
-*/
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- abort(); // return NULL;
- }
- return _talloc_zero(ctx, el_size * count, name);
-}
-
-/*
- realloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- abort(); // return NULL;
- }
- return _talloc_realloc(ctx, ptr, el_size * count, name);
-}
-
-/*
- a function version of talloc_realloc(), so it can be passed as a function pointer
- to libraries that want a realloc function (a realloc function encapsulates
- all the basic capabilities of an allocation library, which is why this is useful)
-*/
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
-{
- return _talloc_realloc(context, ptr, size, NULL);
-}
-
-
-static void talloc_autofree_destructor(void *ptr)
-{
- autofree_context = NULL;
-}
-
-static void talloc_autofree(void)
-{
- _talloc_free(autofree_context);
-}
-
-/*
- return a context which will be auto-freed on exit
- this is useful for reducing the noise in leak reports
-*/
-void *talloc_autofree_context(void)
-{
- if (autofree_context == NULL) {
- autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
- talloc_set_destructor(autofree_context, talloc_autofree_destructor);
- atexit(talloc_autofree);
- }
- return autofree_context;
-}
-
-size_t talloc_get_size(const void *context)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL)
- return 0;
-
- tc = talloc_chunk_from_ptr(context);
-
- return tc->size;
-}
-
-/*
- find a parent of this context that has the given name, if any
-*/
-void *talloc_find_parent_byname(const void *context, const char *name)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(context);
- while (tc) {
- if (tc->name && strcmp(tc->name, name) == 0) {
- return TC_PTR_FROM_CHUNK(tc);
- }
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- return NULL;
-}
-
-/*
- show the parentage of a context
-*/
-void talloc_show_parents(const void *context, FILE *file)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- fprintf(file, "talloc no parents for NULL\n");
- return;
- }
-
- tc = talloc_chunk_from_ptr(context);
- fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
- while (tc) {
- fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- fflush(file);
-}
-
-/*
- return 1 if ptr is a parent of context
-*/
-int talloc_is_parent(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- return 0;
- }
-
- tc = talloc_chunk_from_ptr(context);
- while (tc) {
- if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- return 0;
-}
diff --git a/talloc.h b/talloc.h
index 60dda32811..1eeef8dca1 100644
--- a/talloc.h
+++ b/talloc.h
@@ -1,181 +1,7 @@
-#ifndef _TALLOC_H_
-#define _TALLOC_H_
-/*
- Unix SMB/CIFS implementation.
- Samba temporary memory allocation functions
-
- Copyright (C) Andrew Tridgell 2004-2005
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "compat/compiler.h"
-/* HACK: libsmbclient uses dynamically linked libtalloc.so which has
- * identically named symbols. This name collision caused a crash under
- * stream_smb when trying to play anything with smb://. This hack
- * prevents the symbols declared here from being visible to outside
- * shared libraries and fixes the crash.
- */
-#pragma GCC visibility push(hidden)
-
-/* this is only needed for compatibility with the old talloc */
-typedef void TALLOC_CTX;
-
-/*
- this uses a little trick to allow __LINE__ to be stringified
-*/
-#ifndef __location__
-#define __TALLOC_STRING_LINE1__(s) #s
-#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
-#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
-#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
-#endif
-
-#ifndef TALLOC_DEPRECATED
-#define TALLOC_DEPRECATED 0
-#endif
-
-/* try to make talloc_set_destructor() and talloc_steal() type safe,
- if we have a recent gcc */
-#if defined(__clang__) && defined(__llvm__)
-#define _TALLOC_TYPEOF(ptr) void *
-#define talloc_steal(ctx, ptr) _talloc_steal((ctx),(ptr))
-#elif (__GNUC__ >= 3)
-#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
-/* this extremely strange macro is to avoid some braindamaged warning
- stupidity in gcc 4.1.x */
-#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
-#else
-#define _TALLOC_TYPEOF(ptr) void *
-#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
-#endif
-#define talloc_set_destructor(ptr, function) \
- _talloc_set_destructor((ptr), (function))
-
-#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
-#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
-
-/* useful macros for creating type checked pointers */
-#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
-#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
-#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
-
-#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
-
-#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
-#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
-
-#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
-#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
-#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
-#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
-
-#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
-#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
-
-#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
-
-#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
-#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
-
-#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
-
-#if TALLOC_DEPRECATED
-#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
-#define talloc_p(ctx, type) talloc(ctx, type)
-#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
-#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
-#define talloc_destroy(ctx) talloc_free(ctx)
-#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
-#endif
-
-/* The following definitions come from talloc.c */
-void *_talloc(const void *context, size_t size);
-void *talloc_pool(const void *context, size_t size);
-void _talloc_set_destructor(const void *ptr, void (*destructor)(void *));
-int talloc_increase_ref_count(const void *ptr);
-size_t talloc_reference_count(const void *ptr);
-void *_talloc_reference(const void *context, const void *ptr);
-int talloc_unlink(const void *context, void *ptr);
-const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-void talloc_set_name_const(const void *ptr, const char *name);
-void *talloc_named(const void *context, size_t size,
- const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
-void *talloc_named_const(const void *context, size_t size, const char *name);
-const char *talloc_get_name(const void *ptr);
-void *talloc_check_name(const void *ptr, const char *name);
-void *talloc_parent(const void *ptr);
-const char *talloc_parent_name(const void *ptr);
-void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
-int talloc_free(void *ptr);
-void talloc_free_children(void *ptr);
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
-void *_talloc_steal(const void *new_ctx, const void *ptr);
-void *_talloc_move(const void *new_ctx, const void *pptr);
-size_t talloc_total_size(const void *ptr);
-size_t talloc_total_blocks(const void *ptr);
-void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
- void (*callback)(const void *ptr,
- int depth, int max_depth,
- int is_ref,
- void *private_data),
- void *private_data);
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
-void talloc_report_full(const void *ptr, FILE *f);
-void talloc_report(const void *ptr, FILE *f);
-void talloc_enable_null_tracking(void);
-void talloc_disable_null_tracking(void);
-void talloc_enable_leak_report(void);
-void talloc_enable_leak_report_full(void);
-void *_talloc_zero(const void *ctx, size_t size, const char *name);
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
-void *talloc_autofree_context(void);
-size_t talloc_get_size(const void *ctx);
-void *talloc_find_parent_byname(const void *ctx, const char *name);
-void talloc_show_parents(const void *context, FILE *file);
-int talloc_is_parent(const void *context, const void *ptr);
-
-char *talloc_strdup(const void *t, const char *p);
-char *talloc_strdup_append(char *s, const char *a);
-char *talloc_strdup_append_buffer(char *s, const char *a);
-
-char *talloc_strndup(const void *t, const char *p, size_t n);
-char *talloc_strndup_append(char *s, const char *a, size_t n);
-char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
-
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-
-// end of visibility hack from above
-#pragma GCC visibility pop
-#endif
+#include "ta/ta_talloc.h"