【问题标题】:Does the pointer passed to free() have to point to beginning of the memory block, or can it point to the interior?传递给 free() 的指针是否必须指向内存块的开头,还是可以指向内部?
【发布时间】:2011-06-03 02:34:36
【问题描述】:

问题在标题中...我搜索但找不到任何东西。


编辑:

我真的认为没有必要解释这一点,但是因为人们认为我所说的没有意义(而且我问错了问题),所以问题就在这里:

由于人们似乎非常对所有问题的“根本”原因感兴趣,而不是对提出的实际问题感兴趣(因为这显然有助于更好地解决问题,让我们看看它是否有效),问题来了:

我正在尝试创建一个基于 NTDLL.dll 的 D 运行时库,以便我可以将该库用于 Win32 子系统以外的子系统。所以这迫使我只链接 NTDLL.dll。

是的,我知道这些函数是“未记录的”并且可能随时更改(尽管我打赌一百美元 wcstombs 仍然会做同样的事情确切 20年后,如果它仍然存在的话)。是的,我知道人们(尤其是微软)不喜欢链接到那个库的开发人员,我可能会因为这里而受到批评。是的,以上两点意味着像 chkdsk 和在 Win32 子系统之前运行的碎片整理程序这样的程序甚至不应该首先创建,因为实际上不可能与 kernel32 之类的任何东西链接.dll 或 msvcrt.dll 并且仍然具有 NT-native 可执行文件,因此我们开发人员应该假装这些阶段是我们永远无法企及的。

但是不,我怀疑这里的任何人都希望我粘贴几千行代码并帮助我查看它们并试图找出为什么没有失败的内存分配是被我正在修改的源代码拒绝。所以这就是为什么我问了一个与“根本”原因不同的问题,尽管这被认为是社区的最佳做法。

如果仍然没有任何意义,请随时在下面发布 cmets! :)


编辑 2:

经过大约 8 个小时的调试,我终于找到了问题所在:

事实证明,RtlReAllocateHeap() 确实不会自动像RtlAllocateHeap() 那样工作,如果给它的指针是NULL。

【问题讨论】:

  • 只是为了完成其他答案.. malloc() 记录它已分配的块,并在释放某些内容时将指针与该记录进行比较以检查它是否已分配。
  • @BlackBear:是的,这就是为什么它让我想知道为什么它不能只检查指针是否在块内(这有多难??)......跨度>
  • @BlackBear:实际上,在大多数实现中,堆只保存关于空闲块的信息。 free() 所需的数据(例如块的大小)由 malloc() 附加到分配的块中,从传递给 free() 以访问记录的指针中减去记录的大小。如果实现包含验证签名,则可以进行错误检测,否则无效记录将导致堆损坏。
  • @Clifford:啊,好吧,这很有道理。谢谢。
  • 哎哟:RtlReAllocateHeap() 不处理被赋予 NULL 指针?太糟糕了,MS 没有让它表现得像标准的 realloc() 函数,特别是因为它只需要几行代码。这是一个很难学习的教训。

标签: c memory-management free calloc


【解决方案1】:

它必须指向块的开头。将空指针传递给free() 是安全的,但传递任何未由malloc() 或其亲属分配的指针将导致未定义的行为。某些系统会给您一个运行时错误 - 类似于“释放未分配的指针”。

编辑:

我编写了一个测试程序来获取错误消息。在我的机器上,这个程序:

#include <stdlib.h>

int main(int argc, char **argv)
{
  int *x = malloc(12);
  x++;

  free(x);

  return 0;
}

崩溃并显示此消息:

app(31550) malloc: *** error for object 0x100100084: pointer being freed was not allocated

【讨论】:

  • 嗯......所以在这种情况下,有没有办法(可移植地)请求64字节对齐的内存?我打算分配更多并提取一块,但由于我正在传递指针,所以我无法在开始时跟踪未使用字节的大小......
  • @Lambert,当然可以。编写“aligned malloc”实际上是一个非常流行的求职面试问题。只需分配足够的空间来说明您的对齐方式,并为指针分配额外的空间。然后将指针隐藏在对齐的内存之前,并编写一个free() 函数来提取此信息并释放“真实”指针。
  • 好吧,不是我不能,而是我必须制作一张全新的桌子并记录里面的东西......虽然我知道怎么做,如果可以的话,我想避免痛苦。 :)
  • 这并不难。但您也可以使用memalign() 和朋友。看看这个答案:stackoverflow.com/questions/3839922/aligned-malloc-in-gcc
  • “应该给你一个运行时错误” 不是必需的行为;结果是未定义的并且依赖于实现。在某些情况下,它只会通过添加无效块来破坏堆,直到发生后续内存分配,当 sh*t 发生时,您可能不会注意到!
【解决方案2】:

唯一可以传递给free 的东西是从malloc(或calloc、realloc 等)返回给您的指针,或者为NULL。

我猜你问是因为你有一些函数可以执行 malloc,并且你想弄乱数据块,然后在完成后摆脱它,你不想为保留原始指针的副本而烦恼。那样不行。

【讨论】:

  • 哈哈 不是我不想打扰,而是在我的情况下做到这一点并不容易。但是谢谢你的回答。 :)
  • 怎么不容易呢?您是否正在调用一些 API 函数,而该函数不会将 malloced 指针返回给您?如果它专门隐藏它,那么您应该将它留给 API 函数来进行内存管理。小心,因为双重释放错误非常烦人,因为你必须弄清楚是谁在你之前释放了,以及为什么。
  • 哈哈哈不,我正在尝试在 NTDLL 的RtlAllocateHeap 之上实现一个对齐的 malloc,所以我可以将它传递给另一个库。我可以创建一个新表来跟踪所有内容,但是我不得不担心线程等问题,事情会很痛苦。
  • @Lambert - IOW,你不想打扰。不要为此感到羞耻。避免不必要的工作的愿望对于软件开发人员来说是一种良好的品质。特别是如果您愿意提前完成工作以实现该目标。只是不要走极端。
  • @Lambert,不要做桌子。只需在对齐的 malloc 实现中的内存块中添加一个标头即可。
【解决方案3】:

从您添加到现有答案的 cmets 来看,您似乎问错了问题。如果你需要内存对齐,你为什么不问这个问题呢?询问根本问题,而不是询问您认为的解决方案!

所以如果你不介意我会回答你应该问的问题:

_aligned_malloc() 在 Win32 中支持对齐内存分配。它更接近于 POSIX memalign()

如果您需要对齐分配的实现,实现起来相当简单:

void* aligned_malloc( size_t size, size_t alignment )
{
    void* unaligned = malloc( size + alignment ) ;
    void* aligned = (void*)(((intptr_t)unaligned + alignment) & ~(alignment - 1));
    void** free_rec_ptr = ((void**)aligned - 1) ;
    *free_rec_ptr = unaligned ;

    return aligned ;
}

void aligned_free( void* block )
{
    void** free_rec_ptr = ((void**)block - 1) ;
    free( *free_rec_ptr ) ;
}

alignment 参数必须是 2 的幂。

【讨论】:

  • @Clifford:谢谢你的回答,但不幸的是,我已经知道_aligned_malloc——它只是不存在于我唯一的库 NTDLL.dll 中(malloc 也不存在) m 链接到,我只是想知道我是否需要费心费力地跟踪我传递给其他库的指针对齐的整个麻烦,如果我不需要的话。所以不,我并没有避免询问根本原因,我真的确实想问这个问题。
  • @Lambert:它是 MSVCRT 库的一部分,通常是隐式链接的。由于 malloc()/free() 也在该库中,您必须 可以访问它。你用的是什么编译器?
  • @Clifford:出于各种原因,我特意尝试 not 链接到 MSVCRT —— 所以根据定义,该功能不可用。这不是编译器问题,这是我故意做的。
  • @Lambert:你说得不对:如果你可以调用 free(),你已经链接了 MSVCRT!我询问编译器的原因是因为 MSDN 仅记录 _aligned_malloc() 用于 VC++ 2003 及更高版本。我不确定它在早期版本中是否可用。您最好回答调查性问题,而不是假设问题无关紧要。
  • @Clifford:我说得完全有道理——你的错误假设我实际上是在打电话给free()。我为调用者提供 free(),我正在包装RtlFreeHeap()。现在这有意义吗?另外,我知道我没有链接到 MSVCRT,因为我已经反汇编了我的可执行文件。所以当我说我没有链接到它时,我不是在开玩笑,我是认真的。 :)
【解决方案4】:

FWIW,我上次研究 C 运行时库如何与 malloc 和 free 一起工作时,malloc 给你的块实际上在相对于它给你的指针的负偏移处有一些额外的词.这些说的是块有多大,以及其他东西。 free 依靠能够找到这些东西。不知道这是否能说明问题。

【讨论】:

  • 这正是我最终所做的,只是它因不同的对齐方式而变得更加复杂。不过,感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2013-02-15
相关资源
最近更新 更多