new/delete操作符不匹配错误有多严重?

发布于 2025-01-04 22:13:37 字数 311 浏览 1 评论 0原文

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

char *foo = new char[10];

// do something

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

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

编辑:为了清晰起见,有额外的问题
它只是释放数组的第一个成员吗?或
它会使系统失去对阵列的跟踪吗?或
损坏内存有什么办法吗?

I have discovered the classic new/delete mismatch error in our codebase as follows:

char *foo = new char[10];

// do something

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

Just how serious is this? Does it cause a memory leak or error? What are the consequences. We have some memory issues, but this doesn't seem serious enough to explain all our symptoms (heap corruption etc)

EDIT: extra questions for clarity
Does it just free the first member of the array? or
Does it make the system lose track of the array? or
Corrupt memory is some way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

橘味果▽酱 2025-01-11 22:13:37

这是严重的未定义行为(它可以工作,它可以崩溃,它可以做其他事情)。

It's undefined behavior serious (it could work, it could crash, it could do something else).

将军与妓 2025-01-11 22:13:37

乍一看,调用 delete 而不是 delete[] 应该不是很糟糕:您销毁了第一个对象并引发了一些内存泄漏。

但是:然后,delete(或delete[])调用free来释放内存。并且 free 需要其最初分配的地址,才能正确释放内存。或者,问题是,当 new 返回由 malloc 分配的原始地址时,new[] 返回不同的地址

new[] 返回的地址上调用 free 会引发崩溃(它会混乱地释放内存)。

请参阅这些非常有指导性的链接以更好地理解:

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< /a>

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

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

At the first sight, calling delete instead of delete[] should not be very bad: you destroy the first object and you provoke some memory leak.

BUT: then, delete (or delete[]) calls free to free the memory. And free needs its originally allocated address, to free the memory correctly. Or, the thing is, while new returns the original adress allocated by malloc, new[] returns a different address.

Calling free on the address returned by new[] provokes a crash (it frees memory chaotically).

See these very instructive links for better understanding:

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

From these articles it is also obvious why calling delete[] instead of delete is also a very bad idea.

So, to answer: yes, it is a very very serious error. It corrupts memory (after calling the destructor of the first object only).

风和你 2025-01-11 22:13:37

这是非常严重的。对于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 表达式通常返回一个指针,该指针精确指向由 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 个字节。这最终可能会导致一些诸如堆损坏之类的问题。

It is very serious. With new[], implementations typically store somewhere the number of allocated array elements, since they need to know how many of them will be destructed by delete[].

Compare allocation and deallocations of a single object with new/delete and new[]/delete: https://godbolt.org/z/GYTh7f7Y7. You can clearly see that the machine code in the latter case is much more complicated. Note that new[] stores the number of elements (1) to the beginning of the allocated memory with mov QWORD PTR [rax], 1. delete[] then reads this number with mov rsi, QWORD PTR [rdi-8] to be able to iterate over elements and call their destructors.

Ordinary new does not store this number, so consequently, when you use new together with delete[], delete[] will read some unspecified number and apply destructors to unpredicted memory. This can create serious vulnerability problems.

The opposite new[] plus delete case is also very wrong. Ordinary new expression typically returns a pointer that points exactly to the memory block internally allocated by operator new (which usually calls malloc). This pointer when passed to delete expression is then internally passed as-is to the operator delete deallocation function.

But the same does not hold for new[]. Namely, new[] does not return a pointer obtained internally by operator new. Instead, it returns this pointer increased by 8 bytes (with GCC, but I think the same holds for Clang and MSVC on x86_64). See that lea r12, [rax+8] in the linked assembly. In these 8 bytes, the number of allocated array elements is stored. Consequently, if you apply delete to what you obtained with new[], delete will pass to operator delete a pointer that has not been allocated with operator new, because it will not subtract those 8 bytes from it. This will finally likely cause some like heap corruption.

南七夏 2025-01-11 22:13:37

正如其他答案中所指出的,不匹配的 new []delete 可能会崩溃。

然而,如果被new'd或delete'd的类型没有析构函数,那么至少对于GCC、MSVC和Clang来说,使用operator new/delete方法的默认实现,不会有任何后果。这包括基本类型 int、char 等。

不匹配的 new[]delete (或 newdelete[] )对于复杂的类可能会崩溃。

这是因为如果编译器不需要调用析构函数,则不会在数据之前插入元素计数。

修改 @Daniel Langr 的 godbolt 页面,请注意如果类没有析构函数,则 new/deletenew[]/delete[] 之间的有限差异:
https://godbolt.org/z/hW4f3Ge13
(与它确实有析构函数时相比:https://godbolt.org/z/GYTh7f7Y7
唯一的区别是对 operator newoperator new[] 的调用,以及类似的删除操作。默认情况下,这些函数具有相同的实现。

这对于了解您是否试图找出堆损坏的原因很有用。

As pointed out in other answers, mismatched new [] vs delete will potentially crash.

However if the type being new'd or delete'd does not have a destructor, then at least with GCC, MSVC and Clang, with the default implementation of operator new/delete methods, there will be no consequence. This includes basic types int, char etc.

Mismatched new[] vs delete (or new vs delete[]) for complex classes will likely crash.

This is because the compiler does not insert the element count before the data if it does not need to call the destructor.

Modifying @Daniel Langr's godbolt page, note the limited difference between new/delete and new[]/delete[] if the class does not have a destructor:
https://godbolt.org/z/hW4f3Ge13
(compared to when it does have a destructor: https://godbolt.org/z/GYTh7f7Y7)
The only difference is the calls to operator new vs operator new[] and similar for delete. These functions by default have the same implementation.

This can be useful to know if you're trying to attribute the cause of heap corruption.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文