double free()有哪些问题?

5

我在网络上和我的高级C课程中看到了很多错误的代码(例如下面的代码)。虽然我知道这是不好的编码实践,但除了浪费CPU周期之外,我很难理解它有什么坏处。据我目前的了解,如果指针分配未位于“malloc表”中(缺乏更好的词汇),通常会被忽略。我希望这里的某个人能够更好地解释为什么这样做是不好的,并且(除了这是一个愚蠢的事情)其后果是什么。

char* ptr = malloc(1);

...

free(ptr);
...
free(ptr);

7
这是一种未定义行为。这意味着你的程序不能被认为“有效”。这里没有太多需要理解的内容。 - juanchopanza
1
如果您想要特定的错误行为而不是一般的未定义行为:如果第一次“free”后另一个“malloc”调用返回相同的地址,该怎么办? - Mike Seymour
2
@Brandon:我指的是另一个独立的调用malloc的代码,由一些不相关的管理其自己内存的代码。如果它恰好获得与此相同的地址,则会被错误的第二个free释放,留下悬空指针。 - Mike Seymour
2
指针分配不在“malloc表”中(缺乏更好的词),通常会被忽略。这个陈述是没有意义的。请定义“通常”。 - n. m.
2
@n.m. 我也写了同样的东西,但最终决定不深入讨论,因为那是一堆词的混合。什么是“指针分配”?这样的东西如何“位于malloc表中”,而且那是什么鬼?我猜OP的意思是空闲列表,但那里面包含的是块,而不是指针。忽略“指针分配”是什么意思,这样的事情该如何实现? - Jim Balter
显示剩余3条评论
4个回答

14

考虑您的示例,在 free(ptr) 之后执行以下操作:

char* ptr = malloc(1);

free(ptr) // <-- This will delete the pointer
ptr2 = malloc(1) // <-- now you request again

现在malloc就是它本来的样子,可以返回和ptr相同的指针,如果它确实这样做了,现在你就可以执行以下操作:

// if you call me again and if ptr2 == ptr oops!
free(ptr)

-- 你释放了ptr2导致出现了意外的行为,有大量的崩溃、痛苦和数小时的调试。


2
这非常有用,我理解你的担忧。但我仍想知道为什么 ptr 会有一个值?第二次调用 free(ptr) 时,此时 ptr 的值是什么? 我指的是我们没有将其设置为 NULL 的示例...所以,在 free(ptr) 之后,ptr 是什么?我有点新手。我还在缺少一些细节(或者说_基础知识_),我想。 - harperville
1
@harperville 在第二次free调用时,ptr的值将与第一次free调用时相同。在调用free后,ptr的值不会改变。 - nishanthshanmugham

7
这不仅仅浪费CPU时间。双重free()未定义行为,这意味着程序可以以任意的方式运行。程序可能完美地工作,或在测试中崩溃,或通过所有测试然后在客户面前崩溃,或可能会损坏某些数据,或可能会发射核弹等。所有这些都是未定义行为的有效表现。

7
C11标准第7.22.3.3节指出:
[...] 否则,如果参数与先前由内存管理函数返回的指针不匹配,或者空间已经被调用freerealloc释放,则行为是未定义的。

5
一个好的建议:在释放指针后将其置为空。在您的情况下,由于计算机可以分配由ptr指向的内存,也可能不分配此块内存,或者在碎片整理期间将此块内存添加到其他内存块中,因此您存在未定义行为。
另一方面,free(NULL)是被定义的,并且不会执行任何操作。
char* ptr = malloc(1);
...
free(ptr);
ptr = NULL;
...
free(ptr);

啊,我不知道free(NULL)被定义了。我喜欢那个解释。 - audiFanatic
6
奇怪的是这个作为被接受的答案。无论是否将已释放指针设置为 NULL 是一个好习惯,但这与问题无关,而且 free(NULL) 也不相关。 - Jim Balter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接