visual-studio Visual Studio - 如何找到堆损坏错误的来源

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2470131/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 11:39:57  来源:igfitidea点击:

Visual Studio - how to find source of heap corruption errors

visual-studiodebuggingheap-memory

提问by Danne

I wonder if there is a good way to find the source code that causes a heap corruption error, given the memory address of the data that was written 'outside' the allocated heap block in Visual Studio;

考虑到在 Visual Studio 中分配的堆块“外部”写入的数据的内存地址,我想知道是否有一种好方法可以找到导致堆损坏错误的源代码;

Dedicated (0008) free list element 26F7F670 is wrong size (dead)

专用 (0008) 空闲列表元素 26F7F670 大小错误(已死)

(Trying to write down some notes on how to find memory errors)

(尝试写下一些关于如何查找内存错误的笔记)

Thanks in advance!

提前致谢!

回答by Andreas Brinck

Begin with installing windbg:

从安装windbg开始:

http://www.microsoft.com/whdc/Devtools/Debugging/default.mspx

http://www.microsoft.com/whdc/Devtools/Debugging/default.mspx

Then turn on the pageheap like this:

然后像这样打开pageheap:

gflags.exe –p /enable yourexecutable.exe /full

This will insert a non writable page after each heap allocation.

这将在每次堆分配后插入一个不可写的页面。

After this launch the executable from inside windbg, any writes outside the heap will now be caught by this debugger. To turn of the pageheap afterwards use this:

在从 Windbg 内部启动可执行文件后,堆外的任何写入现在都将被此调试器捕获。之后要关闭页面堆,请使用以下命令:

gflags.exe -p /disable yourexecutable.exe

More info on how to use the pageheap here.

有关如何在此处使用 pageheap 的更多信息。

回答by Merav Kochavi

For Window 10 you could enable the PageHeap option in the GFlags Tool, this tool is included as part of the Debugging Tools for Windows.

对于 Window 10,您可以启用GFlags 工具中PageHeap 选项,该工具作为Windows 调试工具的一部分包含在内。

The Page Heap options in GFlags lets you select standard heap verification or full-page heap verification. Beware, the full heap verification uses a full page of memory for each allocation so it can cause system memory shortages.

GFlags 中的页堆选项允许您选择标准堆验证或整页堆验证。请注意,全堆验证对每次分配使用一整页内存,因此可能会导致系统内存不足。

To enable the Page Heap in GFlags:

在 GFlags 中启用页堆:

?To enable standard page heap verification, the standard version will write a pattern at the end of each heap allocation and then examine the pattern when the allocations are freed.

?为了启用标准页堆验证,标准版本将在每次堆分配结束时写入一个模式,然后在分配被释放时检查该模式。

To verify all processes use:

要验证所有进程,请使用:

gflags /r +hpa

gflags /k +hpa

gflags /r +hpa

gflags /k +hpa

for a single process use:

对于单个进程使用:

gflags /p /enable ImageFileName

gflags /p /启用图像文件名

?To enable full page heap verificationfor one process, this option places an inaccessible page at the end of each allocation so that the program stops immediately if it tries to accesses memory beyond the allocation, this should only be used on a single process due to the heavy memory consumption.

?要为一个进程启用整页堆验证,此选项会在每次分配的末尾放置一个不可访问的页面,以便程序在尝试访问超出分配范围的内存时立即停止,这应该仅用于单个进程,因为大量的内存消耗。

gflags /i ImageFileName +hpa

gflags /p /enable ImageFileName /full

gflags /i ImageFileName +hpa

gflags /p /enable ImageFileName /full

The two commands above are interchangeable.

上面的两个命令是可以互换的。

Note: All page heap settings mentioned above are system wide settings stored in the registry (except /k) and remain effective until you change them. The /k setting is a Kernel flag setting are set for this session and will be lost when Windows shuts down

注意:上面提到的所有页堆设置都是存储在注册表中的系统范围设置(/k 除外),并且在您更改它们之前一直有效。/k 设置是为此会话设置的内核标志设置,并且会在 Windows 关闭时丢失

Another helpful tool is the Application Verifier, but this is not part of the Debugging Tools for Windows, rather it is included in the Windows Software Development Kit (SDK).

另一个有用的工具是Application Verifier,但这不是 Windows 调试工具的一部分,而是包含在Windows 软件开发工具包 (SDK) 中

回答by Smithy

Maybe you can try Microsoft's Application Verifier. It solved a similar problem for me once,by turning on extra checks on heap operations. In my opinion, the randomness of corrupted address is because the heap can be 'subtly' damaged, and the problem won't show up until something big happens to the heap (like massive allocation/free).

也许你可以试试微软的应用程序验证器。通过打开堆操作的额外检查,它曾经为我解决了类似的问题。在我看来,损坏地址的随机性是因为堆可能被“微妙地”损坏,并且直到堆发生重大事件(例如大量分配/释放)才会出现问题。

回答by Timo Geusch

You could set a breakpoint on a write to the memory address. The debugger will then show you the code that writes to the location, but you still need to work out which of the writes are causing the problem.

您可以在写入内存地址时设置断点。调试器随后会向您显示写入该位置的代码,但您仍然需要确定哪些写入导致了问题。

回答by Timo Geusch

It's probably too late but if it compiles with gcc and can run on linux you may use valgrind to find the source of the problem (i don't remember the flags, i only used it once with great success).

这可能为时已晚,但如果它使用 gcc 编译并且可以在 linux 上运行,您可以使用 valgrind 来查找问题的根源(我不记得这些标志,我只使用过一次并取得了巨大成功)。

回答by NoAngel

more info about Gflags and PageHeap(which helped a lot): http://msdn.microsoft.com/en-us/library/windows/hardware/ff549561%28v=vs.85%29.aspx

有关 Gflags 和 PageHeap(帮助很大)的更多信息:http: //msdn.microsoft.com/en-us/library/windows/hardware/ff549561%28v=vs.85%29.aspx

回答by Timores

I am assuming C++ as the language.

我假设 C++ 作为语言。

If the error is reproducible and the corrupted address is always the same, you can put a data breakpoint to stop the program when writing at this address.

如果错误可重现且损坏的地址始终相同,则可以在此地址写入时放置数据断点以停止程序。

回答by Merav Kochavi

Make sure all libraries you are linking to are compiled in the same CLR version as the application you are running - all in Release or all in Debug.

确保您链接到的所有库都在与您正在运行的应用程序相同的 CLR 版本中编译 - 全部在 Release 中或全部在 Debug 中。

When you compile in either Debug and Release you are actually targeting two different versions of the C runtime library. These versions are quite different and they use different strategies for allocating memory and they use different heaps. But the most important thing to know is that they are NOT compatible with one another.

当您在 Debug 和 Release 中进行编译时,您实际上是针对 C 运行时库的两个不同版本。这些版本完全不同,它们使用不同的内存分配策略,并且使用不同的堆。但最重要的是要知道它们彼此不兼容。

The Release C runtime library allocated memory as expected, whereas the Debug will add extra information, such as guard blocks to track buffer overflow and the location that called the allocation function, and in turn it allocates more memory than the Release.

Release C 运行时库按预期分配内存,而 Debug 将添加额外信息,例如跟踪缓冲区溢出的保护块和调用分配函数的位置,然后它分配的内存比 Release 多。

If your are linking your application to a mix of DLLs which were built in Release and Debug, you will most likely end up trying to delete an object in one CLR which was created in another. This means you will be trying to free more or less memory than what was allocated to the object and this can corrupt the heap.

如果您将应用程序链接到在 Release 和 Debug 中构建的混合 DLL,您很可能最终会尝试删除一个 CLR 中的对象,而该对象是在另一个 CLR 中创建的。这意味着您将尝试释放比分配给对象的内存更多或更少的内存,这可能会损坏堆。

You should build your application, as well as attach to libraries which are built under the same configuration, either Release or Debug.

您应该构建您的应用程序,并附加到在相同配置(发布或调试)下构建的库。

This problem can occur especially in modules that are being compiled with different compilers.

尤其是在使用不同编译器编译的模块中,可能会出现此问题。

There is a way to work around, which I will mention but do not recommend. If for some reason you still need to build in different modes, this work around will allows for all memory to be allocated and freed from the same shared heap. The API GetProcessHeap will allow you to access the shared heap throughout the different modules. By using the HeapAlloc & HeapFree you can allocate and free memory in the shared heap. Note: the HeapAlloc and HeapFree should replace all calls to malloc and free in your application.

有一种解决方法,我会提到但不推荐。如果由于某种原因你仍然需要以不同的模式构建,这个变通方法将允许从同一个共享堆分配和释放所有内存。API GetProcessHeap 将允许您访问不同模块中的共享堆。通过使用 HeapAlloc 和 HeapFree,您可以在共享堆中分配和释放内存。注意: HeapAlloc 和 HeapFree 应该替换您的应用程序中对 malloc 和 free 的所有调用。