util: Move become_daemon.c to samba-util-core
[samba.git] / lib / util / talloc_stack.c
index 596efbf6cd36ab1e72748e12cf1f1e5e1d954c23..9c72c801197b2b8f4bcd7fd7627957a4702a700d 100644 (file)
@@ -68,22 +68,20 @@ static void talloc_stackframe_init(void * unused)
 static struct talloc_stackframe *talloc_stackframe_create(void)
 {
 #if defined(PARANOID_MALLOC_CHECKER)
-#ifdef malloc
-#undef malloc
+#ifdef calloc
+#undef calloc
 #endif
 #endif
-       struct talloc_stackframe *ts =
-               (struct talloc_stackframe *)malloc(sizeof(struct talloc_stackframe));
+       struct talloc_stackframe *ts = (struct talloc_stackframe *)calloc(
+               1, sizeof(struct talloc_stackframe));
 #if defined(PARANOID_MALLOC_CHECKER)
-#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#define calloc(n, s) __ERROR_DONT_USE_MALLOC_DIRECTLY
 #endif
 
        if (!ts) {
                smb_panic("talloc_stackframe_init malloc failed");
        }
 
-       ZERO_STRUCTP(ts);
-
        SMB_THREAD_ONCE(&ts_initialized, talloc_stackframe_init, NULL);
 
        if (SMB_THREAD_SET_TLS(global_ts, ts)) {
@@ -98,13 +96,25 @@ static int talloc_pop(TALLOC_CTX *frame)
                (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
        int i;
 
+       /* Catch lazy frame-freeing. */
+       if (ts->talloc_stack[ts->talloc_stacksize-1] != frame) {
+               DEBUG(0, ("Freed frame %s, expected %s.\n",
+                         talloc_get_name(frame),
+                         talloc_get_name(ts->talloc_stack
+                                         [ts->talloc_stacksize-1])));
+#ifdef DEVELOPER
+               smb_panic("Frame not freed in order.");
+#endif
+       }
+
        for (i=ts->talloc_stacksize-1; i>0; i--) {
                if (frame == ts->talloc_stack[i]) {
                        break;
                }
-               talloc_free(ts->talloc_stack[i]);
+               TALLOC_FREE(ts->talloc_stack[i]);
        }
 
+       ts->talloc_stack[i] = NULL;
        ts->talloc_stacksize = i;
        return 0;
 }
@@ -116,9 +126,10 @@ static int talloc_pop(TALLOC_CTX *frame)
  * not explicitly freed.
  */
 
-static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
+static TALLOC_CTX *talloc_stackframe_internal(const char *location,
+                                             size_t poolsize)
 {
-       TALLOC_CTX **tmp, *top, *parent;
+       TALLOC_CTX **tmp, *top;
        struct talloc_stackframe *ts =
                (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
 
@@ -136,22 +147,23 @@ static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
                ts->talloc_stack_arraysize = ts->talloc_stacksize + 1;
         }
 
-       if (ts->talloc_stacksize == 0) {
-               parent = ts->talloc_stack;
-       } else {
-               parent = ts->talloc_stack[ts->talloc_stacksize-1];
-       }
-
        if (poolsize) {
-               top = talloc_pool(parent, poolsize);
+               top = talloc_pool(ts->talloc_stack, poolsize);
        } else {
+               TALLOC_CTX *parent;
+               /* We chain parentage, so if one is a pool we draw from it. */
+               if (ts->talloc_stacksize == 0) {
+                       parent = ts->talloc_stack;
+               } else {
+                       parent = ts->talloc_stack[ts->talloc_stacksize-1];
+               }
                top = talloc_new(parent);
        }
 
        if (top == NULL) {
                goto fail;
        }
-
+       talloc_set_name_const(top, location);
        talloc_set_destructor(top, talloc_pop);
 
        ts->talloc_stack[ts->talloc_stacksize++] = top;
@@ -162,30 +174,51 @@ static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
        return NULL;
 }
 
-TALLOC_CTX *talloc_stackframe(void)
+TALLOC_CTX *_talloc_stackframe(const char *location)
 {
-       return talloc_stackframe_internal(0);
+       return talloc_stackframe_internal(location, 0);
 }
 
-TALLOC_CTX *talloc_stackframe_pool(size_t poolsize)
+TALLOC_CTX *_talloc_stackframe_pool(const char *location, size_t poolsize)
 {
-       return talloc_stackframe_internal(poolsize);
+       return talloc_stackframe_internal(location, poolsize);
 }
 
 /*
  * Get us the current top of the talloc stack.
  */
 
-TALLOC_CTX *talloc_tos(void)
+TALLOC_CTX *_talloc_tos(const char *location)
 {
        struct talloc_stackframe *ts =
                (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
 
-       if (ts == NULL) {
-               talloc_stackframe();
+       if (ts == NULL || ts->talloc_stacksize == 0) {
+               _talloc_stackframe(location);
                ts = (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
-               DEBUG(0, ("no talloc stackframe around, leaking memory\n"));
+               DEBUG(0, ("no talloc stackframe at %s, leaking memory\n",
+                         location));
+#ifdef DEVELOPER
+               smb_panic("No talloc stackframe");
+#endif
        }
 
        return ts->talloc_stack[ts->talloc_stacksize-1];
 }
+
+/*
+ * return true if a talloc stackframe exists
+ * this can be used to prevent memory leaks for code that can
+ * optionally use a talloc stackframe (eg. nt_errstr())
+ */
+
+bool talloc_stackframe_exists(void)
+{
+       struct talloc_stackframe *ts =
+               (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+
+       if (ts == NULL || ts->talloc_stacksize == 0) {
+               return false;
+       }
+       return true;
+}