calloc()替换中的内存对齐问题?

ash*_*449 1 c embedded heap

使用下面的代码我正在尝试编写一个包装器,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)

知道为什么会造成这个问题吗?

shf*_*301 5

你的问题是这一行:

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指针未指向正确的位置,调用代码将溢出分配的缓冲区的末端,从而破坏堆.


Sec*_*att 5

您的代码有几个问题:

  1. 在编写堆函数或堆包装器时,不要使用指针算法来存储堆头.使用结构.这就是他们的目的.

  2. 您已在代码中引入了许多整数溢出错误.如果有人问您calloc()0xfffffffe字节,您将返回4个字节.如果他们为该分配写入超过4个字节,则会出现堆溢出.

  3. calloc()的签名不一样calloc().根据您的交换方式calloc(),这可能会成为一个问题.

  4. 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)