diff options
author | Jan Palus <jpalus@fastmail.com> | 2022-10-05 00:18:09 +0200 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2022-10-31 09:42:40 +0100 |
commit | 0240fd6d0f7e27c459b243578ad51100ff6e2b66 (patch) | |
tree | 98e4bdc62b7e970c13b64715adb694652f8b0014 | |
parent | 19dab2ead2dfc49c24e004fcdbbef6948b7bde94 (diff) | |
download | rneovim-0240fd6d0f7e27c459b243578ad51100ff6e2b66.tar.gz rneovim-0240fd6d0f7e27c459b243578ad51100ff6e2b66.tar.bz2 rneovim-0240fd6d0f7e27c459b243578ad51100ff6e2b66.zip |
fix(memory): fix memory alignment for dynamic allocation
all pointers returned by arena_alloc residing in arena block should be
properly aligned
to meet neovim's alignment requirements but keeping it simple settle on
ARENA_ALIGN = MAX(sizeof(void *), sizeof(double)).
-rw-r--r-- | src/nvim/memory.c | 32 | ||||
-rw-r--r-- | src/nvim/memory.h | 2 |
2 files changed, 20 insertions, 14 deletions
diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 61c43d8f99..93aa9bd6e5 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -6,6 +6,7 @@ #include <assert.h> #include <inttypes.h> #include <stdbool.h> +#include <stdint.h> #include <string.h> #include "nvim/api/extmark.h" @@ -576,6 +577,12 @@ void alloc_block(Arena *arena) blk->prev = prev_blk; } +static size_t arena_align_offset(void *ptr, size_t alignment) +{ + uintptr_t uptr = (uintptr_t)ptr; + return ((uptr + (alignment - 1)) & ~(alignment - 1)) - uptr; +} + /// @param arena if NULL, do a global allocation. caller must then free the value! /// @param size if zero, will still return a non-null pointer, but not a unique one void *arena_alloc(Arena *arena, size_t size, bool align) @@ -583,34 +590,33 @@ void *arena_alloc(Arena *arena, size_t size, bool align) if (!arena) { return xmalloc(size); } - if (align) { - arena->pos = (arena->pos + (ARENA_ALIGN - 1)) & ~(ARENA_ALIGN - 1); + if (!arena->cur_blk) { + alloc_block(arena); } - if (arena->pos + size > arena->size || !arena->cur_blk) { - if (size > (ARENA_BLOCK_SIZE - sizeof(struct consumed_blk)) >> 1) { + size_t align_pos = align ? arena_align_offset(arena->cur_blk + arena->pos, ARENA_ALIGN) : 0; + if (arena->pos + align_pos + size > arena->size) { + if (size + (align ? (ARENA_ALIGN - 1) : 0) > (ARENA_BLOCK_SIZE - sizeof(struct consumed_blk)) + >> 1) { // if allocation is too big, allocate a large block with the requested // size, but still with block pointer head. We do this even for // arena->size / 2, as there likely is space left for the next // small allocation in the current block. - if (!arena->cur_blk) { - // to simplify free-list management, arena->cur_blk must - // always be a normal, ARENA_BLOCK_SIZE sized, block - alloc_block(arena); - } arena_alloc_count++; - char *alloc = xmalloc(size + sizeof(struct consumed_blk)); + char *alloc = xmalloc(size + sizeof(struct consumed_blk) + (align ? (ARENA_ALIGN - 1) : 0)); struct consumed_blk *cur_blk = (struct consumed_blk *)arena->cur_blk; struct consumed_blk *fix_blk = (struct consumed_blk *)alloc; fix_blk->prev = cur_blk->prev; cur_blk->prev = fix_blk; - return (alloc + sizeof(struct consumed_blk)); + char *mem = (alloc + sizeof(struct consumed_blk)); + return mem + (align ? arena_align_offset(mem, ARENA_ALIGN) : 0); } else { alloc_block(arena); + align_pos = align ? arena_align_offset(arena->cur_blk + arena->pos, ARENA_ALIGN) : 0; } } - char *mem = arena->cur_blk + arena->pos; - arena->pos += size; + char *mem = arena->cur_blk + arena->pos + align_pos; + arena->pos += (size + align_pos); return mem; } diff --git a/src/nvim/memory.h b/src/nvim/memory.h index f407192331..1c2ed2ba3b 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -45,7 +45,7 @@ typedef struct consumed_blk { struct consumed_blk *prev; } *ArenaMem; -#define ARENA_ALIGN sizeof(void *) +#define ARENA_ALIGN MAX(sizeof(void *), sizeof(double)) typedef struct { char *cur_blk; |