final choice is the null context. */
void *child = TC_PTR_FROM_CHUNK(tc->child);
const void *new_parent = null_context;
+ struct talloc_chunk *old_parent = NULL;
if (unlikely(tc->child->refs)) {
struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
+ /* finding the parent here is potentially quite
+ expensive, but the alternative, which is to change
+ talloc to always have a valid tc->parent pointer,
+ makes realloc more expensive where there are a
+ large number of children.
+
+ The reason we need the parent pointer here is that
+ if _talloc_free_internal() fails due to references
+ or a failing destructor we need to re-parent, but
+ the free call can invalidate the prev pointer.
+ */
+ if (new_parent == null_context && (tc->child->refs || tc->child->destructor)) {
+ old_parent = talloc_parent_chunk(ptr);
+ }
if (unlikely(_talloc_free(child) == -1)) {
if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ struct talloc_chunk *p = old_parent;
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
__talloc_steal(new_parent, child);
/*
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) PRINTF_FMT(2,0);
static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
{
void _talloc_set(void *ptr, const void *ctx, size_t size, const char *name)
{
void ***child;
- void **pptr = ptr;
+ void *p;
- *pptr = talloc_named_const(ctx, size, name);
- if (unlikely(!*pptr))
- return;
+ p = talloc_named_const(ctx, size, name);
+ if (unlikely(!p))
+ goto set_ptr;
- child = talloc(*pptr, void **);
+ child = talloc(p, void **);
if (unlikely(!child)) {
- talloc_free(*pptr);
- *pptr = NULL;
- return;
+ talloc_free(p);
+ p = NULL;
+ goto set_ptr;
}
- *child = pptr;
+ *child = ptr;
talloc_set_name_const(child, "talloc_set destructor");
talloc_set_destructor(child, talloc_destroy_pointer);
+
+set_ptr:
+ /* memcpy rather than cast avoids aliasing problems. */
+ memcpy(ptr, &p, sizeof(p));
}
/*