Commit 76ae790f authored by Rusty Russell's avatar Rusty Russell

New talloc_set for auto-cleanup.

parent f88058f6
...@@ -789,6 +789,35 @@ void *_talloc(const void *context, size_t size) ...@@ -789,6 +789,35 @@ void *_talloc(const void *context, size_t size)
return __talloc(context, size); return __talloc(context, size);
} }
static int talloc_destroy_pointer(void ***pptr)
{
if ((uintptr_t)**pptr < getpagesize())
TALLOC_ABORT("Double free or invalid talloc_set?");
/* Invalidate pointer so it can't be used again. */
**pptr = (void *)1;
return 0;
}
void _talloc_set(void *ptr, const void *ctx, size_t size, const char *name)
{
void ***child;
void **pptr = ptr;
*pptr = talloc_named_const(ctx, size, name);
if (unlikely(!*pptr))
return;
child = talloc(*pptr, void **);
if (unlikely(!child)) {
talloc_free(*pptr);
*pptr = NULL;
return;
}
*child = pptr;
talloc_set_name_const(child, "talloc_set destructor");
talloc_set_destructor(child, talloc_destroy_pointer);
}
/* /*
externally callable talloc_set_name_const() externally callable talloc_set_name_const()
*/ */
......
...@@ -87,6 +87,30 @@ ...@@ -87,6 +87,30 @@
*/ */
#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) #define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
/**
* talloc_set - allocate dynamic memory for a type, into a pointer
* @ptr: pointer to the pointer to assign.
* @ctx: context to be parent of this allocation, or NULL.
*
* talloc_set() does a talloc, but also adds a destructor which will make the
* pointer invalid when it is freed. This can find many use-after-free bugs.
*
* Note that the destructor is chained off a zero-length allocation, and so
* is not affected by talloc_set_destructor().
*
* Example:
* unsigned int *a;
* a = talloc(NULL, unsigned int);
* talloc_set(&b, a, unsigned int);
* talloc_free(a);
* *b = 1; // This will crash!
*
* See Also:
* talloc.
*/
#define talloc_set(pptr, ctx) \
_talloc_set((pptr), (ctx), sizeof(&**(pptr)), __location__)
/** /**
* talloc_free - free talloc'ed memory and its children * talloc_free - free talloc'ed memory and its children
* @ptr: the talloced pointer to free * @ptr: the talloced pointer to free
...@@ -940,6 +964,7 @@ void *talloc_add_external(const void *ctx, ...@@ -940,6 +964,7 @@ void *talloc_add_external(const void *ctx,
/* The following definitions come from talloc.c */ /* The following definitions come from talloc.c */
void *_talloc(const void *context, size_t size); void *_talloc(const void *context, size_t size);
void _talloc_set(void *ptr, const void *ctx, size_t size, const char *name);
void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)); void _talloc_set_destructor(const void *ptr, int (*destructor)(void *));
size_t talloc_reference_count(const void *ptr); size_t talloc_reference_count(const void *ptr);
void *_talloc_reference(const void *context, const void *ptr); void *_talloc_reference(const void *context, const void *ptr);
......
#include "talloc/talloc.c"
int main(void)
{
int *p;
talloc_set(
#ifdef FAIL
p
#else
&p
#endif
, NULL);
return 0;
}
#include "talloc/talloc.c"
#include "tap/tap.h"
#include <assert.h>
int main(void)
{
char *c;
int *i;
plan_tests(12);
/* Set C to a valid pointer, with correct parent. */
talloc_set(&c, NULL);
ok1(c >= (char *)(intptr_t)getpagesize());
ok1(talloc_parent(c) == NULL);
/* Free it, should blatt c. */
talloc_free(c);
ok1(c);
ok1(c < (char *)(intptr_t)getpagesize());
/* Same test, indirect. */
talloc_set(&i, NULL);
talloc_set(&c, i);
ok1(c >= (char *)(intptr_t)getpagesize());
ok1(i >= (int *)(intptr_t)getpagesize());
ok1(talloc_parent(i) == NULL);
ok1(talloc_parent(c) == i);
talloc_free(i);
ok1(c);
ok1(c < (char *)(intptr_t)getpagesize());
ok1(i);
ok1(i < (int *)(intptr_t)getpagesize());
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment