*/
static void *null_context;
static void *autofree_context;
+static void *no_owner_context;
+void *talloc_no_owner_context(void);
+static inline int _talloc_free(void *ptr);
struct talloc_reference_handle {
struct talloc_reference_handle *next, *prev;
#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_fn)(const char *reason);
+
+void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ talloc_abort_fn = abort_fn;
+}
+
+static void talloc_abort(const char *reason)
+{
+ if (!talloc_abort_fn) {
+ TALLOC_ABORT(reason);
+ }
+
+ talloc_abort_fn(reason);
+}
+
static void talloc_abort_double_free(void)
{
- TALLOC_ABORT("Bad talloc magic value - double free");
+ talloc_abort("Bad talloc magic value - double free");
}
static void talloc_abort_unknown_value(void)
{
- TALLOC_ABORT("Bad talloc magic value - unknown value");
+ talloc_abort("Bad talloc magic value - unknown value");
}
/* panic if we get a bad magic value */
{
struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
_TLIST_REMOVE(ptr_tc->refs, handle);
+ /* If ptr_tc has no refs left and is owner by no_owner_context then we free it */
+ if (ptr_tc->refs == NULL &&
+ no_owner_context && talloc_parent(handle->ptr) == no_owner_context) {
+ _talloc_free(handle->ptr);
+ }
return 0;
}
tc = talloc_chunk_from_ptr(ptr);
if (unlikely(tc->refs)) {
+ /*TODO: INSTEAD:
+ Rather than delete child references,
+ If a node descends from no_owner_context and so do all his references then it can be deleted
+ */
int is_child;
/* check this is a reference from a child or grantchild
* back to it's parent or grantparent
* pointer.
*/
is_child = talloc_is_parent(tc->refs, ptr);
- _talloc_free(tc->refs);
if (is_child) {
+ _talloc_free(tc->refs);
return _talloc_free(ptr);
+ } else {
+ /* we can't free if we have refs, so no_owner_context becomes the owner */
+ _talloc_steal(talloc_no_owner_context(), ptr);
}
return -1;
}
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);
- }
+ const void *new_parent = talloc_no_owner_context();
+/* we are moving this problem of who should own the can't-free to the top of the function */
+//HERE
+// 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 talloc_free fails because of refs and not due to the destructor,
+ it will already have a new owner no_owner_context */
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);
- }
+// making dead mans parent the owner could be a memory leak. no_owner_context will destroy with refs going
+// 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);
}
}
pool_object_count = talloc_pool_objectcount(pool);
if (*pool_object_count == 0) {
- TALLOC_ABORT("Pool object count zero!");
+ talloc_abort("Pool object count zero!");
}
*pool_object_count -= 1;
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 _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);
-
+//HERE
+// 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);
+ talloc_steal(talloc_no_owner_context(), ptr);
return 0;
}
const char *name,
const char *expected)
{
- TALLOC_ABORT("Type missmatch");
+ const char *reason;
+
+ reason = talloc_asprintf(NULL,
+ "%s: Type mismatch: name[%s] expected[%s]",
+ location,
+ name?name:"NULL",
+ expected);
+ if (!reason) {
+ reason = "Type mismatch";
+ }
+
+ talloc_abort(reason);
}
void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
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;
+ const void *new_parent = talloc_no_owner_context();
+//HERE
if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+// struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+// if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ new_parent = talloc_no_owner_context();
}
if (unlikely(_talloc_free(child) == -1)) {
if (new_parent == null_context) {
return NULL;
}
+ /* don't let anybody try to realloc a talloc_pool */
+ if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
+ return NULL;
+ }
+
/* don't shrink if we have less than 1k to gain */
if ((size < tc->size) && ((tc->size - size) < 1024)) {
tc->size = size;
FILE *f = (FILE *)_f;
if (is_ref) {
- fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+ if (talloc_parent(ptr) == no_owner_context && no_owner_context) {
+ fprintf(f, "%*sreference to: %s [no owner]\n", depth*4, "", name);
+ } else {
+ fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+ }
return;
}
return autofree_context;
}
+/* this is only used by the test suite so that failures from on test don't
+ confuse the results of the next test */
+void talloc_erase_no_owner_context(void)
+{
+ /* force free all children */
+ if (no_owner_context) {
+ struct talloc_chunk *tc;
+ tc = talloc_chunk_from_ptr(no_owner_context);
+ tc->child=NULL;
+ tc->refs=NULL;
+ _talloc_free(no_owner_context);
+ no_owner_context=NULL;
+ }
+}
+
+void *talloc_no_owner_context(void)
+{
+ if (no_owner_context == NULL) {
+ no_owner_context = _talloc_named_const(NULL, 0, "no_owner_context");
+ }
+ return no_owner_context;
+}
+
size_t talloc_get_size(const void *context)
{
struct talloc_chunk *tc;