From 92a4ef104c93942387914490f021f6634deda755 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 20 Oct 2020 10:52:55 -0700 Subject: [PATCH] Fix memlimit on pool realloc. Signed-off-by: Jeremy Allison Signed-off-by: Arran Cudbard-Bell --- lib/talloc/talloc.c | 69 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index e476f3e2d05..accc859f77e 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -1833,13 +1833,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons return NULL; } - if (tc->limit && (size > tc->size)) { - if (!talloc_memlimit_check(tc->limit, (size - tc->size))) { - errno = ENOMEM; - return NULL; - } - } - /* handle realloc inside a talloc_pool */ if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { pool_hdr = tc->pool; @@ -1904,6 +1897,25 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons pool_hdr->object_count--; if (new_ptr == NULL) { + /* + * Couldn't allocate from pool (pool size + * counts as already allocated for memlimit + * purposes). We must check memory limit + * before any real malloc. + */ + if (tc->limit) { + /* + * Note we're doing an extra malloc, + * on top of the pool size, so account + * for size only, not the difference + * between old and new size. + */ + if (!talloc_memlimit_check(tc->limit, size)) { + _talloc_chunk_set_not_free(tc); + errno = ENOMEM; + return NULL; + } + } new_ptr = malloc(TC_HDR_SIZE+size); malloced = true; new_size = size; @@ -1917,6 +1929,18 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons /* We're doing malloc then free here, so record the difference. */ old_size = tc->size; new_size = size; + /* + * We must check memory limit + * before any real malloc. + */ + if (tc->limit && (size > old_size)) { + if (!talloc_memlimit_check(tc->limit, + (size - old_size))) { + _talloc_chunk_set_not_free(tc); + errno = ENOMEM; + return NULL; + } + } new_ptr = malloc(size + TC_HDR_SIZE); if (new_ptr) { memcpy(new_ptr, tc, MIN(tc->size, size) + TC_HDR_SIZE); @@ -2020,6 +2044,25 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons new_ptr = tc_alloc_pool(tc, size + TC_HDR_SIZE, 0); if (new_ptr == NULL) { + /* + * Couldn't allocate from pool (pool size + * counts as already allocated for memlimit + * purposes). We must check memory limit + * before any real malloc. + */ + if (tc->limit) { + /* + * Note we're doing an extra malloc, + * on top of the pool size, so account + * for size only, not the difference + * between old and new size. + */ + if (!talloc_memlimit_check(tc->limit, size)) { + _talloc_chunk_set_not_free(tc); + errno = ENOMEM; + return NULL; + } + } new_ptr = malloc(TC_HDR_SIZE+size); malloced = true; new_size = size; @@ -2035,6 +2078,18 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons /* We're doing realloc here, so record the difference. */ old_size = tc->size; new_size = size; + /* + * We must check memory limit + * before any real realloc. + */ + if (tc->limit && (size > old_size)) { + if (!talloc_memlimit_check(tc->limit, + (size - old_size))) { + _talloc_chunk_set_not_free(tc); + errno = ENOMEM; + return NULL; + } + } new_ptr = realloc(tc, size + TC_HDR_SIZE); } got_new_ptr: -- 2.25.1