inspired by http://swapped.cc/halloc/
*/
-#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
+#include "replace.h"
+#include "talloc.h"
+
+#ifdef TALLOC_BUILD_VERSION_MAJOR
+#if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR)
+#error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR"
#endif
-#ifdef realloc
-#undef realloc
#endif
-#define _TALLOC_SAMBA3
-#endif /* (SAMBA_VERSION_MAJOR<4) */
-#endif /* _SAMBA_BUILD_ */
-#ifndef _TALLOC_SAMBA3
-#include "replace.h"
-#include "talloc.h"
-#endif /* not _TALLOC_SAMBA3 */
+#ifdef TALLOC_BUILD_VERSION_MINOR
+#if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR)
+#error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR"
+#endif
+#endif
/* use this to force every realloc to change the pointer, to stress test
code that might not cope */
#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC_V1 0xe814ec70
-#define TALLOC_MAGIC_V2 0xe814ec80
-#define TALLOC_MAGIC TALLOC_MAGIC_V2
+#define TALLOC_MAGIC_BASE 0xe814ec70
+#define TALLOC_MAGIC ( \
+ TALLOC_MAGIC_BASE + \
+ (TALLOC_VERSION_MAJOR << 12) + \
+ (TALLOC_VERSION_MINOR << 4) \
+)
+
#define TALLOC_FLAG_FREE 0x01
#define TALLOC_FLAG_LOOP 0x02
#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+int talloc_version_major(void)
+{
+ return TALLOC_VERSION_MAJOR;
+}
+
+int talloc_version_minor(void)
+{
+ return TALLOC_VERSION_MINOR;
+}
+
+static void (*talloc_log_fn)(const char *message);
+
+void talloc_set_log_fn(void (*log_fn)(const char *message))
+{
+ talloc_log_fn = log_fn;
+}
+
+static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+static void talloc_log(const char *fmt, ...)
+{
+ va_list ap;
+ char *message;
+
+ if (!talloc_log_fn) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ message = talloc_vasprintf(NULL, fmt, ap);
+ va_end(ap);
+
+ talloc_log_fn(message);
+ talloc_free(message);
+}
+
+static void talloc_log_stderr(const char *message)
+{
+ fprintf(stderr, "%s", message);
+}
+
+void talloc_set_log_stderr(void)
+{
+ talloc_set_log_fn(talloc_log_stderr);
+}
+
static void (*talloc_abort_fn)(const char *reason);
void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
static void talloc_abort(const char *reason)
{
+ talloc_log("%s\n", reason);
+
if (!talloc_abort_fn) {
TALLOC_ABORT(reason);
}
talloc_abort_fn(reason);
}
-static void talloc_abort_magic_v1(void)
+static void talloc_abort_magic(unsigned magic)
{
- talloc_abort("Bad talloc magic value - old magic v1 used");
+ unsigned striped = magic - TALLOC_MAGIC_BASE;
+ unsigned major = (striped & 0xFFFFF000) >> 12;
+ unsigned minor = (striped & 0x00000FF0) >> 4;
+ talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n",
+ magic, major, minor,
+ TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR);
+ talloc_abort("Bad talloc magic value - wrong talloc version used/mixed");
}
static void talloc_abort_double_free(void)
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 & (~0xF)) == TALLOC_MAGIC_V1) {
- talloc_abort_magic_v1();
+ if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) {
+ talloc_abort_magic(tc->flags & (~0xF));
return NULL;
}
if (tc->flags & TALLOC_FLAG_FREE) {
+ talloc_log("talloc: double free error - first free may be at %s\n", tc->name);
talloc_abort_double_free();
return NULL;
} else {
/*
internal talloc_free call
*/
-static inline int _talloc_free_internal(void *ptr)
+static inline int _talloc_free_internal(void *ptr, const char *location)
{
struct talloc_chunk *tc;
* pointer.
*/
is_child = talloc_is_parent(tc->refs, ptr);
- _talloc_free_internal(tc->refs);
+ _talloc_free_internal(tc->refs, location);
if (is_child) {
- return _talloc_free_internal(ptr);
+ return _talloc_free_internal(ptr, location);
}
return -1;
}
struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
- if (unlikely(_talloc_free_internal(child) == -1)) {
+ if (unlikely(_talloc_free_internal(child, location) == -1)) {
if (new_parent == null_context) {
struct talloc_chunk *p = talloc_parent_chunk(ptr);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
tc->flags |= TALLOC_FLAG_FREE;
+ /* we mark the freed memory with where we called the free
+ * from. This means on a double free error we can report where
+ * the first free came from
+ */
+ tc->name = location;
+
if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
struct talloc_chunk *pool;
unsigned int *pool_object_count;
if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) {
struct talloc_reference_handle *h;
-#if DEVELOPER
- fprintf(stderr, "WARNING: talloc_steal with references at %s\n", location);
-#endif
+
+ talloc_log("WARNING: talloc_steal with references at %s\n",
+ location);
+
for (h=tc->refs; h; h=h->next) {
-#if DEVELOPER
- fprintf(stderr, "\treference at %s\n", h->location);
-#endif
+ talloc_log("\treference at %s\n",
+ h->location);
}
}
if (_talloc_steal_internal(new_parent, h) != h) {
return NULL;
}
- return (void *)ptr;
+ return discard_const_p(void, ptr);
}
}
return -1;
}
- return _talloc_free_internal(h);
+ return _talloc_free_internal(h, __location__);
}
/*
tc_p = talloc_chunk_from_ptr(ptr);
if (tc_p->refs == NULL) {
- return _talloc_free_internal(ptr);
+ return _talloc_free_internal(ptr, __location__);
}
new_p = talloc_parent_chunk(tc_p->refs);
va_end(ap);
if (unlikely(name == NULL)) {
- _talloc_free_internal(ptr);
+ _talloc_free_internal(ptr, __location__);
return NULL;
}
va_end(ap);
if (unlikely(name == NULL)) {
- _talloc_free_internal(ptr);
+ _talloc_free_internal(ptr, __location__);
return NULL;
}
if (unlikely(tc->refs != NULL)) {
struct talloc_reference_handle *h;
-#if DEVELOPER
- fprintf(stderr, "ERROR: talloc_free with references at %s\n", location);
-#endif
+
+ talloc_log("ERROR: talloc_free with references at %s\n",
+ location);
+
for (h=tc->refs; h; h=h->next) {
-#if DEVELOPER
- fprintf(stderr, "\treference at %s\n", h->location);
-#endif
+ talloc_log("\treference at %s\n",
+ h->location);
}
return -1;
}
- return _talloc_free_internal(ptr);
+ return _talloc_free_internal(ptr, location);
}
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, (void *)*pptr);
+ void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr));
(*pptr) = NULL;
return ret;
}
*/
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);
+ if (f) {
+ talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
+ fflush(f);
+ }
}
/*
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");
+ if (autofree_context != NULL) {
+ talloc_reparent(NULL, null_context, autofree_context);
+ }
+ }
+}
+
+/*
+ enable tracking of the NULL context, not moving the autofree context
+ into the NULL context. This is needed for the talloc testsuite
+*/
+void talloc_enable_null_tracking_no_autofree(void)
{
if (null_context == NULL) {
null_context = _talloc_named_const(NULL, 0, "null_context");
*/
void talloc_disable_null_tracking(void)
{
+ if (null_context != NULL) {
+ /* we have to move any children onto the real NULL
+ context */
+ struct talloc_chunk *tc, *tc2;
+ tc = talloc_chunk_from_ptr(null_context);
+ for (tc2 = tc->child; tc2; tc2=tc2->next) {
+ if (tc2->parent == tc) tc2->parent = NULL;
+ if (tc2->prev == tc) tc2->prev = NULL;
+ }
+ for (tc2 = tc->next; tc2; tc2=tc2->next) {
+ if (tc2->parent == tc) tc2->parent = NULL;
+ if (tc2->prev == tc) tc2->prev = NULL;
+ }
+ tc->child = NULL;
+ tc->next = NULL;
+ }
talloc_free(null_context);
null_context = NULL;
}
}
return 0;
}
-
-
-
-
-/* ABI compat functions (do NOT append anything beyond thess functions,
- * keep them as the last ones in the file) */
-
-static const char *talloc_ABI_compat_location = "Called from compatibility function";
-
-/* ABI compat function (don't use) */
-void *_talloc_reference(const void *context, const void *ptr) {
- return _talloc_reference_loc(context, ptr, talloc_ABI_compat_location);
-}
-
-/* ABI compat function (don't use) */
-void *_talloc_steal(const void *new_ctx, const void *ptr)
-{
- return _talloc_steal_internal(new_ctx, ptr);
-}
-
-#undef talloc_free
-int talloc_free(void *ptr);
-int talloc_free(void *ptr)
-{
- return _talloc_free_internal(ptr);
-}
-
-/* DO NOT APPEND ANYTHING BEYOND THIS POINT */