【问题标题】:C++ How to debug a dangling pointer in productionC ++如何在生产中调试悬空指针
【发布时间】:2021-12-26 09:59:35
【问题描述】:

基本上情况是我们有一个 C++ 程序在尝试访问一个已经释放的对象时偶尔会崩溃(在 Debug 构建中,我们注意到指向的内存充满了通常的“cdcdcdcd”模式)。我们试图跟踪清除对象的每个点,但找不到已知指针未正确设置为 null 的位置。

有两个主要问题 - 代码非常庞大且令人费解,编写了至少十年的时间,并且有几个开发人员下落不明,甚至有些人已经去世,因此无法进入与最初编写代码的人联系。代码的复杂性使得手动确定存在多少指向所述对象的指针以及哪些函数使用或复制它们是不切实际的。

第二个大问题是我们没有可靠的重现方式。我们知道,在拥有数百个并发用户的生产系统中,它每天大约崩溃两次,但在测试环境中重现崩溃的所有尝试都失败了。我们应该可以在崩溃后检查生产环境几分钟,但最终我们必须将其恢复。环境为Windows Server 2019,程序用Visual Studio 2019编译,服务器上有Visual Studio的副本和程序源代码。我们已经尝试使用 DMP 文件,但失败了,因为转储只显示了悬空指针的使用,它没有告诉我们指向的对象被释放的点在哪里。

我会很感激任何建议,因为我几乎没有想法。

谢谢。

【问题讨论】:

  • 我会从寻找Rule of Three 违规者开始。
  • 没有minimal reproducible example,我们无能为力。将原始指针使用替换为 shared_ptrunique_ptr 可能会解决此问题。您可以将打印语句添加到导致崩溃的对象的析构函数并打印其地址,甚至可能是堆栈跟踪。编写大量单元测试并使用测试覆盖工具来确保他们在夜间测试所有内容也有帮助
  • 对象及其类型,甚至事后访问它的位置都是已知的。现在通常是繁琐的工作来确定您用来取消引用它的指针是从哪里复制的,而其他副本是从哪里删除的。如果您的团队中没有人可以,那么您必须雇用。
  • 我将不胜感激任何建议,因为我几乎没有想法。 -- 缓慢但肯定地重写可以使用现代 C++ 重写的代码部分容器、智能指针、std::string 而不是字符指针等,并观察新程序是否正确运行。如果新程序模仿了旧程序,而新程序崩溃了,那么您现在有更好的机会来调试问题。
  • MSVS 现在支持 Address Sanitizer 。首先使用它构建一个发布版本并对其进行测试。确保还为任何转储分析生成必要的 .pdb 文件。

标签: c++ visual-studio pointers debugging dangling-pointer


【解决方案1】:

您已经注意到“释放后使用”问题。下一步是找出其中的哪一部分是错误的。对象应该没有被释放,还是应该没有被使用?

对于智能指针,这仍然需要了解 - 您应该使用 shared_ptr 还是 weak_ptr?这些类并不神奇——您可以通过许多其他方式实现相同的行为。但它们肯定很方便;你只需要弄清楚使用哪一个。另一个很大的优势是未来的读者会看到weak_ptr 并且可以反转你的逻辑 - 这是一个非拥有指针,因此实现了“释放后不要使用”而不是“使用时不要释放” .

【讨论】:

  • 好吧,我同意如果在任何地方都使用 shared_ptr 会是一个好主意,但不幸的是情况并非如此(我认为 shared_ptr 在第一次编写该代码时甚至不存在于 STL 中)。它的遗留代码和编码标准在过去几乎没有强制执行,因此在当前的 HR 中几乎不可能跟踪和找到每一次使用。我希望有某种调试实用程序可以跟踪指向特定地址的所有指针。
  • @Dan 你需要一种方法来追踪无效指针,所以我为你找到了一个solution。希望对您有所帮助。
猜你喜欢
  • 2011-07-14
  • 2021-09-14
  • 1970-01-01
  • 1970-01-01
  • 2020-09-07
  • 2013-01-10
  • 1970-01-01
  • 2018-04-09
相关资源
最近更新 更多