Tuesday, 15 June 2010

c - Custom Memory Mapped Allocator SEGFAULTs on allocate after freeing -



c - Custom Memory Mapped Allocator SEGFAULTs on allocate after freeing -

so needed simple allocator allocate (on occasion zeroing) , later free 4k blocks pool of mapped memory. however, after implementing this, while testing found after freeing block or two, if tried allocate block, programme segfault.

curiously enough, when free multiple blocks in row, nil seems break.

some of import definitions collected other files:

#define xmattr_constant __attribute__((const)) #define xmattr_malloc __attribute__((malloc)) #define xmattr_pure __attribute__((pure)) #define xm_likely(x) __builtin_expect(!!(x), 1) #define xm_unlikely(x) __builtin_expect(!!(x), 0) #define ablklen 4096 // 4k pagesize typedef struct { uint8_t magic[16]; // "sfdb5" "vx.xxxxxxx" '\0' uint8_t *freelist; uint64_t size; uint64_t bounds; } arenaheader;

allocation code:

void *pd_arena; void pd_init (size_t len, uint8_t *map) { int x; size_t const block = len / 256; // arena physical size size_t const size = (block / ablklen) * ablklen; // arena useable size arenaheader *header; (x = 0; x < 256; x++) { header = (void *) &(map[x * block]); header->freelist = null; // no free blocks because free header->size = size; // useable size header->bounds = ablklen; // current bounds } return; } xmattr_malloc void *pd_mallocbk (void) { arenaheader *header = pd_arena; uint8_t *ptr; if (xm_unlikely (header->freelist)) { // there's sitting free block ptr = header->freelist; // homecoming free block void **next = ptr; header->freelist = *next; // update free list } else if (xm_likely (header->bounds < header->size)) { // no free blocks ptr = pd_arena; ptr += header->size; header->size += ablklen; } else { // no more blocks ptr = null; } homecoming ptr; } xmattr_malloc void *pd_callocbk (void) { void *ptr = pd_mallocbk (); if (xm_likely (ptr)) // allocation successful memset (ptr, 0, ablklen); homecoming ptr; } void pd_freebk (void *ptr) { arenaheader *header = pd_arena; if (xm_likely (ptr)) { // non-null ptr void *next = header->freelist; // current top of stack void **this = ptr; *this = next; // move address of current top of stack ptr header->freelist = ptr; // force ptr stack } return; }

test code:

#define f_len (1024 * 1024 * 1024) // 1 gb #define a_len (f_len / 256) int main (int argc, char **argv) { int x, y; // setup int fd; uint8_t *map; assert (fd = open ("./pd_single.testout", o_creat | o_rdwr | o_excl)); if (ftruncate (fd, f_len)) { perror ("ftruncate failed: "); homecoming 1; } assert (map = mmap (null, f_len, prot_read | prot_write, map_file | map_shared, fd, 0)); uint8_t *arena[256]; (x = 0; x < 256; x++) arena[x] = map + (x * a_len); // test volatile int *var; void *list[512]; int lcnt = 0; pd_init (f_len, map); // per arena test (x = 0; x < 256; x++) { pd_arena = arena[x]; // allocate , write few times (y = 0; y < 256; y++) { assert ((list[lcnt] = pd_mallocbk ())); var = list[lcnt]; *var = (x + 1) * (y + 1); } // free not (y = 0; y < 64; y++) pd_freebk (list[lcnt]); // reallocate , write (y = 0; y < 16; y++) { assert ((list[lcnt] = pd_mallocbk())); var = list[lcnt]; *var = 16; } } // cleanup munmap (map, f_len); close (fd); homecoming 0; }

after running programme through gdb, found segfaults within pd_mallocbk(); specifically, on line:

header->freelist = *next; // update free list

however, can't seem understand wrong line and/or how prepare it.

so, 2 questions, (in order of importance, least):

what wrong selected line , how can prepare it? are there other allocators can assign part of mapped memory utilize instead of having implement this?

the next code works improve original, still crashes when starting work on lastly arena.

#include <assert.h> #include <fcntl.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> #define xmattr_malloc __attribute__((malloc)) #define xm_likely(x) __builtin_expect(!!(x), 1) #define xm_unlikely(x) __builtin_expect(!!(x), 0) enum { ablklen = 4096 }; void pd_freebk(void *ptr); xmattr_malloc void *pd_callocbk(void); xmattr_malloc void *pd_mallocbk(void); void pd_init(size_t len, uint8_t *map); typedef struct { uint8_t magic[16]; // "sfdb5" "vx.xxxxxxx" '\0' uint8_t *freelist; uint64_t size; uint64_t bounds; } arenaheader; static void *pd_arena; static void pd_dump_arena(file *fp, const char *tag, const arenaheader *arena) { assert(arena != null); fprintf(fp, "arena: 0x%.8" prixptr " - %s\n", (uintptr_t)arena, tag); fprintf(fp, "size: %.8" priu64 ", bounds: %.8" priu64 ", freelist: 0x%.8" prixptr "\n", arena->size, arena->bounds, (uintptr_t)arena->freelist); } void pd_init(size_t len, uint8_t *map) { size_t const block = len / 256; // arena physical size size_t const size = (block / ablklen) * ablklen; // arena useable size arenaheader *header; (int x = 0; x < 256; x++) { header = (void *) &(map[x * block]); header->freelist = null; // no free blocks because free header->size = size; // useable size header->bounds = ablklen; // current bounds } (int x = 0; x < 256; x++) { char buffer[32]; sprintf(buffer, "arena %.3d", x); pd_dump_arena(stdout, buffer, (arenaheader *)&map[x * block]); } } xmattr_malloc void *pd_mallocbk(void) { arenaheader *header = pd_arena; void *ptr; if (xm_unlikely(header->freelist)) // there's sitting free block { ptr = header->freelist; // homecoming free block void **next = ptr; header->freelist = *next; // update free list } else if (xm_likely(header->bounds < header->size)) // no free blocks { ptr = pd_arena; ptr = (uint8_t *)ptr + header->size; header->size += ablklen; } else // no more blocks { ptr = null; } homecoming ptr; } xmattr_malloc void *pd_callocbk(void) { void *ptr = pd_mallocbk(); if (xm_likely(ptr)) // allocation successful memset(ptr, 0, ablklen); homecoming ptr; } void pd_freebk(void *ptr) { arenaheader *header = pd_arena; if (xm_likely(ptr)) // non-null ptr { void *next = header->freelist; // current top of stack void **this = ptr; *this = next; // move address of current top of stack ptr header->freelist = ptr; // force ptr stack } } enum { num_arenas = 256 }; #define f_len (1024 * 1024 * 1024) // 1 gb #define a_len (f_len / num_arenas) int main(void) { const char filename[] = "./pd_single.testout"; // setup //int fd = open(filename, o_creat | o_rdwr | o_excl, 0444); int fd = open(filename, o_creat | o_rdwr, 0600); assert(fd >= 0); if (ftruncate(fd, f_len)) { unlink(filename); perror("ftruncate failed: "); homecoming 1; } uint8_t *map = mmap(null, f_len, prot_read | prot_write, map_file | map_shared, fd, 0); assert(map != map_failed); uint8_t *arena[num_arenas]; (int x = 0; x < num_arenas; x++) arena[x] = map + (x * a_len); pd_init(f_len, map); // test void *list[512]; // per arena test (int x = 0; x < num_arenas; x++) { int lcnt = 0; pd_arena = arena[x]; printf("arena[%.3d] = 0x%.8" prixptr "\n", x, (uintptr_t)pd_arena); // allocate , write few times (int y = 0; y < 256; y++) { assert((list[lcnt] = pd_mallocbk())); int *var = list[lcnt]; *var = (x + 1) * (y + 1); printf("[%.3d] info 0x%.8" prixptr " = %d\n", y, (uintptr_t)list[lcnt], *var); lcnt++; } // free not lcnt = 0; (int y = 0; y < 64; y++) { printf("[%.3d] free 0x%.8" prixptr " = %d\n", y, (uintptr_t)list[lcnt], *(int *)list[lcnt]); pd_freebk(list[lcnt]); lcnt++; } // reallocate , write lcnt = 0; (int y = 0; y < 16; y++) { assert((list[lcnt] = pd_mallocbk())); int *var = list[lcnt]; *var = 16; printf("[%.3d] info 0x%.8" prixptr " = %d\n", y, (uintptr_t)list[lcnt], *var); lcnt++; } } // cleanup munmap(map, f_len); close(fd); unlink(filename); homecoming 0; }

i've not yet tracked downwards residual bug. note diagnostic printing (verbose) , different handling of lcnt in main(). busy freeing same memory multiple times, not detecting in pd_freebk() code. leaking memory because not incrementing lcnt in main().

c memory-management segmentation-fault

No comments:

Post a Comment