Skip to content
Permalink
Browse files

malloc: make sure returned memory is properly aligned

The accounting data stored at the beginning of a memory block used by
malloc must push the returned memory address to a word boundary. This
is already the case on 32-bit systems, but not on 64-bit systems where
e.g. struct k_mem_block_id still has a size of 4.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
  • Loading branch information...
Nicolas Pitre authored and andrewboie committed May 23, 2019
1 parent 1578ef7 commit 39cd2ebef7ac0b4b0b79fdc4876cfd3430915e84
Showing with 10 additions and 8 deletions.
  1. +4 −3 kernel/mempool.c
  2. +4 −3 lib/os/mempool.c
  3. +2 −2 tests/kernel/mem_heap/mheap_api_concept/src/test_mheap_concept.c
@@ -141,7 +141,8 @@ void *k_mem_pool_malloc(struct k_mem_pool *pool, size_t size)
* get a block large enough to hold an initial (hidden) block
* descriptor, as well as the space the caller requested
*/
if (size_add_overflow(size, sizeof(struct k_mem_block_id), &size)) {
if (size_add_overflow(size, WB_UP(sizeof(struct k_mem_block_id)),
&size)) {
return NULL;
}
if (k_mem_pool_alloc(pool, &block, size, K_NO_WAIT) != 0) {
@@ -152,14 +153,14 @@ void *k_mem_pool_malloc(struct k_mem_pool *pool, size_t size)
(void)memcpy(block.data, &block.id, sizeof(struct k_mem_block_id));

/* return address of the user area part of the block to the caller */
return (char *)block.data + sizeof(struct k_mem_block_id);
return (char *)block.data + WB_UP(sizeof(struct k_mem_block_id));
}

void k_free(void *ptr)
{
if (ptr != NULL) {
/* point to hidden block descriptor at start of block */
ptr = (char *)ptr - sizeof(struct k_mem_block_id);
ptr = (char *)ptr - WB_UP(sizeof(struct k_mem_block_id));

/* return block to the heap memory pool */
k_mem_pool_free_id(ptr);
@@ -349,7 +349,7 @@ void *sys_mem_pool_alloc(struct sys_mem_pool *p, size_t size)

sys_mutex_lock(&p->mutex, K_FOREVER);

size += sizeof(struct sys_mem_pool_block);
size += WB_UP(sizeof(struct sys_mem_pool_block));
if (z_sys_mem_pool_block_alloc(&p->base, size, &level, &block,
(void **)&ret)) {
ret = NULL;
@@ -360,7 +360,7 @@ void *sys_mem_pool_alloc(struct sys_mem_pool *p, size_t size)
blk->level = level;
blk->block = block;
blk->pool = p;
ret += sizeof(*blk);
ret += WB_UP(sizeof(struct sys_mem_pool_block));
out:
sys_mutex_unlock(&p->mutex);
return ret;
@@ -375,7 +375,8 @@ void sys_mem_pool_free(void *ptr)
return;
}

blk = (struct sys_mem_pool_block *)((char *)ptr - sizeof(*blk));
ptr = (char *)ptr - WB_UP(sizeof(struct sys_mem_pool_block));
blk = (struct sys_mem_pool_block *)ptr;
p = blk->pool;

sys_mutex_lock(&p->mutex, K_FOREVER);
@@ -31,12 +31,12 @@ void test_mheap_malloc_align4(void)

/**
* TESTPOINT: The address of the allocated chunk is guaranteed to be
* aligned on a multiple of 4 bytes.
* aligned on a word boundary (4 or 8 bytes).
*/
for (int i = 0; i < BLK_NUM_MAX; i++) {
block[i] = k_malloc(i);
zassert_not_null(block[i], NULL);
zassert_false((int)block[i] % 4, NULL);
zassert_false((uintptr_t)block[i] % sizeof(void *), NULL);
}

/* test case tear down*/

0 comments on commit 39cd2eb

Please sign in to comment.
You can’t perform that action at this time.