[PATCH] Fix talloc memlimits to work correctly with pools.

Jeremy Allison jra at samba.org
Tue Aug 27 14:44:47 MDT 2013


The current talloc_memlimit code is broken
w.r.t talloc_pools. It accounts for the
original pool allocation, and then also
counts all the sub-allocations from the
pool against the memlimit, which it
shouldn't (only the original pool
allocation actually does a malloc).

This patchset fixes that, and adds
a simple test case to show memory
limits working with pools.

After this local.talloc test is
valgrind clean.

Please review and push if you're
happy with it.

Once this is in I'll rebase Volker's
nested talloc pool patch on top of
it and submit that for review.

Cheers,

	Jeremy.
-------------- next part --------------
>From b3f229b0785fde584f74b7aa516eb50f7d3b4f41 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:36:23 -0700
Subject: [PATCH 01/13] Start to fix talloc memlimits with talloc pools.

Add the functions:

talloc_memlimit_grow(), talloc_memlimit_shrink(),
talloc_memlimit_update_on_free().

as replacements for talloc_memlimit_update().
The interface to talloc_memlimit_update() is very
hard to understand and use. The above functions
are (to me) much clearer.

The goal of these changes is to only update
the memlimits on malloc/free/realloc, not
on every pool allocation. That way we only
count pool creation as allocation from any
imposed limits, not allocation from an already
created pool.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 76f0aee..3f51a4c 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -238,6 +238,11 @@ struct talloc_memlimit {
 static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size);
 static bool talloc_memlimit_update(struct talloc_memlimit *limit,
 				   size_t old_size, size_t new_size);
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+				size_t size);
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+				size_t size);
+static void talloc_memlimit_update_on_free(struct talloc_chunk *tc);
 
 typedef int (*talloc_destructor_t)(void *);
 
@@ -2564,6 +2569,74 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
 	return true;
 }
 
+/*
+  Update memory limits when freeing a talloc_chunk.
+*/
+static void talloc_memlimit_update_on_free(struct talloc_chunk *tc)
+{
+	if (!tc->limit) {
+		return;
+	}
+
+	/*
+	 * Pool entries don't count. Only the pools
+	 * themselves are counted as part of the memory
+	 * limits.
+	 */
+	if (tc->flags & TALLOC_FLAG_POOLMEM) {
+		return;
+	}
+
+	/*
+	 * If we are part of a memory limited context hierarchy
+	 * we need to subtract the memory used from the counters
+	 */
+
+	talloc_memlimit_shrink(tc->limit, tc->size+TC_HDR_SIZE);
+
+	if (tc->limit->parent == tc) {
+		free(tc->limit);
+	}
+
+	tc->limit = NULL;
+}
+
+/*
+  Increase memory limit accounting after a malloc/realloc.
+*/
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+				size_t size)
+{
+	struct talloc_memlimit *l;
+
+	for (l = limit; l != NULL; l = l->upper) {
+		ssize_t new_cur_size = (ssize_t)l->cur_size + (ssize_t)size;
+		if (new_cur_size < 0) {
+			talloc_abort("logic error in talloc_memlimit_grow\n");
+			return;
+		}
+		l->cur_size = (size_t)new_cur_size;
+	}
+}
+
+/*
+  Decrease memory limit accounting after a free/realloc.
+*/
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+				size_t size)
+{
+	struct talloc_memlimit *l;
+
+	for (l = limit; l != NULL; l = l->upper) {
+		ssize_t new_cur_size = (ssize_t)l->cur_size - (ssize_t)size;
+		if (new_cur_size < 0) {
+			talloc_abort("logic error in talloc_memlimit_shrink\n");
+			return;
+		}
+		l->cur_size = (size_t)new_cur_size;
+	}
+}
+
 static bool talloc_memlimit_update(struct talloc_memlimit *limit,
 				   size_t old_size, size_t new_size)
 {
-- 
1.8.3.1


>From e2756251a6c183752374c20dd1d9a10eb178cf0d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:43:50 -0700
Subject: [PATCH 02/13] Remove magic TC_HDR_SIZE handling inside
 talloc_memlimit_check().

Make the callers handle this correctly (in a later change).

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 3f51a4c..99b678f 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -2561,7 +2561,7 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
 	for (l = limit; l != NULL; l = l->upper) {
 		if (l->max_size != 0 &&
 		    ((l->max_size <= l->cur_size) ||
-		     (l->max_size - l->cur_size < TC_HDR_SIZE+size))) {
+		     (l->max_size - l->cur_size < size))) {
 			return false;
 		}
 	}
-- 
1.8.3.1


>From f698055d3f93f38b7615f926f93622dc782c5ea9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:46:09 -0700
Subject: [PATCH 03/13] Change _talloc_total_mem_internal() to ignore memory
 allocated from a pool when calculating limit size.

We must only count normal tallocs, or a talloc pool itself.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 99b678f..9dfc142 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -1817,7 +1817,14 @@ static size_t _talloc_total_mem_internal(const void *ptr,
 		break;
 	case TOTAL_MEM_LIMIT:
 		if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) {
-			total = tc->size + TC_HDR_SIZE;
+			/*
+			 * Don't count memory allocated from a pool
+			 * when calculating limits. Only count the
+			 * pool itself.
+			 */
+			if (!(tc->flags & TALLOC_FLAG_POOLMEM)) {
+				total = tc->size + TC_HDR_SIZE;
+			}
 		}
 		break;
 	}
-- 
1.8.3.1


>From 51eddaccdabb2c7ab1caeb820462fa9e2fdd2002 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:49:00 -0700
Subject: [PATCH 04/13] Change __talloc() to only call
 talloc_memlimit_check()/talloc_memlimit_grow() on actual malloc allocation.

Don't check the memlimit if the allocation was successful from a pool. We already
checked the memory limit when we created the pool.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 9dfc142..2f1444a 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -586,27 +586,24 @@ static inline void *__talloc(const void *context, size_t size)
 			limit = ptc->limit;
 		}
 
-		if (!talloc_memlimit_check(limit, (TC_HDR_SIZE+size))) {
-			errno = ENOMEM;
-			return NULL;
-		}
-
 		tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size);
 	}
 
 	if (tc == NULL) {
+		/*
+		 * Only do the memlimit check/update on actual allocation.
+		 */
+		if (!talloc_memlimit_check(limit, TC_HDR_SIZE + size)) {
+			errno = ENOMEM;
+			return NULL;
+		}
+
 		tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
 		if (unlikely(tc == NULL)) return NULL;
 		tc->flags = TALLOC_MAGIC;
 		tc->pool  = NULL;
-	}
 
-	if (limit != NULL) {
-		struct talloc_memlimit *l;
-
-		for (l = limit; l != NULL; l = l->upper) {
-			l->cur_size += TC_HDR_SIZE+size;
-		}
+		talloc_memlimit_grow(limit, TC_HDR_SIZE + size);
 	}
 
 	tc->limit = limit;
-- 
1.8.3.1


>From 4790d42c5357f5a5eb51bde160dc2cae6ebfe3dd Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:51:20 -0700
Subject: [PATCH 05/13] Update memory limits when we call free() on a pool.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 2f1444a..892aa80 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -807,6 +807,8 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 		 */
 		pool->hdr.c.name = location;
 
+		talloc_memlimit_update_on_free(&pool->hdr.c);
+
 		TC_INVALIDATE_FULL_CHUNK(&pool->hdr.c);
 		free(pool);
 		return;
-- 
1.8.3.1


>From ecd36d5d26e069726be054683043647c3f2d2792 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:54:38 -0700
Subject: [PATCH 06/13] Inside _talloc_free_internal(), always call
 talloc_memlimit_update_on_free() before we free the real memory.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 27 ++++-----------------------
 1 file changed, 4 insertions(+), 23 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 892aa80..e051d70 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -909,29 +909,6 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
 
 	tc->flags |= TALLOC_FLAG_FREE;
 
-	/*
-	 * If we are part of a memory limited context hierarchy
-	 * we need to subtract the memory used from the counters
-	 */
-	if (tc->limit) {
-		struct talloc_memlimit *l;
-
-		for (l = tc->limit; l != NULL; l = l->upper) {
-			if (l->cur_size >= tc->size+TC_HDR_SIZE) {
-				l->cur_size -= tc->size+TC_HDR_SIZE;
-			} else {
-				talloc_abort("cur_size memlimit counter not correct!");
-				return 0;
-			}
-		}
-
-		if (tc->limit->parent == tc) {
-			free(tc->limit);
-		}
-
-		tc->limit = NULL;
-	}
-
 	/* we mark the freed memory with where we called the free
 	 * from. This means on a double free error we can report where
 	 * the first free came from
@@ -952,6 +929,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
 			return 0;
 		}
 
+		talloc_memlimit_update_on_free(tc);
+
 		TC_INVALIDATE_FULL_CHUNK(tc);
 		free(tc);
 		return 0;
@@ -962,6 +941,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
 		return 0;
 	}
 
+	talloc_memlimit_update_on_free(tc);
+
 	TC_INVALIDATE_FULL_CHUNK(tc);
 	free(tc);
 	return 0;
-- 
1.8.3.1


>From 55be6414d0b17b86b4efb01f6869965bcffea47a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:57:43 -0700
Subject: [PATCH 07/13] In _talloc_steal_internal(), correctly decrement the
 memory limit in the source, and increment in the destination.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index e051d70..b3543e5 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -976,11 +976,8 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
 
 		ctx_size = _talloc_total_limit_size(ptr, NULL, NULL);
 
-		if (!talloc_memlimit_update(tc->limit->upper, ctx_size, 0)) {
-			talloc_abort("cur_size memlimit counter not correct!");
-			errno = EINVAL;
-			return NULL;
-		}
+		/* Decrement the memory limit from the source .. */
+		talloc_memlimit_shrink(tc->limit->upper, ctx_size);
 
 		if (tc->limit->parent == tc) {
 			tc->limit->upper = NULL;
@@ -1025,17 +1022,11 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
 	if (new_tc->child) new_tc->child->parent = NULL;
 	_TLIST_ADD(new_tc->child, tc);
 
-	if (tc->limit || new_tc->limit) {
+	if (new_tc->limit) {
 		ctx_size = _talloc_total_limit_size(ptr, tc->limit,
 						    new_tc->limit);
-	}
-
-	if (new_tc->limit) {
-		struct talloc_memlimit *l;
-
-		for (l = new_tc->limit; l != NULL; l = l->upper) {
-			l->cur_size += ctx_size;
-		}
+		/* .. and increment it in the destination. */
+		talloc_memlimit_grow(new_tc->limit, ctx_size);
 	}
 
 	return discard_const_p(void, ptr);
-- 
1.8.3.1


>From adfef346c6f9ecf5c076059df6f23ea331382bb0 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 12:59:04 -0700
Subject: [PATCH 08/13] Fix a conditional check. (size - tc->size > 0) is
 always true if size and tc->size are unsigned.

Replace with (size > tc->size).

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index b3543e5..8d0c8b3 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -1505,7 +1505,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		return NULL;
 	}
 
-	if (tc->limit && (size - tc->size > 0)) {
+	if (tc->limit && (size > tc->size)) {
 		if (!talloc_memlimit_check(tc->limit, (size - tc->size))) {
 			errno = ENOMEM;
 			return NULL;
-- 
1.8.3.1


>From a3b4adc37cb428c954f49e082277abb0c8169ab5 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 13:03:27 -0700
Subject: [PATCH 09/13] Don't call talloc_memlimit_update() inside
 _talloc_realloc() when we're just manipulating pool members.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 8d0c8b3..7bf54f2 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -1627,14 +1627,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		if (new_chunk_size == old_chunk_size) {
 			TC_UNDEFINE_GROW_CHUNK(tc, size);
 			tc->flags &= ~TALLOC_FLAG_FREE;
-			if (!talloc_memlimit_update(tc->limit,
-							tc->size, size)) {
-				talloc_abort("cur_size memlimit counter not"
-					     " correct!");
-				errno = EINVAL;
-				return NULL;
-			}
-
 			tc->size = size;
 			return ptr;
 		}
@@ -1650,13 +1642,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			if (space_left >= space_needed) {
 				TC_UNDEFINE_GROW_CHUNK(tc, size);
 				tc->flags &= ~TALLOC_FLAG_FREE;
-				if (!talloc_memlimit_update(tc->limit,
-							tc->size, size)) {
-					talloc_abort("cur_size memlimit "
-						     "counter not correct!");
-					errno = EINVAL;
-					return NULL;
-				}
 				tc->size = size;
 				pool_tc->hdr.c.pool = tc_next_chunk(tc);
 				return ptr;
-- 
1.8.3.1


>From d0219ce7b135bce72cd69e886b4139d11d4a0bad Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 13:07:04 -0700
Subject: [PATCH 10/13] Inside _talloc_realloc(), keep track of size changes
 over malloc/realloc/free.

Replace the last use of talloc_memlimit_update() with talloc_memlimit_grow()/
talloc_memlimit_shrink().

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 7bf54f2..41f7498 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -1477,6 +1477,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 	void *new_ptr;
 	bool malloced = false;
 	union talloc_pool_chunk *pool_tc = NULL;
+	ssize_t size_change = 0;
 
 	/* size zero is equivalent to free() */
 	if (unlikely(size == 0)) {
@@ -1564,6 +1565,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		if (new_ptr == NULL) {
 			new_ptr = malloc(TC_HDR_SIZE+size);
 			malloced = true;
+			size_change = TC_HDR_SIZE+(ssize_t)size;
 		}
 
 		if (new_ptr) {
@@ -1571,6 +1573,8 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			TC_INVALIDATE_FULL_CHUNK(tc);
 		}
 	} else {
+		/* malloc new then free old. size_change is the difference. */
+		size_change = (ssize_t)size - (ssize_t)tc->size;
 		new_ptr = malloc(size + TC_HDR_SIZE);
 		if (new_ptr) {
 			memcpy(new_ptr, tc, MIN(tc->size, size) + TC_HDR_SIZE);
@@ -1653,6 +1657,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		if (new_ptr == NULL) {
 			new_ptr = malloc(TC_HDR_SIZE+size);
 			malloced = true;
+			size_change = TC_HDR_SIZE+(ssize_t)size;
 		}
 
 		if (new_ptr) {
@@ -1662,6 +1667,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		}
 	}
 	else {
+		size_change = (ssize_t)size - (ssize_t)tc->size;
 		new_ptr = realloc(tc, size + TC_HDR_SIZE);
 	}
 got_new_ptr:
@@ -1690,11 +1696,12 @@ got_new_ptr:
 		tc->next->prev = tc;
 	}
 
-	if (!talloc_memlimit_update(tc->limit, tc->size, size)) {
-		talloc_abort("cur_size memlimit counter not correct!");
-		errno = EINVAL;
-		return NULL;
+	if (size_change > 0) {
+		talloc_memlimit_grow(tc->limit, (size_t)size_change);
+	} else if (size_change < 0) {
+		talloc_memlimit_shrink(tc->limit, (size_t)-size_change);
 	}
+
 	tc->size = size;
 	_talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
 
-- 
1.8.3.1


>From b047fbea78f9efa30c24fa78d199a7231c9075a5 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 13:08:33 -0700
Subject: [PATCH 11/13] Remove talloc_memlimit_update(). No longer used.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 41f7498..ebcde2d 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -236,8 +236,6 @@ struct talloc_memlimit {
 };
 
 static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size);
-static bool talloc_memlimit_update(struct talloc_memlimit *limit,
-				   size_t old_size, size_t new_size);
 static void talloc_memlimit_grow(struct talloc_memlimit *limit,
 				size_t size);
 static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
@@ -2607,28 +2605,6 @@ static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
 	}
 }
 
-static bool talloc_memlimit_update(struct talloc_memlimit *limit,
-				   size_t old_size, size_t new_size)
-{
-	struct talloc_memlimit *l;
-	ssize_t d;
-
-	if (old_size == 0) {
-		d = new_size + TC_HDR_SIZE;
-	} else {
-		d = new_size - old_size;
-	}
-	for (l = limit; l != NULL; l = l->upper) {
-		ssize_t new_cur_size = l->cur_size + d;
-		if (new_cur_size < 0) {
-			return false;
-		}
-		l->cur_size = new_cur_size;
-	}
-
-	return true;
-}
-
 _PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size)
 {
 	struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx);
-- 
1.8.3.1


>From a56d3ff4332f361deb7b8f544d88f5a578efa58a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 13:09:03 -0700
Subject: [PATCH 12/13] Add simple limited pool tests to test_memlimit().

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/testsuite.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index d456cbb..426c31a 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -1359,6 +1359,8 @@ static bool test_memlimit(void)
 {
 	void *root;
 	char *l1, *l2, *l3, *l4, *l5, *t;
+	char *pool;
+	int i;
 
 	printf("test: memlimit\n# MEMORY LIMITS\n");
 
@@ -1520,6 +1522,31 @@ static bool test_memlimit(void)
 	talloc_report_full(root, stdout);
 	talloc_free(root);
 
+	/* Test memlimits with pools. */
+	pool = talloc_pool(NULL, 10*1024);
+	torture_assert("memlimit", pool != NULL,
+		"failed: alloc should not fail due to memory limit\n");
+	talloc_set_memlimit(pool, 10*1024);
+	for (i = 0; i < 9; i++) {
+		l1 = talloc_size(pool, 1024);
+		torture_assert("memlimit", l1 != NULL,
+			"failed: alloc should not fail due to memory limit\n");
+	}
+	/* The next alloc should fail. */
+	l2 = talloc_size(pool, 1024);
+	torture_assert("memlimit", l2 == NULL,
+			"failed: alloc should fail due to memory limit\n");
+
+	/* Moving one of the children shouldn't change the limit,
+	   as it's still inside the pool. */
+	root = talloc_new(NULL);
+	talloc_steal(root, l1);
+	l2 = talloc_size(pool, 1024);
+	torture_assert("memlimit", l2 == NULL,
+			"failed: alloc should fail due to memory limit\n");
+
+	talloc_free(pool);
+	talloc_free(root);
 	printf("success: memlimit\n");
 
 	return true;
-- 
1.8.3.1


>From e3698b94598ddbf97f4769c158c6c92e93539ecd Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 27 Aug 2013 13:20:43 -0700
Subject: [PATCH 13/13] Fix valgrind errors with memmove and talloc pools.

bin/smbtorture //127.0.0.1 local.talloc now runs with no valgrind errors.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index ebcde2d..686e7b8 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -1605,6 +1605,27 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 				size_t old_used = TC_HDR_SIZE + tc->size;
 				size_t new_used = TC_HDR_SIZE + size;
 				new_ptr = start;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+				{
+					/*
+					 * The area from
+					 * start -> tc may have
+					 * been freed and thus been marked as
+					 * VALGRIND_MEM_NOACCESS. Set it to
+					 * VALGRIND_MEM_UNDEFINED so we can
+					 * copy into it without valgrind errors.
+					 * We can't just mark
+					 * new_ptr -> new_ptr + old_used
+					 * as this may overlap on top of tc,
+					 * (which is why we use memmove, not
+					 * memcpy below) hence the MIN.
+					 */
+					size_t undef_len = MIN((((char *)tc) - ((char *)new_ptr)),old_used);
+					VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, undef_len);
+				}
+#endif
+
 				memmove(new_ptr, tc, old_used);
 
 				tc = (struct talloc_chunk *)new_ptr;
-- 
1.8.3.1



More information about the samba-technical mailing list