code that might not cope */
#define ALWAYS_REALLOC 0
+/* How many bottom bits of flags are not magic value */
+#define TALLOC_FLAG_BITS 5
+
+#define TALLOC_FLAG_BITMASK ((1 << TALLOC_FLAG_BITS)-1)
+#define TALLOC_MAGIC_BITMASK (~TALLOC_FLAG_BITMASK)
+
+#define TALLOC_MAGIC_MAJOR_SHIFT (7 + TALLOC_FLAG_BITS)
+#define TALLOC_MAGIC_MINOR_SHIFT TALLOC_FLAG_BITS
+
+#define TALLOC_MAGIC_BASE_BITMASK (~(1 << TALLOC_MAGIC_MAJOR_SHIFT))
#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC_BASE 0xe814ec70
+#define TALLOC_MAGIC_BASE 0xe814ec60
#define TALLOC_MAGIC ( \
TALLOC_MAGIC_BASE + \
- (TALLOC_VERSION_MAJOR << 12) + \
- (TALLOC_VERSION_MINOR << 4) \
+ (TALLOC_VERSION_MAJOR << TALLOC_MAGIC_MAJOR_SHIFT) + \
+ (TALLOC_VERSION_MINOR << TALLOC_MAGIC_MINOR_SHIFT) \
)
#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_FLAG_MAY_REF 0x10 /* Warn as if this has multiple references */
#define TALLOC_MAGIC_REFERENCE ((const char *)1)
/* by default we abort when given a bad pointer (such as when talloc_free() is called
static void talloc_abort_magic(unsigned magic)
{
unsigned striped = magic - TALLOC_MAGIC_BASE;
- unsigned major = (striped & 0xFFFFF000) >> 12;
- unsigned minor = (striped & 0x00000FF0) >> 4;
+ unsigned major = (striped >> TALLOC_MAGIC_MAJOR_SHIFT);
+ unsigned minor = ((striped & ((1 << TALLOC_MAGIC_MAJOR_SHIFT)-1)) >> TALLOC_MAGIC_MINOR_SHIFT);
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);
{
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 & (~0xFFF)) == TALLOC_MAGIC_BASE) {
- talloc_abort_magic(tc->flags & (~0xF));
+ if (unlikely((tc->flags & (TALLOC_FLAG_FREE | TALLOC_MAGIC_BITMASK)) != TALLOC_MAGIC)) {
+ if ((tc->flags & TALLOC_MAGIC_BITMASK) == TALLOC_MAGIC_BASE) {
+ talloc_abort_magic(tc->flags & TALLOC_MAGIC_BITMASK);
return NULL;
}
_PUBLIC_ void *talloc_parent(const void *ptr)
{
struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+
+ if (ptr && talloc_chunk_from_ptr(ptr)->flags & TALLOC_FLAG_MAY_REF) {
+ talloc_log("talloc_parent on may_reference pointer");
+ }
return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
}
_PUBLIC_ const char *talloc_parent_name(const void *ptr)
{
struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+
+ if (ptr && talloc_chunk_from_ptr(ptr)->flags & TALLOC_FLAG_MAY_REF) {
+ talloc_log("talloc_parent_name on may_reference pointer");
+ }
return tc? tc->name : NULL;
}
return discard_const_p(void, ptr);
}
+static void log_references(const char *fmt, const char *location,
+ struct talloc_chunk *tc)
+{
+ struct talloc_reference_handle *h;
+
+ talloc_log(fmt, location);
+
+ for (h=tc->refs; h; h=h->next) {
+ talloc_log("\treference at %s\n", h->location);
+ }
+}
+
/*
move a lump of memory from one talloc context to another return the
ptr on success, or NULL if it could not be transferred.
tc = talloc_chunk_from_ptr(ptr);
if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) {
- struct talloc_reference_handle *h;
-
- talloc_log("WARNING: talloc_steal with references at %s\n",
- location);
-
- for (h=tc->refs; h; h=h->next) {
- talloc_log("\treference at %s\n",
- h->location);
- }
+ log_references("WARNING: talloc_steal with references at %s\n",
+ location, tc);
+ } else if (tc->flags & TALLOC_FLAG_MAY_REF) {
+ log_references("WARNING: talloc_steal on may_reference ptr at %s\n",
+ location, tc);
}
#if 0
}
tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_MAY_REF) {
+ log_references("ERROR: talloc_free with may_reference at %s\n",
+ location, tc);
+ }
if (unlikely(tc->refs != NULL)) {
struct talloc_reference_handle *h;
return talloc_unlink(null_context, ptr);
}
- talloc_log("ERROR: talloc_free with references at %s\n",
- location);
-
- for (h=tc->refs; h; h=h->next) {
- talloc_log("\treference at %s\n",
- h->location);
- }
+ log_references("ERROR: talloc_free with references at %s\n",
+ location, tc);
return -1;
}
{
return _talloc_is_parent(context, ptr, TALLOC_MAX_DEPTH);
}
+
+_PUBLIC_ void *talloc_may_reference(const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ tc = talloc_chunk_from_ptr(ptr);
+ tc->flags |= TALLOC_FLAG_MAY_REF;
+ return discard_const_p(void, ptr);
+}
*/
#define TALLOC_VERSION_MAJOR 2
-#define TALLOC_VERSION_MINOR 0
+#define TALLOC_VERSION_MINOR 1
int talloc_version_major(void);
int talloc_version_minor(void);
void *_talloc_reference_loc(const void *context, const void *ptr, const char *location);
#endif
+/**
+ * @brief Mark a talloc pointer as being referencable.
+ *
+ * The talloc_may_reference() function marks ptr as having future
+ * references. As referenced (aka multi-parent) objects need to be
+ * handled differently, this helps debugging: you will get a warning
+ * from talloc_steal() and talloc_free() even if there is only a
+ * single (or NULL) parent.
+ *
+ * It will also warn on talloc_parent() or talloc_parent_name() on
+ * such pointers.
+ *
+ * @param[in] ptr The pointer you may create an additional parent for.
+ *
+ * Example:
+ * @code
+ * unsigned int *a;
+ * // We may reference this later; be careful!
+ * a = talloc(NULL, unsigned int);
+ * talloc_may_reference(a);
+ * @endcode
+ *
+ * @see talloc_reference()
+ */
+void *talloc_may_reference(const void *ptr);
+
/**
* @brief Remove a specific parent from a talloc chunk.
*