Trầ*_* Dự 4 c segmentation-fault
我实现了一个自定义内存分配器。这个内部文件的所有主要代码memory.c我都在这个文件中创建了一个主函数来测试函数。一切正常。但是当我将这些测试代码移动到另一个文件(调用main.c并运行它)时,我遇到了分段错误。
int main (int argc, char *argv []) {
allocator_init();
char* ptr = (char*) allocate(4096); // csutom function. that on `memory.c`
strcpy(ptr, "this is the test one");// segmentation fault here
printf("print: %s\n", ptr);
deallocate(ptr);
}
Run Code Online (Sandbox Code Playgroud)
这是主要代码:
volatile Memory memory;
/* allocated memory to memory variable by assign /dev/zero to 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 to optimize
PAGE_SIZE = getPageSize();
// fd = open("ZEROES", O_RDWR);
if(fd == -1) {
perror("File open failed");
exit(0);
}
// Initialize the region list
memory.region = NULL;
int i;
/// Initialize the caches
/// size of each cache is 16 * 2^i => 16, 32, 64, 128, 256, 512, 1024, 2048
for (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 from mapped address */
region = mapped_addr;
region->size = size;
region->addr = mapped_addr + REGION_SIZE;
printf("allocated region: %p\n", region->addr);
/* assign this region to memory */
memory.region = region;
/* just simple append algorithm in linked list. so new region will be appended to 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);
}
Run Code Online (Sandbox Code Playgroud)
这是memory.h定义我使用过的所有结构:
#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 up to the 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 for 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 for caller (can calc by allocated address + Region size)
int size; /// size of this allocated Region (not include size Region)
struct __Region *next;
} Region;
/// size of Slab equals to size of System Page
typedef struct __Slab {
void *addr; /// address of this slab (exclude header)
char *bitmap; /// started address can use for caller (can calc by allocated address + slab size)
int size;
int slots; /// number of slots in maximum has been used
int cache_size; /// size of cache that contains this slab
int bitmap_size; /// size of bitmap. so, can count address bit by bitmap + bitmap_size
int currentSize; /// current allocated elements of this slab. currentSize = 0. deallocated this slab
int bit; /// bit to marked which 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
Run Code Online (Sandbox Code Playgroud)
上面的代码可以正常工作,allocate函数返回一个地址。我只是在移动到另一个文件时遇到错误。在我的中memory.c,我有一些全局变量来控制分配的地址和内存。当我将代码移动到新文件时它会影响吗?我无法解释这一点。
谢谢 :)
有一些值得观察的地方:
\n\nallocator_init()、allocate()和deallocate_cache()。文件中的其他所有内容都是实现细节,应该对代码的使用者隐藏。extern在标头中的变量前面编写,则应该以 为前缀,static并且您最好有一个很好的理由。(有关完整的讨论,请参阅如何在 C 中的源文件之间共享变量。)_保留供实现使用。这有点过于简化,但它涵盖了所有基础,并且比形式上正确的规则更容易记住。以 开头的名称__绝对是禁止的(100%;不涉及简化)。不要为自己定义此类名称,并且在代码中使用此类名称时要格外小心(它们通常是您可能不应该使用的类型)。我只是从结构标签中删除了前导下划线;它工作得很愉快。"bits.h",但幸运的是您的代码没有使用其中的任何内容,因此注释掉它效果很好。getPageSize()但未定义它。也许是情有可原的;我用4096代替。追踪发现这是一个在标题中定义的变量,导致了这场解释该做什么的PAGE_SIZE争论的开始。它应该是文件中的变量。从源文件外部可见的唯一内容应该是消费者需要使用的那些函数(也许还有全局变量)。其他一切都应该是不可见的\xe2\x80\x94,没有名称冲突,没有误用或滥用的可能性。staticmemory.cstaticPAGE_SIZE未使用。顺便说一句,当代码可以在源代码外部访问时,因为它不是静态的,所以将所有可以静态的东西都变成静态定义 \xe2\x80\x94 是另一个优点,编译器无法警告未使用的变量或功能。MAX_SIZE您的标头为;定义了两个不同的值 不!#define TRUE 1; 再说一次,不要。(MAX_SIZE也没有使用,也没有FALSE,也没有SLAB_SIZE,\xe2\x80\xa6)你的ALIGN宏有问题:
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~0x7)\nRun Code Online (Sandbox Code Playgroud)\n\n按照目前的情况,ALIGNMENT 为 8,并且宏有效。但假设我将 ALIGNMENT 更改为 16;那么面具是错误的。应该是吧& ~(ALIGNMENT - 1)。请注意明显不完整的参数化。
EXIT_FAILURE\xe2\x80\x94 或遵循其他一些本地相关方案。deallocate_cache()但您的主程序调用了deallocate(),并且没有给出两者的代码。命名不一致是有问题的。我使用了一个虚拟实现。显然,还必须添加必要的标头。好的; 修复了该批次后,编译并链接了代码。然后我遇到了:
\n\nMapping failed: Operation not supported by device\nRun Code Online (Sandbox Code Playgroud)\n\n这是 Mac OS X 10.9.2 Mavericks。仅供参考。我通过创建一个空文件./dev.zero并引用它来解决这个问题。当心可移植性假设。
然后它因总线错误(信号 10)而崩溃。它没有打印消息allocated region。这将损坏限制在 3 行代码内。
你不能对void *标准 C 中的类型进行算术运算。GCC 允许你这样做;但是,不要在具有任何可移植性的代码中利用这一点。
当我创建一个空文件时,程序崩溃了。当我将dd if=/dev/zero of=dev.zero bs=1k count=1024文件初始化为全零时,程序不再崩溃。我添加了一堆调试打印代码。
我建议不要使用/dev/zero您的映射文件。
Mapping succeeded: 0x10ca74000\nregion = 0x10ca74000\nsize = 4096\nallocated region: 0x10ca74018\nMemory: allocate_region (0x10ca40080)\nRegion: Base (0x10ca74000)\nAddress: 0x10ca74018, size: 4096, next = 0x0\nCache: line 0 (0x10ca40088)\nSize: 16\nCache: line 1 (0x10ca40098)\nSize: 32\nCache: line 2 (0x10ca400a8)\nSize: 64\nCache: line 3 (0x10ca400b8)\nSize: 128\nCache: line 4 (0x10ca400c8)\nSize: 256\nCache: line 5 (0x10ca400d8)\nSize: 512\nCache: line 6 (0x10ca400e8)\nSize: 1024\nCache: line 7 (0x10ca400f8)\nSize: 2048\nptr = 0x10ca74018\nprint: this is the test one\ndeallocate called for 0x10ca74018: unimplemented\nRun Code Online (Sandbox Code Playgroud)\n\n#ifndef MEMORY_H\n#define MEMORY_H\n\nextern void allocator_init(void);\nextern void deallocate(void *ptr);\nextern void *allocate(unsigned int size);\n\n#endif // MEMORY_H\nRun Code Online (Sandbox Code Playgroud)\n\n#include <stdio.h>\n#include <string.h>\n#include "memory.h"\n\nint main(void)\n{\n allocator_init();\n char *ptr = (char *) allocate(4096); // custom function. that on `memory.c`\n printf("ptr = %p\\n", ptr);\n strcpy(ptr, "this is the test one"); // segmentation fault here\n printf("print: %s\\n", ptr);\n deallocate(ptr);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n#include "memory.h"\n#include <assert.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/mman.h>\n#include <unistd.h>\n\n#define REGION_SIZE sizeof(Region)\n\n#define ALIGNMENT 8\n#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))\n\n#if defined(DEV_ZERO_MEMORY_MAPPING)\n#define DEV_ZERO "/dev/zero"\n#else\n#define DEV_ZERO "./dev.zero"\n#endif\n\nenum { NUM_CACHES = 8 };\n\nstatic int fd = -1;\n\ntypedef struct Region\n{\n void *addr;\n int size;\n struct Region *next;\n} Region;\n\ntypedef struct Slab\n{\n void *addr;\n char *bitmap;\n int size;\n int slots;\n int cache_size;\n int bitmap_size;\n int currentSize;\n int bit;\n struct Slab *next;\n} Slab;\n\ntypedef struct Cache\n{\n int size;\n Slab *S;\n} Cache;\n\ntypedef struct Memory\n{\n Region *region;\n Cache cache[NUM_CACHES];\n} Memory;\n\nstatic Memory memory = { 0 };\n\nstatic void dump_slab(FILE *fp, const char *tag, const Slab *slab)\n{\n fprintf(fp, "Slab: %s (%p)\\n", tag, slab);\n if (slab != 0)\n {\n fprintf(fp, "addr: %p, ", slab->addr);\n fprintf(fp, "bitmap: %p, ", (void *)slab->bitmap);\n fprintf(fp, "size: %6d, slots %3d, ", slab->size, slab->slots);\n /*\n int cache_size;\n int bitmap_size;\n int currentSize;\n int bit;\n struct Slab *next;\n */\n }\n}\n\nstatic void dump_cache(FILE *fp, const char *tag, const Cache *cache)\n{\n fprintf(fp, "Cache: %s (%p)\\n", tag, cache);\n if (cache != 0)\n {\n fprintf(fp, "Size: %d\\n", cache->size);\n Slab *slab = cache->S;\n while (slab != 0)\n {\n dump_slab(fp, "", slab);\n slab = slab->next;\n }\n }\n}\n\nstatic void dump_region(FILE *fp, const char *tag, const Region *reg)\n{\n fprintf(fp, "Region: %s (%p)\\n", tag, reg);\n if (reg != 0)\n {\n fprintf(fp, "Address: %p, size: %6d, next = %p\\n",\n reg->addr, reg->size, reg->next);\n }\n}\n\nstatic void dump_memory(FILE *fp, const char *tag, const Memory *mem)\n{\n fprintf(fp, "Memory: %s (%p)\\n", tag, mem);\n if (mem != 0)\n {\n Region *reg = mem->region;\n dump_region(fp, "Base", reg);\n while (reg->next != 0)\n {\n dump_region(fp, "Next", reg->next);\n reg = reg->next;\n }\n for (int i = 0; i < NUM_CACHES; i++)\n {\n char line[32];\n snprintf(line, sizeof(line), "line %d", i);\n dump_cache(fp, line, &memory.cache[i]);\n }\n }\n}\n\nvoid allocator_init(void)\n{\n fd = open(DEV_ZERO, O_RDWR|O_CREAT, 0600);\n if (fd == -1)\n {\n perror("File open failed");\n exit(0);\n }\n\n if (fd == -1)\n {\n perror("File open failed");\n exit(0);\n }\n\n memory.region = NULL;\n\n for (int i = 0; i < NUM_CACHES; i++)\n {\n memory.cache[i].size = 16 << i;\n memory.cache[i].S = NULL;\n }\n}\n\nstatic void *allocate_region(unsigned int size)\n{\n assert(fd != -1);\n\n Region *temp = memory.region;\n void *mapped_addr = mmap(NULL, size + REGION_SIZE, PROT_READ | PROT_WRITE,\n MAP_PRIVATE, fd, 0);\n\n if (mapped_addr == MAP_FAILED)\n {\n perror("Mapping failed");\n exit(0);\n }\n printf("Mapping succeeded: %p\\n", mapped_addr);\n\n Region *region = mapped_addr;\n printf("region = %p\\n", region);\n region->size = size;\n printf("size = %d\\n", region->size);\n region->addr = (char *)mapped_addr + REGION_SIZE;\n printf("allocated region: %p\\n", region->addr);\n\n memory.region = region;\n region->next = temp;\n\n dump_memory(stderr, __func__, &memory);\n\n return region->addr;\n}\n\nvoid *allocate(unsigned int size)\n{\n size = ALIGN(size);\n return allocate_region(size);\n}\n\nvoid deallocate(void *ptr)\n{\n fprintf(stderr, "%s called for %p: unimplemented\\n", __func__, ptr);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我强烈建议创建函数来沿着所示的dump_memory()、dump_region()、dump_cache()、dump_slab()函数转储复杂结构;它们通常非常有帮助,尽管它们实际上在调试过程中起到了转移注意力的作用。