新/删除操作符不匹配错误有多严重?

时间:2012-02-11 08:00:53

标签: c++ new-operator delete-operator

我在代码库中发现了经典的新/删除不匹配错误,如下所示:

char *foo = new char[10];

// do something

delete foo; // instead of delete[] foo;

这有多严重?它是否会导致内存泄漏或错误?有什么后果。我们有一些内存问题,但这似乎不足以解释我们所有的症状(堆损坏等)

编辑:为清晰起见的额外问题 它只是释放数组的第一个成员吗?或
是否会使系统失去对阵列的跟踪?或
腐败的记忆是某种方式?

3 个答案:

答案 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

http://web.archive.org/web/20080703153358/http://taossa.com/index.php/2007/01/03/attacking-delete-and-delete-in-c

从这些文章中可以明显看出,为什么调用delete[]而不是删除也是一个非常糟糕的主意。

所以,回答:是的,这是一个非常严重的错误。它破坏了内存(仅在调用第一个对象的析构函数之后)。

答案 2 :(得分:1)

很严重。使用 new[],实现通常将分配的数组元素数量存储在某处,因为它们需要知道 delete[] 会破坏多少个数组元素。

将单个对象的分配和释放与 new/deletenew[]/delete 进行比较:https://godbolt.org/z/GYTh7f7Y7。可以清楚地看到,后一种情况下的机器码要复杂得多。请注意,new[] 将元素数 (1) 存储到使用 mov QWORD PTR [rax], 1 分配的内存的开头。 delete[] 然后使用 mov rsi, QWORD PTR [rdi-8] 读取这个数字,以便能够迭代元素并调用它们的析构函数。

普通 new 不存储此数字,因此,当您将 newdelete[] 一起使用时,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 个字节。这最终可能会导致一些类似堆损坏。