【问题标题】:What does "double free" mean?“双免”是什么意思?
【发布时间】:2026-01-16 18:25:01
【问题描述】:

正如标题所暗示的,我是 C 的新手,很快就会有期中考试。我目前正在修改过去的论文,一个反复出现的主题是双重免费问题。我知道这是在同一内存位置两次调用free() 的过程,但我有几个问题我不是 100% 确定如何回答:

问题一:C语言中double free的结果是什么,为什么会出现这样的问题?

这将导致双重释放:

char* ptr = malloc(sizeof(char));

*ptr = 'a';
free(ptr);
free(ptr);

我对此的回应是它会返回 0x0 内存地址并导致系统不稳定/崩溃。另外,如果我没记错的话,双重释放实际上可以调用malloc 两次,这会导致缓冲区溢出,从而使系统易受攻击。

简要总结这个问题的最佳方式是什么?

问题 2:描述一个特别容易引入 C 语言中的双重免费?

我在想,当你在你周围传递指针时,可能会不小心在一个函数中释放它,然后又在不知不觉中释放它?

再次,总结这一点的“最佳”方式是什么?

【问题讨论】:

  • "...would it return a 0x0 memory address..." - 这是怎么回事? what 会返回 0x0 内存地址吗?函数free 不返回任何内容。
  • 双重免费错误有时可能是极其严重的安全漏洞 - 这是一个示例:awakened1712.github.io/hacking/hacking-whatsapp-gif-rce

标签: c double-free


【解决方案1】:

从技术上讲,C 中的双重释放会导致未定义的行为。这意味着该程序可以完全任意地运行,并且所有关于发生的事情的赌注都没有。这肯定是一件坏事!在实践中,双重释放内存块会破坏内存管理器的状态,这可能会导致现有内存块损坏或未来分配以奇怪的方式失败(例如,相同的内存分配给两个malloc的不同连续调用)。

在各种情况下都可能发生双重释放。一种相当常见的情况是,当多个不同的对象都具有彼此的指针并开始通过调用free 进行清理时。发生这种情况时,如果您不小心,可能会在清理对象时多次free 同一个指针。不过,还有很多其他情况。

希望这会有所帮助!

【讨论】:

  • 我在 C 中发现了一堆未定义的行为,所以我期待着这些方面的东西。由于这个原因,我打算建议单/双链表非常容易受到双重免费的影响,感谢您的回复。
【解决方案2】:

因为 free() 将通过管理存储在每个区域之前的标签中的信息来合并相邻区域。这有点像管理双链表。因此,如果ptr 指向的缓冲区已被攻击字符串覆盖,将很危险,其中可以注入虚假标签。

【讨论】:

    【解决方案3】:

    这个问题已经得到很好的回答,但是由于“重复问题”链接,我添加了一个较晚的答案,该链接询问“如何避免它?”

    在发布的示例代码中添加了一行。

    char* ptr = malloc(sizeof(char));
    
    *ptr = 'a';
    free(ptr);
    ptr = NULL;         // add this
    free(ptr);
    

    函数freeNULL 指针没有任何作用。

    【讨论】:

    • 这仅在只有一个指针指向一块内存的微不足道的情况下才有用。在更常见的情况下,有多个指针指向同一个内存,情况要复杂得多。
    【解决方案4】:

    根据已发布的 C11 标准,在 free 内存位置上调用 free 会导致未定义的行为。它可能导致奇怪的情况,例如即使可用内存也没有分配,堆损坏,相同的内存位置分配给不同的 malloc 等。基本上,它是未定义的,可以是任何东西。

    ANSI C11 标准可以在这里找到。 https://www.iso.org/obp/ui/#iso:std:iso-iec:9899:ed-3:v1:en

    编辑:基于 cmets 已将 NULL 更改为 freed。此外,链接现在指向 ISO/IEC 9899:2011(en)

    【讨论】:

    • 您在哪里找到这些信息? (“在 NULL 指针上调用 free 会导致未定义的行为。”)这是不正确的。
    • "Double free" 和 "free on NULL" 是两个不同的问题。前者是未定义的行为,但后者是无害的无操作。
    • 你确定这是正确的吗?我已经明确表示的 ISO 标准草案在空指针上调用 free 无效。
    • 对不起。我的错。意味着双重释放。对原始答案进行了一些修改。 @templatetypedef 用户名也签出。