From: Elijah Newren <newren@gmail.com>
To: "René Scharfe" <l.s.r@web.de>
Cc: Git List <git@vger.kernel.org>, Jameson Miller <jamill@microsoft.com>
Subject: Re: [PATCH] mem-pool: fix big allocations
Date: Sat, 23 Dec 2023 19:11:57 -0800 [thread overview]
Message-ID: <CABPp-BFiK9A6426d7CFeMZvaBcvmShaY9O0krtCe7jeV9wW7nQ@mail.gmail.com> (raw)
In-Reply-To: <fa89d269-1a23-4ed6-bebc-30c0b629f444@web.de>
On Thu, Dec 21, 2023 at 3:13 PM René Scharfe <l.s.r@web.de> wrote:
>
> Memory pool allocations that require a new block and would fill at
> least half of it are handled specially. Before 158dfeff3d (mem-pool:
> add life cycle management functions, 2018-07-02) they used to be
> allocated outside of the pool. This patch made mem_pool_alloc() create
> a bespoke block instead, to allow releasing it when the pool gets
> discarded.
>
> Unfortunately mem_pool_alloc() returns a pointer to the start of such a
> bespoke block, i.e. to the struct mp_block at its top. When the caller
> writes to it, the management information gets corrupted. This affects
> mem_pool_discard() and -- if there are no other blocks in the pool --
> also mem_pool_alloc().
>
> Return the payload pointer of bespoke blocks, just like for smaller
> allocations, to protect the management struct.
>
> Also update next_free to mark the block as full. This is only strictly
> necessary for the first allocated block, because subsequent ones are
> inserted after the current block and never considered for further
> allocations, but it's easier to just do it in all cases.
>
> Add a basic unit test to demonstate the issue by using mem_pool_calloc()
demonstrate (missing 'r')?
> with a tiny block size, which forces the creation of a bespoke block.
> Without the mem_pool_alloc() fix it reports zeroed pointers:
>
> ok 1 - mem_pool_calloc returns 100 zeroed bytes with big block
> # check "((pool->mp_block->next_free) != (((void*)0))) == 1" failed at t/unit-tests/t-mem-pool.c:22
> # left: 0
> # right: 1
> # check "((pool->mp_block->end) != (((void*)0))) == 1" failed at t/unit-tests/t-mem-pool.c:23
> # left: 0
> # right: 1
> not ok 2 - mem_pool_calloc returns 100 zeroed bytes with tiny block
> 1..2
>
> Signed-off-by: René Scharfe <l.s.r@web.de>
> ---
> Makefile | 1 +
> mem-pool.c | 6 +++---
> t/unit-tests/t-mem-pool.c | 34 ++++++++++++++++++++++++++++++++++
> 3 files changed, 38 insertions(+), 3 deletions(-)
> create mode 100644 t/unit-tests/t-mem-pool.c
>
> diff --git a/Makefile b/Makefile
> index 88ba7a3c51..15990ff312 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1340,6 +1340,7 @@ THIRD_PARTY_SOURCES += sha1collisiondetection/%
> THIRD_PARTY_SOURCES += sha1dc/%
>
> UNIT_TEST_PROGRAMS += t-basic
> +UNIT_TEST_PROGRAMS += t-mem-pool
> UNIT_TEST_PROGRAMS += t-strbuf
> UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
> UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
> diff --git a/mem-pool.c b/mem-pool.c
> index c34846d176..e8d976c3ee 100644
> --- a/mem-pool.c
> +++ b/mem-pool.c
> @@ -99,9 +99,9 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
>
> if (!p) {
> if (len >= (pool->block_alloc / 2))
> - return mem_pool_alloc_block(pool, len, pool->mp_block);
> -
> - p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
> + p = mem_pool_alloc_block(pool, len, pool->mp_block);
> + else
> + p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
> }
>
> r = p->next_free;
> diff --git a/t/unit-tests/t-mem-pool.c b/t/unit-tests/t-mem-pool.c
> new file mode 100644
> index 0000000000..2295779b0b
> --- /dev/null
> +++ b/t/unit-tests/t-mem-pool.c
> @@ -0,0 +1,34 @@
> +#include "test-lib.h"
> +#include "mem-pool.h"
> +
> +#define check_ptr(a, op, b) check_int(((a) op (b)), ==, 1)
> +
> +static void setup_static(void (*f)(struct mem_pool *), size_t block_alloc)
> +{
> + struct mem_pool pool = { .block_alloc = block_alloc };
> + f(&pool);
> + mem_pool_discard(&pool, 0);
> +}
> +
> +static void t_calloc_100(struct mem_pool *pool)
> +{
> + size_t size = 100;
> + char *buffer = mem_pool_calloc(pool, 1, size);
> + for (size_t i = 0; i < size; i++)
> + check_int(buffer[i], ==, 0);
> + if (!check_ptr(pool->mp_block, !=, NULL))
> + return;
> + check_ptr(pool->mp_block->next_free, <=, pool->mp_block->end);
> + check_ptr(pool->mp_block->next_free, !=, NULL);
> + check_ptr(pool->mp_block->end, !=, NULL);
> +}
> +
> +int cmd_main(int argc, const char **argv)
> +{
> + TEST(setup_static(t_calloc_100, 1024 * 1024),
> + "mem_pool_calloc returns 100 zeroed bytes with big block");
> + TEST(setup_static(t_calloc_100, 1),
> + "mem_pool_calloc returns 100 zeroed bytes with tiny block");
> +
> + return test_done();
> +}
> --
> 2.43.0
Nice catch; looks good to me. Out of curiosity, how'd you find the issue?
next prev parent reply other threads:[~2023-12-24 3:12 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-21 23:13 [PATCH] mem-pool: fix big allocations René Scharfe
2023-12-24 3:11 ` Elijah Newren [this message]
2023-12-24 9:30 ` René Scharfe
2023-12-28 15:10 ` Phillip Wood
2023-12-28 16:05 ` René Scharfe
2023-12-28 16:48 ` phillip.wood123
2023-12-28 18:56 ` René Scharfe
2023-12-28 19:34 ` phillip.wood123
2023-12-29 6:53 ` René Scharfe
2023-12-28 19:19 ` [PATCH v2] " René Scharfe
2023-12-28 19:36 ` phillip.wood123
2024-01-02 22:29 ` Taylor Blau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CABPp-BFiK9A6426d7CFeMZvaBcvmShaY9O0krtCe7jeV9wW7nQ@mail.gmail.com \
--to=newren@gmail.com \
--cc=git@vger.kernel.org \
--cc=jamill@microsoft.com \
--cc=l.s.r@web.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).