【问题标题】:this pointer is lost when calling a member method调用成员方法时this指针丢失
【发布时间】:2012-09-10 09:45:10
【问题描述】:

我在 Fedora 17 x86_64 机器上使用 64 位 g++ 4.7.0 编译我的程序时遇到了一个奇怪的问题(相同的程序在 32 位 Fedora 上运行良好)。

程序太复杂了,我想不出一个简单的方法来生成一个小代码示例。但是从下面的gdb记录中就可以看出问题所在了。

Program received signal SIGSEGV, Segmentation fault.
0x000000000042a4b0 in boost::shared_ptr<cppPNML::details::ddObj>::operator!(this=0x100000007)
    at /usr/include/boost/smart_ptr/detail/operator_bool.hpp:55
55          return px == 0;
Missing separate debuginfos, use: debuginfo-install gnome-keyring-3.4.1-3.fc17.x86_64
(gdb) bt
#0  0x000000000042a4b0 in boost::shared_ptr<cppPNML::details::ddObj>::operator! (this=0x100000007)
    at /usr/include/boost/smart_ptr/detail/operator_bool.hpp:55
#1  0x00000000004202a5 in cppPNML::pnNode::getBBox (this=0xffffffff) at cpp_pnml.cpp:131
#2  0x000000000040eca4 in draw_page (g=..., painter=...) at pnml2pdf.cpp:178
#3  0x000000000040e3b9 in main (argc=2, argv=0x7fffffffe188) at pnml2pdf.cpp:106
(gdb) up
#1  0x00000000004202a5 in cppPNML::pnNode::getBBox (this=0xffffffff) at cpp_pnml.cpp:131
131   if(!p_) return pair<double, double>(0,0);
(gdb) up
#2  0x000000000040eca4 in draw_page (g=..., painter=...) at pnml2pdf.cpp:178
178     boost::tie(w, h) = node.getBBox();
(gdb) p node
$1 = {<cppPNML::pnObj> = {_vptr.pnObj = 0x79a490, p_ = {px = 0x7c40a0, pn = {pi_ = 0x7c4170}}}, <No data fields>}
(gdb) l
173   QRectF bound(0,0,0,0);
174   
175   // nodes
176   for(pnNode node = g.front<pnNode>(); node.valid(); node = node.next()) {
177     double h, w, x, y, wa, ha, xa, ya, angle;
178     boost::tie(w, h) = node.getBBox();
179     angle = atan2(h, w);
180     boost::tie(x, y) = node.getPosition();
181     wa = 0; ha = 0; xa = 0; ya = 0;
182     
(gdb)

正在调试的程序是一个图形打印程序(pnml2pdf),它使用QT4将图形绘制成pdf。 对象节点属于pnNode类,是我自己的图形数据结构库定义的(挺复杂的,https://github.com/wsong83/cppPNML)。 它显示了一个 SEG 错误,其中智能指针未初始化。 通过回溯可以看出node.getBBox()的this指针是无效的。 但是,从上一级打印节点显示该节点实际上是可以的。

我在这里完全糊涂了。

任何人有任何线索或需要更多代码段吗?提前致谢!

更新: 感谢@atzz 的建议,我现在可以确定在成员方法 getBBox() 中计算此指针会产生错误的地址。该问题不是由任何源代码错误引起的(直接链接目标文件会消除段错误),而是由 64 位静态库生成命令“ar”引起的(因为 pnNode 的定义是在静态库中定义的,而不是目标文件)。现在看来静态库是错误的,导致这个计算错误。

仍在挖掘...如果有人仍然有兴趣知道,将更新结果。

【问题讨论】:

  • 我认为将您的问题减少到可管理大小的样本将帮助您找到问题,并帮助我们了解这里出了什么问题。来自 gdb 的转储没有那么有用。
  • 你试过 valgrind 吗?
  • @PlasmaHH 我不同意。代码链接在问题中,并不太大,无法查看。当然,这个问题似乎非常狭窄,但潜在的问题可能足够普遍,足以使其他人受益(我们还不知道)。我认为现有的抨击无法立即理解的问题的趋势不利于 SO 作为有用资源的未来。
  • 你可以通过disassemble命令在gdb中反汇编。如果我没有记错,disass pnml2pdf.cpp:176 pnml2pdf.cpp:179 应该反汇编与上述行相对应的地址范围。
  • @WeiSong 它是一个专门用于解决内存相关问题的 linux 调试器。你可以看看quick start或者我的回答here

标签: c++ g++ x86-64


【解决方案1】:
  1. 这是优化版本还是调试版本?在我看来,它应该在第 176 行而不是第 178 行失败。

  2. 您确定循环正确吗?看起来你要结束了。我怀疑你对node.valid() 的实现要么没有做正确的事情,要么是循环测试的错误事情。

0xffffffff 的值看起来像 std::iterator end() 的值,所以我认为你要么需要测试你的循环,要么确保 pnObj::valid() const { return p_ != NULL &amp;&amp; p_ != 0xffffffff; }

您实现next() 的方式也看起来不对。创建一个迭代器,搜索字符串ID,然后在迭代器上调用next()

【讨论】:

  • 呃,我之前怀疑过第176行,但是从步骤调试中你可以看到valid()成员方法确实得到了正确的this指针。我将尝试编写一个简单的程序来测试循环,希望我在那里犯了一些愚蠢的错误。
  • 另外,这不是迭代器。 next 简单地返回下一个节点对象。 OGDF等其他轻量级图形库也采用同样的方法。实现迭代类型很好,但可能比需要的要重(因此尚未实现)。
猜你喜欢
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多