我在代码库中发现了经典的新/删除不匹配错误,如下所示:
char *foo = new char[10];
// do something
delete foo; // instead of delete[] foo;
这有多严重?它是否会导致内存泄漏或错误?有什么后果。我们有一些内存问题,但这似乎不足以解释我们所有的症状(堆损坏等)
编辑:为清晰起见的额外问题
它只是释放数组的第一个成员吗?或
是否会使系统失去对阵列的跟踪?或
腐败的记忆是某种方式?
答案 0 :(得分:17)
这是未定义的行为严重(它可能会起作用,它可能会崩溃,它可能会做其他事情)。
答案 1 :(得分:9)
乍一看,调用delete
而不是delete[]
应该不是很糟糕:你破坏第一个对象并引发一些内存泄漏。
但是:然后,delete
(或delete[]
)调用free
来释放内存。并且free
需要其最初分配的地址,以正确释放内存。或者,问题是,当new
返回malloc分配的原始地址时,new[]
会返回不同的地址。
在new[]
返回的地址上自由调用会引发崩溃(它会混乱地释放内存)。
请参阅这些非常有用的链接以便更好地理解:
http://blogs.msdn.com/b/oldnewthing/archive/2004/02/03/66660.aspx#66782
从这些文章中可以明显看出,为什么调用delete[]
而不是删除也是一个非常糟糕的主意。
所以,回答:是的,这是一个非常严重的错误。它破坏了内存(仅在调用第一个对象的析构函数之后)。
答案 2 :(得分:1)
很严重。使用 new[]
,实现通常将分配的数组元素数量存储在某处,因为它们需要知道 delete[]
会破坏多少个数组元素。
将单个对象的分配和释放与 new
/delete
和 new[]
/delete
进行比较:https://godbolt.org/z/GYTh7f7Y7。可以清楚地看到,后一种情况下的机器码要复杂得多。请注意,new[]
将元素数 (1) 存储到使用 mov QWORD PTR [rax], 1
分配的内存的开头。 delete[]
然后使用 mov rsi, QWORD PTR [rdi-8]
读取这个数字,以便能够迭代元素并调用它们的析构函数。
普通 new
不存储此数字,因此,当您将 new
与 delete[]
一起使用时,delete[]
将读取一些未指定的数字并将析构函数应用于不可预测的内存.这会造成严重的漏洞问题。
相反的new[]
加delete
的情况也是非常错误的。普通的 new
表达式通常返回一个指针,该指针正好指向由 operator new
(通常调用 malloc
)内部分配的内存块。这个指针在传递给 delete
表达式时,会在内部原样传递给 operator delete
释放函数。
但同样的情况不适用于 new[]
。即,new[]
不返回由 operator new
内部获得的指针。相反,它返回这个增加了 8 个字节的指针(使用 GCC,但我认为 x86_64 上的 Clang 和 MSVC 也是如此)。请参阅链接程序集中的 lea r12, [rax+8]
。在这 8 个字节中,存储了分配的数组元素的数量。因此,如果您将 delete
应用到您使用 new[]
获得的内容,delete
将传递给 operator delete
一个尚未使用 operator new
分配的指针,因为它不会从中减去那 8 个字节。这最终可能会导致一些类似堆损坏。