调试堆上的损坏对象

时间:2016-06-16 09:31:01

标签: c++ gdb valgrind lldb

我正在调试一个非平凡的软件项目,我在堆上有一堆对象。在某个时间点(至少),其中一个对象被破坏。

我在我的班级中添加了一个const成员作为金丝雀,事实上,它在执行过程中被破坏了。通常,我会在此变量中添加一个观察点,以确定何时写入内存。但是,我不知道哪个实例被覆盖,因为类中存储的任何信息也会被破坏。

我有太多的物体在每个物体上设置一个观察点,但我还没有能够用较小的输入设置重现。运行valgrind我看到"无效读取大小4和#34;,这是我读取的4个字节的canary int,但此时它已经太晚了。

有关如何从这里开始的任何建议?

3 个答案:

答案 0 :(得分:1)

可能这不够具体,但当我遇到类似的问题时,这就是我最终要做的事情。我假设你能以确定的方式重现你的问题。

我的策略是先找出导致问题的实例。我在一个暴露症状的特定线上做了一个计数器。例如,在Visual Studio上,我会设置一个在第100000次点击时触发的断点,以便它永远不会;但Visual Studio仍会告诉您执行期间遇到断点的次数。通过反复试验,我会发现问题出现在说,第20次遇到断点,因此我会设置断点在第19次迭代时触发,以便能够在发生损坏之前区分相应的实例。 / p>

从那里开始,我可以获得在它之前被破坏的变量的地址,并使用调试器来查找正在发生的事情:收集有关故障实例的足够信息。

然后,我确实在战略位置设置了断点,这些断点由条件触发:例如。仅触发具有适当地址的实例或成员中的特定值。

你可能会在症状准确发生的时候到达,但不是问题,但那仍然是。

希望这有帮助!

答案 1 :(得分:1)

  

运行valgrind我看到"读取大小为4"的无效,这是我读取的4个字节的canary int,但此时已经太晚了。

你很困惑:如果valgrind告诉你你正在做无效读取(可能是因为对象已被释放),那么你正在阅读 danging (已经释放)的对象,那就是完全你的问题。

您不应该尝试访问此类对象,并且在释放/删除对象后,您的金丝雀已被更改/损坏这一事实无关紧要。

答案 2 :(得分:1)

我设法找出导致我的问题的原因。原来我看到的对象从未存在过。就像@ employ-russian一样,我想知道我的对象是否可能已被删除,我不知道。在析构函数上放置断点没有产生任何结果,唯一合理的解释是指针本身无效,指向不是我的类的有效实例的内存。

瞧瞧;我解除引用的指针没有被另一个类的构造函数初始化。当我添加对null的显式检查并且Valgrind的错误变为Conditional jump or move depends on uninitialised value(s)时,我想通了。通过使用--track-origins=yes,我很快找出了未初始化数据的来源,即初始化列表中缺少的指针。

(我知道编译器可以使用-Wuninitialized检测到未初始化的值,但显然我的clang(apple)版本并不想在启用-Wall的情况下提及它。)