svn commit: samba r8032 - in branches/SAMBA_4_0/source/lib/talloc: .

tridge at samba.org tridge at samba.org
Fri Jul 1 01:25:56 GMT 2005


Author: tridge
Date: 2005-07-01 01:25:55 +0000 (Fri, 01 Jul 2005)
New Revision: 8032

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=8032

Log:
added loop detection into talloc. Robert Collins found a way to make a
memory loop with talloc_unlink(), so now we detect it and handle it

Modified:
   branches/SAMBA_4_0/source/lib/talloc/talloc.c
   branches/SAMBA_4_0/source/lib/talloc/testsuite.c


Changeset:
Modified: branches/SAMBA_4_0/source/lib/talloc/talloc.c
===================================================================
--- branches/SAMBA_4_0/source/lib/talloc/talloc.c	2005-06-30 23:44:18 UTC (rev 8031)
+++ branches/SAMBA_4_0/source/lib/talloc/talloc.c	2005-07-01 01:25:55 UTC (rev 8032)
@@ -59,8 +59,9 @@
 
 
 #define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0xe814ec4f
-#define TALLOC_MAGIC_FREE 0x7faebef3
+#define TALLOC_MAGIC 0xe814ec70
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
 #define TALLOC_MAGIC_REFERENCE ((const char *)1)
 
 /* by default we abort when given a bad pointer (such as when talloc_free() is called 
@@ -100,7 +101,7 @@
 	talloc_destructor_t destructor;
 	const char *name;
 	union {
-		unsigned magic;
+		unsigned flags;
 		double align_dummy;
 	} u;
 };
@@ -109,14 +110,12 @@
 static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
 {
 	struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1;
-	if (tc->u.magic != TALLOC_MAGIC) { 
-		if (tc->u.magic == TALLOC_MAGIC_FREE) {
-			TALLOC_ABORT("Bad talloc magic value - double free"); 
-		} else {
-			TALLOC_ABORT("Bad talloc magic value - unknown value"); 
-		}
+	if ((tc->u.flags & ~0xF) != TALLOC_MAGIC) { 
+		TALLOC_ABORT("Bad talloc magic value - unknown value"); 
 	}
-
+	if (tc->u.flags & TALLOC_FLAG_FREE) {
+		TALLOC_ABORT("Bad talloc magic value - double free"); 
+	}
 	return tc;
 }
 
@@ -183,7 +182,7 @@
 	if (tc == NULL) return NULL;
 
 	tc->size = size;
-	tc->u.magic = TALLOC_MAGIC;
+	tc->u.flags = TALLOC_MAGIC;
 	tc->destructor = NULL;
 	tc->child = NULL;
 	tc->name = NULL;
@@ -537,6 +536,11 @@
 		return -1;
 	}
 
+	if (tc->u.flags & TALLOC_FLAG_LOOP) {
+		/* we have a free loop - stop looping */
+		return 0;
+	}
+
 	if (tc->destructor) {
 		talloc_destructor_t d = tc->destructor;
 		if (d == (talloc_destructor_t)-1) {
@@ -550,6 +554,8 @@
 		tc->destructor = NULL;
 	}
 
+	tc->u.flags |= TALLOC_FLAG_LOOP;
+
 	talloc_free_children(ptr);
 
 	if (tc->parent) {
@@ -562,7 +568,7 @@
 		if (tc->next) tc->next->prev = tc->prev;
 	}
 
-	tc->u.magic = TALLOC_MAGIC_FREE;
+	tc->u.flags |= TALLOC_FLAG_FREE;
 
 	free(tc);
 	return 0;
@@ -602,7 +608,7 @@
 	}
 
 	/* by resetting magic we catch users of the old memory */
-	tc->u.magic = TALLOC_MAGIC_FREE;
+	tc->u.flags |= TALLOC_FLAG_FREE;
 
 #if ALWAYS_REALLOC
 	new_ptr = malloc(size + sizeof(*tc));
@@ -614,12 +620,12 @@
 	new_ptr = realloc(tc, size + sizeof(*tc));
 #endif
 	if (!new_ptr) {	
-		tc->u.magic = TALLOC_MAGIC; 
+		tc->u.flags &= ~TALLOC_FLAG_FREE; 
 		return NULL; 
 	}
 
 	tc = new_ptr;
-	tc->u.magic = TALLOC_MAGIC;
+	tc->u.flags &= ~TALLOC_FLAG_FREE; 
 	if (tc->parent) {
 		tc->parent->child = new_ptr;
 	}
@@ -714,10 +720,19 @@
 
 	tc = talloc_chunk_from_ptr(ptr);
 
+	if (tc->u.flags & TALLOC_FLAG_LOOP) {
+		return 0;
+	}
+
+	tc->u.flags |= TALLOC_FLAG_LOOP;
+
 	total = tc->size;
 	for (c=tc->child;c;c=c->next) {
 		total += talloc_total_size(c+1);
 	}
+
+	tc->u.flags &= ~TALLOC_FLAG_LOOP;
+
 	return total;
 }
 
@@ -729,10 +744,19 @@
 	off_t total = 0;
 	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
 
+	if (tc->u.flags & TALLOC_FLAG_LOOP) {
+		return 0;
+	}
+
+	tc->u.flags |= TALLOC_FLAG_LOOP;
+
 	total++;
 	for (c=tc->child;c;c=c->next) {
 		total += talloc_total_blocks(c+1);
 	}
+
+	tc->u.flags &= ~TALLOC_FLAG_LOOP;
+
 	return total;
 }
 
@@ -758,6 +782,12 @@
 {
 	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
 
+	if (tc->u.flags & TALLOC_FLAG_LOOP) {
+		return;
+	}
+
+	tc->u.flags |= TALLOC_FLAG_LOOP;
+
 	for (c=tc->child;c;c=c->next) {
 		if (c->name == TALLOC_MAGIC_REFERENCE) {
 			struct talloc_reference_handle *handle = (void *)(c+1);
@@ -774,7 +804,7 @@
 			talloc_report_depth(c+1, f, depth+1);
 		}
 	}
-
+	tc->u.flags &= ~TALLOC_FLAG_LOOP;
 }
 
 /*

Modified: branches/SAMBA_4_0/source/lib/talloc/testsuite.c
===================================================================
--- branches/SAMBA_4_0/source/lib/talloc/testsuite.c	2005-06-30 23:44:18 UTC (rev 8031)
+++ branches/SAMBA_4_0/source/lib/talloc/testsuite.c	2005-07-01 01:25:55 UTC (rev 8032)
@@ -818,6 +818,26 @@
 }
 
 
+BOOL test_lifeless(void)
+{
+	char *top = talloc_new(NULL);
+	char *parent, *child; 
+	char *child_owner = talloc_new(NULL);
+
+	printf("TESTING TALLOC_UNLINK LOOP\n");
+
+	parent = talloc_strdup(top, "parent");
+	child = talloc_strdup(parent, "child");  
+	talloc_reference(child, parent);
+	talloc_reference(child_owner, child); 
+	talloc_unlink(top, parent);
+	talloc_free(child);
+	talloc_report_full(top, stdout);
+	talloc_free(top);
+	return True;
+}
+
+
 BOOL torture_local_talloc(void) 
 {
 	BOOL ret = True;
@@ -834,6 +854,7 @@
 	ret &= test_unref_reparent();
 	ret &= test_realloc_fn();
 	ret &= test_type();
+	ret &= test_lifeless();
 	if (ret) {
 		ret &= test_speed();
 	}



More information about the samba-cvs mailing list