这是一个便宜的技巧,但是我正在尝试更改正在处理的C库的分配方法。由于某种原因,它使用了GlobalLock,也许是因为它曾经是多个DLL。我将其更改为alloc:
HANDLE BmiDibAlloc(size_t uBytes)
{
HANDLE alloc = malloc(uBytes + sizeof (size_t));
if (alloc != NULL)
{
memcpy_s(alloc, sizeof (alloc), &uBytes, sizeof (size_t));
}
return BmiDibAttach(alloc); //just tracks the number of memory allocs for logging
}
BOOL BmiDibFree(HANDLE hdib)
{
if (!hdib) {
return TRUE;
}
free(hdib);
// Forget this handle:
return BmiDibDetach(hdib);
}
由于无法再使用GlobalSize,因此我会在第一个sizeof(size_t)个字节上增加分配的大小...
当使用第一种方法分配后,位图写得很好时-但是,当我到达Free时,它将抛出堆损坏。既然它可能在这些调用之间,那么有人会从给出的信息中看出一些问题吗?
最佳答案
当您分配一个块时,您会分配更多的空间,将标头存储在该块的开头,然后返回一个指向该块内偏移量的指针(而不是该块的开头)。例如“返回分配+ sizeof(MY_HEADER)”。
当您释放一个块时,您必须执行相反的操作。例如:
BOOL BmiDibFree(HANDLE callerPointer)
{
actualPointer = callerPointer - sizeof(MY_HEADER);
free(actualPointer);
注意1:为了提高性能,应确保“ sizeof(MY_HEADER)”是“ malloc()”提供的最小对齐方式的倍数;这样您就不会对调用方造成对齐错误的问题。
注意2:您可以在块的实际开始和块的实际结尾添加“ canaries”(魔术数字),并检查它们(在释放和重新分配期间),以增加检测堆损坏的机会。我这样做并设置了“堆已损坏”标志,并在进行任何malloc / free / realloc之前测试此标志(如果堆已损坏,则所有后续操作都将立即失败,以避免使混乱变大)。
注意3:您可以使用条件编译(例如“ #ifdef DEBUGGING”)来启用/禁用包装器的各种功能。我也这样做-一种启用额外检查(金丝雀),另一种启用统计信息的收集/报告(分配的块总数,随时分配的最大块数,分配的字节总数,最大数目随时分配的字节数)。