c++ - 可能的堆损坏(win 32, native c++)

标签 c++ debugging memory winapi

我正在使用单线程 native C++ 应用程序。 有一个很难重现的错误,我无法在本地重现。 我在发布的可执行文件中启用了整页堆和调试信息,并从客户端获取了转储(它必须使用该应用程序很多天才能获得错误)。

客户端报告的内容:应用程序挂起并且永远无法恢复。它必须从任务管理器中杀死。 我从转储中看到:应用程序陷入无限循环。

循环来自遍历一个已经变成循环的双链表。存在内存损坏的迹象,因为许多数据成员具有奇怪的值,例如没有匹配的枚举数、小于 0000FFFF 的值或链表本身的大小被报告为 3 亿以上,这是不正常的。

我可以从转储中获得的唯一其他信息是套接字读取操作失败,读取数据为 0。这会导致(现在是循环的)列表的遍历。

我有几个转储都卡在同一个无限循环中。 我试图获取分配堆栈跟踪,但是 !heap -p -a 给了我 “地址 eeddccee 的 ReadMemory 错误 使用 `!address eeddccee' 检查地址的有效性。” 对于我尝试的所有地址。

目前我正在研究修复 L4 警告(除了我不知道哪个可能与此相关,我有一堆 C4100、C4511、C4512,我不知道如何修复;我是主要是修复像 C4244 这样的简单问题)。 DebugDiag 没有找到任何东西,除了给我一个 “这个线程没有完全解决,可能是也可能不是问题。可能需要对这些线程进行进一步分析。”在单线程上。

据我所知,我的选择是修复更多警告、重新阅读代码直到我突然想到什么或从这里学到新东西。

这真的是内存损坏吗?为什么每次都卡在同一个结构中? 我怎样才能找到原因?

最佳答案

修复警告错误是一个好主意——它可能会让你感觉更好,并且肯定会减少构建中的困惑——但它不太可能解决当前的问题,因此最好将其作为带外任务留给 future 。

带有 0 数据的套接字读取失败可能意味着套接字已关闭。也许您在这里遇到了计时问题,其中套接字关闭逻辑导致并发访问某些未正确锁定的共享数据结构。仔细查看套接字代码,确保锁定正确且无懈可击。确保在您的套接字 API 调用中正确处理了所有可能的错误代码(大概是 Winsock?)。您可以确定,即使是容器上并发访问的最小窗口或“不可能发生”的错误路径最终也会在您的生产环境中出现。我知道您说过该应用程序是单线程的,但 Windows 有一个有趣的习惯,它会为您提供并非您自己启动的额外线程,例如,如果您使用的 DLL 服务本身会启动新线程。

当您无法获得良好的生产诊断时会很困难,但如果您可以将问题缩小到特定区域,请尝试在模拟现实生活中使用的单元测试应用程序中隔离失败代码,并强调到底它在您的桌面上。我遇到过这样的间歇性错误,即使在专门测试应用程序的重负载下也需要数小时才能重现该问题。在调试器中以这种模式(当然是发布版本)运行可能会比您想象的更快地暴露问题。

另一种选择可能是安装 Process Dumper在发生故障的机器上并指示它在访问冲突和进程退出时转储完整的内存镜像(根据标准 Windbg DMP 文件可调试)。这可能会提供比小型转储事后调试更好的信息。如果您的客户愿意合作,他们可以指示在下次出现问题时生成转储。这是您无需在机器上或无法远程访问机器即可进行实时调试的最接近方法。

您可能还需要考虑在套接字关闭逻辑中生成额外的诊断,以验证这是否是错误情况的近因。

确保您客户的操作系统和其他系统软件是最新的,并安装了所有必需的补丁。也许这甚至不是你的错(尽管你似乎有一个错误,可以肯定)。

关于c++ - 可能的堆损坏(win 32, native c++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3684077/

相关文章:

C++ 奇怪的 RAW 套接字和 iptables 问题

c++ - 如何在 RichEdit 控件中更改选择颜色?

c++ - Eclipse-CDT:如何处理打开套接字的权限被拒绝错误?

go - 在Go语言编写的游戏中查找内存泄漏的正确方法

python - 使用 copy=False 为 numpy.array 分配内存?

c++ - 创建一个结构体作为枚举类成员

visual-studio-2008 - 如何告诉 Visual Studio 在 Break All 时不要离开当前文件?

c# - 每当输入文件(或类)时中断

c++ - 如何使用多指针写入 ProcessMemory

java - 如何从 jni 代码 junit 测试回调