talloc: talloc_may_reference
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 25 Oct 2011 00:51:33 +0000 (11:21 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 25 Oct 2011 00:51:33 +0000 (11:21 +1030)
A new flag allows us to mark objects which will/may be referenced in
future.  You shouldn't try to treat these as a non-reference-counted
object, even if it's currently only got one reference.

This makes us clean up the hardcoded constants for flag bits, and also
bump the minor number since we've changed talloc flags.

Signed-off-byL Rusty Russell <rusty@rustcorp.com.au>

lib/talloc/talloc.c
lib/talloc/talloc.h
lib/talloc/wscript

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);
+}
index 96c7e2467c27b27dd23107f799603fa855434351..cedc8d50f02fe94bc3703ea6a1067a3910c26a01 100644 (file)
@@ -43,7 +43,7 @@ extern "C" {
  */
 
 #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);
@@ -933,6 +933,32 @@ void *talloc_reference(const void *ctx, const void *ptr);
 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.
  *
index dd83e16a423273af472bfb2afbcca6a6e8c2f662..44e7f2b224d855d3e442d83ad61e93ac6cf53cc1 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'talloc'
-VERSION = '2.0.7'
+VERSION = '2.1.0'
 
 
 blddir = 'bin'