C : Segmentation Fault when move main function to new file -
i implement custom memory allocator. main code inside file memory.c create main function in file test function. works fine. when move testing code file (calling main.c , run it. meet segmentation fault.
int main (int argc, char *argv []) { allocator_init(); char* ptr = (char*) allocate(4096); // csutom function. on `memory.c` strcpy(ptr, "this test one");// segmentation fault here printf("print: %s\n", ptr); deallocate(ptr); } here main code :
volatile memory memory; /* allocated memory memory variable assign /dev/zero memory */ void allocator_init() { fd = open("/dev/zero", o_rdwr); if(fd == -1) { perror("file open failed"); exit(0); } // page size can different on different platform. customize again optimize page_size = getpagesize(); // fd = open("zeroes", o_rdwr); if(fd == -1) { perror("file open failed"); exit(0); } // initialize region list memory.region = null; int i; /// initialize caches /// size of each cache 16 * 2^i => 16, 32, 64, 128, 256, 512, 1024, 2048 (i=0; i<8; i++) { memory.cache[i].size = 16<<i; memory.cache[i].s = null; } return; } void *allocate_region (unsigned int size) { region *region, *temp; temp = memory.region; void *mapped_addr = mmap(null, size + region_size, prot_read | prot_write, map_private, fd, 0); if(mapped_addr == map_failed) { perror("mapping failed"); exit(0); } /* create region mapped address */ region = mapped_addr; region->size = size; region->addr = mapped_addr + region_size; printf("allocated region: %p\n", region->addr); /* assign region memory */ memory.region = region; /* simple append algorithm in linked list. new region appended head of linked list */ region->next = temp; return region->addr; } /* allocate : if size < 2048 : allocate cache. else allocate region */ void *allocate(unsigned int size) { size = align(size); return allocate_region(size); } here memory.h define struct have used:
#ifndef memory_h #define memory_h #define max_size (1024*1024) #define region_size sizeof(region) #define slab_size sizeof(slab) #define word_size 32 #define alignment 8 /* rounds nearest multiple of alignment */ #define align(size) (((size) + (alignment-1)) & ~0x7) #define size_t_size (align(sizeof(size_t))) #define true 1 #define false 0 #define max_size 10000 // caches are: // 16, 32, 64, 128, 256, 512, 1024, 2048 #include "bits.h" int page_size; // file descriptor zeroes file int fd; void allocator_init(); int deallocate_cache(void* ptr); void *allocate(unsigned int size); typedef struct __region { void *addr; /// started address can use caller (can calc allocated address + region size) int size; /// size of allocated region (not include size region) struct __region *next; } region; /// size of slab equals size of system page typedef struct __slab { void *addr; /// address of slab (exclude header) char *bitmap; /// started address can use caller (can calc allocated address + slab size) int size; int slots; /// number of slots in maximum has been used int cache_size; /// size of cache contains slab int bitmap_size; /// size of bitmap. so, can count address bit bitmap + bitmap_size int currentsize; /// current allocated elements of slab. currentsize = 0. deallocated slab int bit; /// bit marked part of slab has been used struct __slab * next; } slab; typedef struct __cache { int size; slab *s; } cache; typedef struct __memory { region *region; cache cache[8]; } memory; #endif // memory_h above code works fine, allocate function return address. meet error when move file. in memory.c, have global variable control allocated address , memory. affect when move code new file ? cannot explain this.
thanks :)
there observations worth making:
- your header should declare consumer of code needs know. that's 3 functions:
allocator_init(),allocate(),deallocate_cache(). else in file implementation detail should hidden consumer of code. - headers should not define variables — not tentatively. if aren't writing
externin front of variable in header, should prefixedstatic, you'd better have reason it. (see how share variable between source files in c complete disquisition.) - names starting
_reserved implementation use. that's slight over-simplification, covers bases , easier remember formally correct rules. names starting__off-limits (100%; no simplification involved). don't define such names yourself, , extremely cautious using such names in code (they're types shouldn't using). removed leading underscores structure tags; works happily. - your header included
"bits.h", fortunately code didn't use it, commenting out worked fine. - your code uses
getpagesize()doesn't define it. excusable; used 4096 instead. , tracking down showedpage_sizevariable defined in header, leading start ofdiatribepolemic explaining to. shouldstaticvariable inmemory.cfile. things visible outside of source file should functions (and perhaps global variables) consumers need use. else shouldstaticinvisible — no name conflicts, no possibility of misuse or abuse. - when made static variable, compiler complains
page_sizeunused. that, incidentally, advantage of making can static static definition — when code accessed outside source because not static, compiler can't warn unused variables or functions. - your header defined 2 different values
max_size; don't! - your header defined unused values, such
#define true 1; again, don't. (max_sizewasn't used, either, norfalse, norslab_size, …) your
alignmacro faulty:#define align(size) (((size) + (alignment - 1)) & ~0x7)as stands, alignment 8, , macro works. suppose change alignment 16; mask wrong. should
& ~(alignment - 1). beware of apparent parameterization incomplete.- if exit because of error, should not exit status 0; means success. either use 1 or
exit_failure— or follow other locally relevant scheme. - your header declared
deallocate_cache()main program callsdeallocate(), code neither given. naming inconsistency problematic. used dummy implementation.
obviously, necessary headers had added, too. ok; lot fixed, code compiled , linked. ran into:
mapping failed: operation not supported device this mac os x 10.9.2 mavericks. fyi. worked around creating empty file ./dev.zero , referencing that. beware portability assumptions.
then crashed bus error, signal 10. didn't print allocated region message. limits damage 3 lines of code.
you cannot arithmetic on void * types in standard c. gcc allow it; don't take advantage of that, though, in code has pretensions portability.
when created empty file, program crashed. when used dd if=/dev/zero of=dev.zero bs=1k count=1024 initialize file zeros, program no longer crashed. i'd added bunch of debug printing code.
i suggest not using /dev/zero mapping file.
mapping succeeded: 0x10ca74000 region = 0x10ca74000 size = 4096 allocated region: 0x10ca74018 memory: allocate_region (0x10ca40080) region: base (0x10ca74000) address: 0x10ca74018, size: 4096, next = 0x0 cache: line 0 (0x10ca40088) size: 16 cache: line 1 (0x10ca40098) size: 32 cache: line 2 (0x10ca400a8) size: 64 cache: line 3 (0x10ca400b8) size: 128 cache: line 4 (0x10ca400c8) size: 256 cache: line 5 (0x10ca400d8) size: 512 cache: line 6 (0x10ca400e8) size: 1024 cache: line 7 (0x10ca400f8) size: 2048 ptr = 0x10ca74018 print: test 1 deallocate called 0x10ca74018: unimplemented code
memory.h
#ifndef memory_h #define memory_h extern void allocator_init(void); extern void deallocate(void *ptr); extern void *allocate(unsigned int size); #endif // memory_h main.c
#include <stdio.h> #include <string.h> #include "memory.h" int main(void) { allocator_init(); char *ptr = (char *) allocate(4096); // custom function. on `memory.c` printf("ptr = %p\n", ptr); strcpy(ptr, "this test one"); // segmentation fault here printf("print: %s\n", ptr); deallocate(ptr); } memory.c
#include "memory.h" #include <assert.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> #define region_size sizeof(region) #define alignment 8 #define align(size) (((size) + (alignment - 1)) & ~(alignment - 1)) #if defined(dev_zero_memory_mapping) #define dev_zero "/dev/zero" #else #define dev_zero "./dev.zero" #endif enum { num_caches = 8 }; static int fd = -1; typedef struct region { void *addr; int size; struct region *next; } region; typedef struct slab { void *addr; char *bitmap; int size; int slots; int cache_size; int bitmap_size; int currentsize; int bit; struct slab *next; } slab; typedef struct cache { int size; slab *s; } cache; typedef struct memory { region *region; cache cache[num_caches]; } memory; static memory memory = { 0 }; static void dump_slab(file *fp, const char *tag, const slab *slab) { fprintf(fp, "slab: %s (%p)\n", tag, slab); if (slab != 0) { fprintf(fp, "addr: %p, ", slab->addr); fprintf(fp, "bitmap: %p, ", (void *)slab->bitmap); fprintf(fp, "size: %6d, slots %3d, ", slab->size, slab->slots); /* int cache_size; int bitmap_size; int currentsize; int bit; struct slab *next; */ } } static void dump_cache(file *fp, const char *tag, const cache *cache) { fprintf(fp, "cache: %s (%p)\n", tag, cache); if (cache != 0) { fprintf(fp, "size: %d\n", cache->size); slab *slab = cache->s; while (slab != 0) { dump_slab(fp, "", slab); slab = slab->next; } } } static void dump_region(file *fp, const char *tag, const region *reg) { fprintf(fp, "region: %s (%p)\n", tag, reg); if (reg != 0) { fprintf(fp, "address: %p, size: %6d, next = %p\n", reg->addr, reg->size, reg->next); } } static void dump_memory(file *fp, const char *tag, const memory *mem) { fprintf(fp, "memory: %s (%p)\n", tag, mem); if (mem != 0) { region *reg = mem->region; dump_region(fp, "base", reg); while (reg->next != 0) { dump_region(fp, "next", reg->next); reg = reg->next; } (int = 0; < num_caches; i++) { char line[32]; snprintf(line, sizeof(line), "line %d", i); dump_cache(fp, line, &memory.cache[i]); } } } void allocator_init(void) { fd = open(dev_zero, o_rdwr|o_creat, 0600); if (fd == -1) { perror("file open failed"); exit(0); } if (fd == -1) { perror("file open failed"); exit(0); } memory.region = null; (int = 0; < num_caches; i++) { memory.cache[i].size = 16 << i; memory.cache[i].s = null; } } static void *allocate_region(unsigned int size) { assert(fd != -1); region *temp = memory.region; void *mapped_addr = mmap(null, size + region_size, prot_read | prot_write, map_private, fd, 0); if (mapped_addr == map_failed) { perror("mapping failed"); exit(0); } printf("mapping succeeded: %p\n", mapped_addr); region *region = mapped_addr; printf("region = %p\n", region); region->size = size; printf("size = %d\n", region->size); region->addr = (char *)mapped_addr + region_size; printf("allocated region: %p\n", region->addr); memory.region = region; region->next = temp; dump_memory(stderr, __func__, &memory); return region->addr; } void *allocate(unsigned int size) { size = align(size); return allocate_region(size); } void deallocate(void *ptr) { fprintf(stderr, "%s called %p: unimplemented\n", __func__, ptr); } i recommend making functions dump complex structures along dump_memory(), dump_region(), dump_cache(), dump_slab() functions shown; they're helpful, though of red herring in debugging this.
Comments
Post a Comment