2012-01-29 48 views
2

当试图释放相同的mableced堆两次或未分配的堆时,分别发生致命错误“double free or corruption(fasttop)”和“invalid pointer”,因此运行程序立即中止。不正确释放堆中止C程序

尽管这样做在逻辑上不合适,但在我看来,对于正在运行的程序实际上没有致命的伤害。为什么它被迫立即中止?

+0

我宁愿用这种方式来默默无视。如果你正在双重释放内存然后显然出了问题,并且很高兴知道它是什么 – Dan 2012-01-29 21:15:58

+0

如果C支持异常处理,我可能更喜欢抛出一个检查的异常,这反过来程序本身需要正确处理。 – sof 2012-01-29 21:22:16

+0

@sof,看着这个问题和你对No的答案的评论,在我看来,当你说“未分配的堆”时,你的意思是一个NULL指针 - 即做相当于free(NULL);或'免费(0);'。是这种情况还是你的意思是'未分配堆'的不同之处? – AAT 2012-01-29 21:54:19

回答

3

立即中止可最大限度地提高发现错误并修复错误的几率。
这种错误看起来似乎无害,但只需轻微更改代码,它们就是灾难性的,而且很难调试。

考虑一下 - 你(A)释放指针p,并在一段时间后再次释放它。同时,一些代码(B)做了malloc,碰巧得到了相同的地址。现在第二个免费版似乎可以,因为分配了p。现在另一个人(C)做了malloc,并再次获取相同的地址(很可能,如果它的大小相同)。当C写入p时,他正在破坏B的数据。谁应该责怪? A.祝你好运调试。

所以双倍免费应该在年轻的时候抓住,不能容忍。

1

标准中的任何内容都不会保证崩溃。做双免费是未定义的行为。它会在某些情况下被运行时库捕获,这会通过立即杀死你,从而避免进一步损害你的内存管理错误。

但是你不能依赖那个。如果不注意,可能会发生各种形式的沉默,令人讨厌的堆损坏,并且在发生这种情况时您将会吃掉您的数据 - 并不好。

运行时可以为您提供安全网,但不会依赖它。如果你在其中之一上绊倒,调试它直到它被真正修复。

+0

我想从stdlib中寻找is_allocated(堆)... – sof 2012-01-29 21:59:13

1

如果你有足够的理由允许双重释放一个指针,比我建议你看看使用setjmp和longjmp实现C异常处理,但从经验来看,我更倾向于消除这样的逻辑。

+0

Thx指向'setjmp'和'longjmp'。 – sof 2012-01-29 22:12:31

+1

没有办法允许它。一旦发生双重空闲,你就调用了未定义的行为,整个程序状态是未定义的。 – 2012-01-29 23:59:23

0

考虑下面的代码:

int * i = (int *)malloc(2 * sizeof(int)); 
    free(i); 
    int * j = (int *)malloc(sizeof(int)); 
    int * k = (int *)malloc(sizeof(int)); 
    free(i); 

现在,假设j持有相同的地址i,和K持有i + 1。当第二个free()被命令时,你声明整个块(j,k)是免费的,而不仅仅是jfree()实际上知道它有多少内存要声明免费)。这种行为是可以理解的,因为即使你使用j,你也可以在代码的其余部分使用k

+0

调用'free(heap)'后,我们按照惯例设置'heap = NULL'。再次调用'free(heap)'不会产生这样的副作用。 – sof 2012-01-29 21:45:52

0

虽然这样做在逻辑上不合适,但在我看来,对于正在运行的程序实际上没有致命的伤害。

谬误警报。考虑以下几点:

  • 线程1分配地址42并写'xyzzy'给它。
  • 线程1释放地址42.
  • 线程2分配地址42并向其写入'plugh'。
  • 线程1错误地再次释放地址42。
  • 线程3分配地址42并写入'twisty-little-passage'给它。

现在线程2和3 认为他们自己的内存。这是我的小儿子和女儿都认为他们拥有那个最新的玩具购买的话,不,这不是有好下场的:-)

记住是关于可持续,那些“线程”提到不必须是多线程环境下的执行线程,这只是我用来显示内存所有权的区别。

一个好的成语对错误处理:

  • ,如果你可以完全解决这个问题,这样做。
  • 如果您无法完全修复,请尽快停止以最大限度地减少损坏。