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)) {
(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;
}
* 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);
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;
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;
+}