Skip to content

Commit 6cbae64

Browse files
rscharfegitster
authored andcommitted
mem-pool: fix big allocations
Memory pool allocations that require a new block and would fill at least half of it are handled specially. Before 158dfef (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 demonstrate the issue by using mem_pool_calloc() with a tiny block size, which forces the creation of a bespoke block. Helped-by: Phillip Wood <[email protected]> Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 055bb6e commit 6cbae64

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,7 @@ THIRD_PARTY_SOURCES += sha1collisiondetection/%
13401340
THIRD_PARTY_SOURCES += sha1dc/%
13411341

13421342
UNIT_TEST_PROGRAMS += t-basic
1343+
UNIT_TEST_PROGRAMS += t-mem-pool
13431344
UNIT_TEST_PROGRAMS += t-strbuf
13441345
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
13451346
UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))

mem-pool.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
9999

100100
if (!p) {
101101
if (len >= (pool->block_alloc / 2))
102-
return mem_pool_alloc_block(pool, len, pool->mp_block);
103-
104-
p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
102+
p = mem_pool_alloc_block(pool, len, pool->mp_block);
103+
else
104+
p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
105105
}
106106

107107
r = p->next_free;

t/unit-tests/t-mem-pool.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "test-lib.h"
2+
#include "mem-pool.h"
3+
4+
static void setup_static(void (*f)(struct mem_pool *), size_t block_alloc)
5+
{
6+
struct mem_pool pool = { .block_alloc = block_alloc };
7+
f(&pool);
8+
mem_pool_discard(&pool, 0);
9+
}
10+
11+
static void t_calloc_100(struct mem_pool *pool)
12+
{
13+
size_t size = 100;
14+
char *buffer = mem_pool_calloc(pool, 1, size);
15+
for (size_t i = 0; i < size; i++)
16+
check_int(buffer[i], ==, 0);
17+
if (!check(pool->mp_block != NULL))
18+
return;
19+
check(pool->mp_block->next_free != NULL);
20+
check(pool->mp_block->end != NULL);
21+
}
22+
23+
int cmd_main(int argc, const char **argv)
24+
{
25+
TEST(setup_static(t_calloc_100, 1024 * 1024),
26+
"mem_pool_calloc returns 100 zeroed bytes with big block");
27+
TEST(setup_static(t_calloc_100, 1),
28+
"mem_pool_calloc returns 100 zeroed bytes with tiny block");
29+
30+
return test_done();
31+
}

0 commit comments

Comments
 (0)