C++ 堆损坏:原因可能是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1504251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Heap corruption: What could the cause be?
提问by Satbir
I am investigating a crash due to heap corruption. As this issue is non-trivial and involves analyzing the stack and dump results, I have decided to do a code review of files related to the crash.
我正在调查由于堆损坏导致的崩溃。由于这个问题很重要并且涉及分析堆栈和转储结果,因此我决定对与崩溃相关的文件进行代码。
To be frank, I don't have in-depth knowledge of when the heap could be corrupted.
坦率地说,我对堆何时会损坏没有深入的了解。
I would appreciate if you could suggest scenarios which could lead to heap corruption.
如果您能提出可能导致堆损坏的方案,我将不胜感激。
Platform: Windows XP
平台:Windows XP
Language: C++
语言:C++
Compiler: VC6
编译器:VC6
回答by cwap
Common scenarios include:
常见场景包括:
- Writing outside the allocated space of an array (
char *stuff = new char[10]; stuff[10] = 3;) - Casting to the wrong type
- Uninitialized pointers
- Typo error for -> and .
- Typo error when using * and & (or multiple of either)
- 在数组分配的空间之外写入 (
char *stuff = new char[10]; stuff[10] = 3;) - 投射到错误的类型
- 未初始化的指针
- -> 和 .
- 使用 * 和 & (或其中之一的倍数)时出现拼写错误
[EDIT] From the comments, a few more:
[编辑] 从评论中,还有一些:
- Mixing new [] and new with delete [] and delete
- Missing or incorrect copy-constructors
- Pointer pointing to garbage
- Calling delete multiple times on the same data
- Polymorphic baseclasses without virtual destructors
- 将 new [] 和 new 与 delete [] 和 delete 混合使用
- 缺少或不正确的复制构造函数
- 指向垃圾的指针
- 对同一数据多次调用 delete
- 没有虚拟析构函数的多态基类
回答by Coincoin
Welcome to hell. There is no easy solution so I will only provide some pointers.
欢迎来到地狱。没有简单的解决方案,所以我只会提供一些提示。
Try to reproduce the bug in a debug environement. Debuggers can pad your heap allocations with bound checks and will tell you if you wrote in those bound checks. Also, it will consistently allocate memory using the same virtual addresses, making reproductibility easier.
尝试在调试环境中重现该错误。调试器可以用绑定检查填充您的堆分配,并会告诉您是否在这些绑定检查中写入。此外,它将始终使用相同的虚拟地址分配内存,从而更容易重现。
In that case, you can try an analyser tool such as Purify. They will detect pretty much anything nasty that your code is doing but will also run VERY slowly. Such a tool will detect out of bound memory access, freed memory access, trying to free twice the same block, using the wrong allocator/deallocators, etc... Those are all kind of conditions that can stay latent for very long and only crash at the most inopportune moment.
在这种情况下,您可以尝试使用分析工具,例如 Purify。他们几乎会检测到您的代码正在做的任何令人讨厌的事情,但也会运行得很慢。这样的工具将检测越界内存访问、释放内存访问、尝试释放两次相同的块、使用错误的分配器/释放器等......这些都是可以潜伏很长时间并且只会崩溃的条件在最不合时宜的时候。
回答by Komat
You can look at the sample chapter from the Advanced Windows Debugging bookwhich provides various examples of heap corruption.
您可以查看Advanced Windows Debugging 书中的示例章节,其中提供了堆损坏的各种示例。
EDIT: If you are using stl containers which might move elements during changes (i.e. vector, deque), ensure that you are not keeping references into such elements across operations which might changes it.
编辑:如果您使用的 stl 容器可能会在更改期间移动元素(即向量、双端队列),请确保您不会在可能更改元素的操作之间保留对此类元素的引用。
回答by David Thornley
There are products that will observe the memory allocations and deallocations, and produce a report on anomalies. Last I used one, they weren't cheap, but I don't know what the situation is right now. However, finding stuff for VC++ 6 might be a problem.
有些产品会观察内存分配和释放,并生成异常报告。上次我用了一个,它们不便宜,但我不知道现在的情况。然而,寻找 VC++ 6 的东西可能是一个问题。
Remember that you're liable to be getting heap corruption a lot more often than you're going to crash, so be attentive to the problem reports, and fix all heap corruption.
请记住,与崩溃相比,您可能会更频繁地发生堆损坏,因此请注意问题报告,并修复所有堆损坏。
I'd suggest using std::tr1::smart_ptr<>instead of raw pointers everywhere, but I'm not sure VC++ 6 is going to support that.
我建议std::tr1::smart_ptr<>在任何地方使用而不是原始指针,但我不确定 VC++ 6 是否会支持它。
Why are you still on VC++ 6? Would it be practical to upgrade? The tools are better with the more recent versions, and they fully support smart pointers.
为什么你还在使用 VC++ 6?升级是否实用?这些工具在更新的版本中更好,并且它们完全支持智能指针。
回答by Richard Corden
Check out the answers to thisrelated question.
查看此相关问题的答案。
The answerI suggested provides a technique which may be able to get you back to the code that is actually causing the heap corruption. My answer describes the technique using gdbbut I'm sure you must be able to do something similar on windows.
我建议的答案提供了一种技术,可以让您回到实际导致堆损坏的代码。我的回答描述了使用的技术, gdb但我相信您必须能够在 Windows 上做类似的事情。
The principle at least should be the same.
至少原理应该是一样的。
回答by jalf
Every time you do something which isn't defined in the language standard, it is undefined behavior, and one of the ways in which it might manifest itself is through heap corruption. There are about three million ways to do this in C++, so it's really impossible to say.
每次你做一些语言标准中没有定义的事情时,它都是未定义的行为,它可能表现出来的一种方式是通过堆损坏。在 C++ 中大约有 300 万种方法可以做到这一点,所以真的无法说。
A few common cases are double-freeing dynamically allocated memory, or writing outside the bounds of an array. Or writing to an uninitialized pointer.
一些常见的情况是双重释放动态分配的内存,或写入数组边界之外。或写入未初始化的指针。
Recent versions of Microsoft's compiler add an /analyze compiler switch which performs a bunch of static analysis to catch such errors. On Linux, valgrind is an obvious choice.
Microsoft 编译器的最新版本添加了一个 /analyze 编译器开关,该开关执行一堆静态分析以捕获此类错误。在 Linux 上,valgrind 是一个显而易见的选择。
Of course, you are using VC6 which has been unsupported for years, and which has a number of known bugs, resulting in invalid code being generated.
当然,您使用的 VC6 多年来一直不受支持,并且存在许多已知错误,从而导致生成无效代码。
If possible, you should upgrade to a proper compiler.
如果可能,您应该升级到合适的编译器。
回答by Alan
An additional debugging tip is to look at the values that are being written to the wrong place using the raw memory view. Is it writing zeros... strings... some other recognizable number pattern? If you can see the corrupted memory at some point after the error occurs, that can provide a hint of the code that caused it.
另一个调试技巧是使用原始内存视图查看写入错误位置的值。是写零...字符串...其他一些可识别的数字模式?如果您可以在错误发生后的某个时刻看到损坏的内存,则可以提供导致错误的代码的提示。
Also always set pointers to null after deleting them even in destructors. Sometimes unexpected things can be triggered during a destructor chain in a base class than cause an access to a partially deleted sub-class.
即使在析构函数中删除它们后,也始终将指针设置为空。有时,在基类中的析构函数链期间可能会触发意外事件,从而导致访问部分删除的子类。
回答by Red
During freeing heap memory, first child memory block need to be deleted and then parant memory block otherwise the child momory block would be leaked parmanently which causes the crash after running the tool millions of times.. ex:
在释放堆内存时,需要先删除子内存块,然后删除子内存块,否则子内存块会被永久泄漏,导致运行该工具数百万次后崩溃..例如:
constQ= new double* [num_equations];
for(int i=0;i<num_equations;i++)
{
constQ[i]=new double[num_equations];
for(int j=0;j<num_equations;j++)
{
constQ[i][j]=0.0;
}
.
.
.
//Deleting/Freeing memory block
//Here the below only parent memory block is deleted, the child memory block is leaked.
if(constQ!=NULL)
{
delete[] constQ;
constQ=NULL
}
//Correct way of deleting heap memory..First delet child block memory and then Parent block
if(constQ!=NULL)
{
for(int i=0; i <num_equations;i++)
{
delete[] constQ[i];
delete[] constQ;
constQ=NULL
}
回答by RED SOFT ADAIR
Its a common mistake to free() or delete allocated memory more than one. It may help to insert something like *var = NULL after such calls, and to check for != NULL when calling free. Although in C++ its legal to call deletewith a NULL variable, calling C - free() will fail.
free() 或删除多个分配的内存是一个常见的错误。在此类调用之后插入类似 *var = NULL 之类的内容可能会有所帮助,并在调用 free 时检查 != NULL。尽管在 C++ 中使用 NULL 变量调用delete是合法的,但调用 C - free() 将失败。
Also a common problem is to confuse delete and delete [].
另外一个常见的问题是混淆了删除和删除[]。
Variables allocated with newmust be released with delete.
用new分配的变量必须用delete释放。
Array allocated with new []must be released with delete[].
用new []分配的数组必须用delete[]释放。
Also make sure not to mix C- style memory management (malloc, calloc, free) with C++ style memory management (new/delete). In legacy code often both are mixed, but things allocated with the one can not be freed with the other.
还要确保不要将 C 风格的内存管理(malloc、calloc、free)与 C++ 风格的内存管理(新建/删除)混合在一起。在遗留代码中,两者通常是混合的,但是用一个分配的东西不能用另一个释放。
All of these errors will usually not be recognized by a compiler.
编译器通常无法识别所有这些错误。
回答by Paul Nathan
If you have access to a *nix machine, you can use Valgrind.
如果您可以访问 *nix 机器,则可以使用 Valgrind。

