使用下面的代码我正在尝试编写一个包装器,calloc()以便通过将大小存储在分配的内存的第1个2/4bytes中来保存已分配堆内存的跟踪.当我单独测试这个似乎没关系.但是,当我将calloc()其替换为我的系统时,它的创建问题就意味着它有时会返回NULL,即使有很多堆可用.
我正在使用IAR编译器在ARM板上运行它:
void *MyCalloc(size_t size) {
size_t new_size = ((size + 3) & ~0x3);
size_t *result = calloc(1,new_size + sizeof(size_t));
if ( result ) {
printf("MyCalloc addr: %p\n", result);
*result = (new_size + sizeof(size_t));
result = result + sizeof(size_t);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
知道为什么会造成这个问题吗?
你的问题是这一行:
result = result + sizeof(size_t);
Run Code Online (Sandbox Code Playgroud)
使用指针添加时,数字隐含地乘以指针的大小.所以
result = result + 1;
Run Code Online (Sandbox Code Playgroud)
将按sizeof(size_t)字节向前移动结果指针.这是你想要的.因为
result = result + sizeof(size_t);
Run Code Online (Sandbox Code Playgroud)
将结果指针按sizeof(size_t) * sizeof(size_t)字节向前移动.
因此,result指针未指向正确的位置,调用代码将溢出分配的缓冲区的末端,从而破坏堆.
您的代码有几个问题:
在编写堆函数或堆包装器时,不要使用指针算法来存储堆头.使用结构.这就是他们的目的.
您已在代码中引入了许多整数溢出错误.如果有人问您calloc()0xfffffffe字节,您将返回4个字节.如果他们为该分配写入超过4个字节,则会出现堆溢出.
你calloc()的签名不一样calloc().根据您的交换方式calloc(),这可能会成为一个问题.
calloc()并malloc()自然地返回对齐的指针.在x86中,他们需要返回一个指向应用程序的指针,该指针至少与8个字节对齐,而在x64中,它们需要返回一个至少16字节对齐的指针.
在你的代码中,你使用真正的calloc进行"繁重的提升"(即作为"原始分配器"),这很好并且将返回一个8或16字节对齐的指针,但当你返回一个指针在该结构中有4个字节,你的calloc最终会返回一个指向调用者的非对齐指针,这可能会给调用calloc替换的人带来问题.
尝试一些更像这样的代码:
typedef struct
{
size_t cbSize;
} MyAwesomeHeapHeader;
// TODO: ensure that MyAwesomeHeapHeader is 8-byte aligned on x86 and 16-byte aligned on x64 (or just 16-byte aligned on both).
void* MyAwesomeMalloc(size_t cbSize)
{
MyAwesomeHeapHeader* header;
void* internalAllocatorPtr;
size_t cbAlloc;
// TODO: Maybe I want a heap footer as well?
// TODO: I should really check the following for an integer overflow:
cbAlloc = sizeof(MyAwesomeHeapHeader) + cbSize;
internalAllocatorPtr = MyAwesomeRawAllocator(cbAlloc); // at the moment you're using the real calloc for this, but you could use malloc or write your own raw allocator
// TODO: Check for null
header = (MyAwesomeHeapHeader*)internalAllocatorPtr;
header->heapSize = cbSize;
// TODO: other fields here.
return (uint8_t*)(internalAllocatorPtr) + sizeof(MyAwesomeHeapHeader);
}
Run Code Online (Sandbox Code Playgroud)