talloc: talloc_may_reference
[rusty/samba.git] / lib / talloc / talloc.c
index 5ea07918cfd8218115cbdefb1cfb88cd200db0a9..41684dfee18c360c5aaf3b7040b1ad2b306992b2 100644 (file)
    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 
@@ -323,8 +334,8 @@ static void talloc_abort(const char *reason)
 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);
@@ -346,9 +357,9 @@ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
 {
        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;
                }
 
@@ -412,6 +423,10 @@ static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
 _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;
 }
 
@@ -421,6 +436,10 @@ _PUBLIC_ void *talloc_parent(const void *ptr)
 _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;
 }
 
@@ -936,6 +955,18 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
        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.
@@ -952,15 +983,11 @@ _PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const cha
        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
@@ -1346,6 +1373,11 @@ _PUBLIC_ int _talloc_free(void *ptr, const char *location)
        }
        
        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;
@@ -1357,13 +1389,8 @@ _PUBLIC_ int _talloc_free(void *ptr, const char *location)
                        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;
        }
        
@@ -2369,3 +2396,12 @@ _PUBLIC_ int talloc_is_parent(const void *context, const void *ptr)
 {
        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);
+}