如何检查使用 free() 和 new [] 的结果
进程因 SIGSEV 崩溃,并且回溯表明内存损坏。 Valgrind 报告表明存在一些“不匹配的空闲”,即使用 new[] 分配的内存正在使用 free() 释放。
我发现以下来自 cert.org 的信息
另一个潜在的问题是,当将一个指针传递给用operator new分配的数组时,操作符delete()可能会在操作符delete()调用free()时发生这种情况(这在许多实现中很常见,尽管不是这样) C++ 标准要求),传递给 free() 的指针不是通过调用 malloc() 返回的指针。这是因为当由operator new调用时malloc()返回的前四个字节通常用于存储数组的大小(同样,标准没有指定,但很常见),因此operator new返回的指针实际上指向到距 malloc() 返回的指针四个字节的地址。因此,free() 将读取错误的大小来释放,这可能会导致堆内存损坏问题。
问题是,如何证明 free() 正在释放错误的大小?任何人都可以建议如何验证这是否发生在我的环境中,也许使用 gdb 或任何其他工具?
另外,该数组是基本类型 char,因此不存在不调用单独析构函数的问题。
A process is crashing with SIGSEV, and the backtraces indicate memory corruption.
Valgrind report indicates that there are some 'Mismatched free', i.e memory allocated with new[] is being released with free().
I found the following information from cert.org
Another potential problem is that when passing a pointer to an array allocated with operator new to operator delete(), it is possible that when free() is called by operator delete() (as is common in many implementations, although not required by the C++ Standard), the pointer passed to free() is not one that was returned by a call to malloc(). This is because the first four bytes returned by malloc() when called by operator new will typically be used to store the size of the array (again, not specified by the Standard, but common), so the pointer returned by operator new actually points to an address that is four bytes from the pointer returned by malloc(). Consequently, free() will read in the wrong size to deallocate, and this could lead to heap memory corruption problems.
Question is, how can I demonstrate that free() is deallocating wrong size? Can anyone suggest how to verify that this is happening in my environment, maybe with gdb or any other tools?
Also, the array is of basic type char, so there is no question of seperate destructor not being invoked.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您已经运行了一个工具,它告诉您这就是正在发生的事情。然后您为什么要运行另一个工具来验证“这确实是正在发生的事情”?
根据 Valgrind 的说法,您不匹配一些
免费
调用。这就是问题,这就是你需要解决的问题。只要该问题存在,就可能会产生一百万种不同的后果,其中之一就是您引用的文本中所描述的。但是您不需要知道您的程序中实际发生了这百万个后果中的哪一个,因为这些只是症状,您已经知道原因是什么了。
当您不匹配
free
/delete
时,唯一能保证的效果是“发生了一些事情”。那“东西”是什么?没有人能说清楚。除非您故意尝试编写糟糕的软件,否则您应该从源头上解决问题,而您所要求的内容不会对您有所帮助。
You already ran a tool which told you that this is what is happening. Why would you then run another tool to verify that "this is really what is happening"?
You are mismatching some
free
calls according to Valgrind. That is problem, and that is what you need to fix.As long as that problem exists, it might have a million different consequences, one of which is what was described in the text you quoted. But you don't need to know which of this million of consequences is actually happening in your program, because those are just the symptoms, and you already know what the cause is.
The only guaranteed effect when you mismatch
free
/delete
is that "something happens". And what that "something" is? No one can say.Unless you are intentionally trying to write bad software, you should fix the problem at the source, and what you are asking won't help you with that.
这是实现定义的。尽管您可能能够使用特定的编译器/工具链/libc,但您无法一般地“演示”这一点。
我建议您使用 valgrind 来发现此类错误。
可以在 SO Edit 上找到此类工具的更全面列表,
这是包含此类列表的推荐帖子:Linux 中的内存泄漏检查工具出现问题
That is implementation defined. You cannot generically 'demonstrate' that, although you might be able to using a specific compiler/toolchain/libc.
I suggest you use valgrind to spot such errors.
More comprehensive lists of such tools can be found on SO
Edit Here is a recomended post with such a list: Problem with memory leak check tools in Linux
您可以尝试使用 Duma ( http://duma.sourceforge.net/ )。它检测 malloc/free new/delete 不一致性。它还在调用 free/delete 后检查双重释放和修改的内存
You can try using Duma ( http://duma.sourceforge.net/ ). It detects malloc/free new/delete incoherencies. It also checks for double deallocation and modified memory after calling free/delete
对 free() 的调用不会释放错误的大小,无论您传入的指针是用 malloc() (或其任何变体)分配的还是不是。在第一种情况下,它将释放最初分配的数量,而在第二种情况下,它可能会崩溃。
根据实现的不同,SIGSEGV 附带的错误消息可能会告诉您传入的指针无效(或未分配或类似情况)。
The call to
free()
will not deallocate the wrong size, either the pointer you pass in was allocated withmalloc()
(or any variant thereof) or it was not. In the first case it will deallocate as much as was initially allocated, while in the second case it will probably crash.Depending on the implementation the error message that comes with the SIGSEGV will probably tell you that the pointer passed in is invalid (or was not allocated or something alike).
如果这是向其他人解释和“演示”这一点的情况,我建议您在不演示的情况下解释为什么它是危险的。在这种情况下,解释应该足以清楚地向每个人展示陷阱。如果您坚持要演示,您可以使用
malloc
创建一个缓冲区,并使用new []
创建一个缓冲区,并显示保存与一起使用的已分配大小的内存位置的内容>malloc
和new
使用的内容。只需观察差异即可。但话又说回来,正如他所解释的那样,该行为是特定于实现的。If this is a case of explaining and "demonstrating" this to others, I would suggest you explain why it is dangerous without demonstrating. An explanation should be sufficient in this case to clearly show everyone the pitfalls. If you do insist on demonstrating you could create a buffer using
malloc
and one usingnew []
and show the contents of the memory locations that hold the allocated size used withmalloc
and the contents used bynew
. Simply observing the difference. But then again the behaviour is implementation specific as sehe explained.下面是演示该问题的代码示例:
如果您在 Linux 下使用 ltrace 运行该代码,您将看到类似以下内容:
因此,在第二种情况下,被释放的指针与被分配的指针不匹配(因为用户在 B 中声明了析构函数) )。
当然,new[] 和 free 之间的不匹配是未定义的行为,但在实践中并不总是会导致 SIGSEGV。
Here is a code sample that demonstrates the issue:
If you run that with ltrace under Linux you will see something like:
So in the second case the pointer being freed doesn't match the one being allocated (because of the user declared destructor in B).
Of course, a mismatch between new[] and free is undefined behaviour, but it will not always result in SIGSEGVs in practice.