无法找到段错误的根源

发布于 2024-08-02 10:16:37 字数 2729 浏览 5 评论 0原文

编辑:问题已解决。这是(又一种)情况,问题实际上并不在看起来的地方。线索是使用 @0xfeeefefe 作为指向对象的指针。这是Windows API函数在释放内存时返回的地址...表明正在操作的对象已被删除。

我在尝试从 std::map 中删除值时收到分段错误,但我一生都无法弄清楚原因。从调试器(gdb)我看到:

Program received signal SIGSEGV, Segmentation fault.
0x0048785f in std::less<irr::gui::IGUIWindow*>::operator()(irr::gui::IGUIWindow* const&, irr::gui::IGUIWindow* const&) const (this=0x258ab04, __x=@0x22f778, __y=@0xfeeefefe)
at C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_function.h:227
227           { return __x < __y; }

但奇怪的部分是对这两个输入值的以下检查:

(gdb) x 0x22f778
0x22f778:       0x025e1ef8
(gdb) x 0xfeeefefe
0xfeeefefe:     0x025e1ef8

一些背景: 该映射是指针到指针的映射。具体来说,键是指向 GUI 系统中的窗口的指针,值是指向可以将要打印的信息发送到该窗口的对象的指针。还有一个从可调试对象到窗口的逆映射。原因是,如果窗口关闭,则需要通知可调试对象,以便它不能浪费时间尝试向其发送数据。逆映射是这样的,当管理器(此代码所在的类)从可调试对象接收到数据包时,它知道在哪个窗口中打印信息。

所以问题是为什么两个指针值的比较 < code>return( 0x025e1ef8 < 0x025e1ef8 ) 导致错误?

我只尝试在代码中的某一点删除某些内容,并且它不在循环中,因此不会有任何迭代器被破坏。我也只在另一个地方将东西插入到该地图中,并且当插入和删除东西时我会打印出痕迹,而且我看不出有什么问题。

我知道这没有足够的信息来真正提供帮助,但代码确实很大,我不确定我能做些什么来找出问题。如果有建议,我很乐意提供更多信息。我将粘贴代码的一些部分,以便快速了解发生了什么。希望这里有一些东西可以表明我的问题是什么。

这是有问题的部分

case EGET_ELEMENT_CLOSED:
{
    IGUIWindow* window =
        static_cast<IGUIWindow*>(event.GUIEvent.Caller);

    if( m_debugMap.find(window) != m_debugMap.end())
    {
        IGuiDebuggable* debug = m_debugMap[window];
        debug->removeListener(this);

        cout << "closing window: " << window << " attached"
                " to debuggable: " << debug << endl;

        m_debugMap.erase(window);    /// segfault here
        m_conMap.erase(debug);       /// if above line commented, segfault here
    }

    m_eventMap.erase(window);    /// if above block commented, segfault here
    window->remove();
    return true;
}

这是将元素添加到地图的部分

IGUIElement*    winElmnt    =
                    m_env->getRootGUIElement()->getElementFromId(0,false);

IGUIElement*    editElmnt   = winElmnt->getElementFromId(1);
IGUIWindow*     window      = static_cast<IGUIWindow*>(winElmnt);

cout << "CModelTesterGui: adding " << window << "(" << winElmnt
     << ") to the debug map with edit box " << editElmnt << endl;

m_conMap[debug]             = static_cast<IGUIEditBox*>(editElmnt);
m_debugMap[window]          = debug;

window->setID(-1);
debug->addListener( this );

正如你所看到的,我正在打印出要进入的内容和试图从地图中删除的内容的地址,它们与我相对应我会期望所以我不会试图删除失效的值或任何东西。

哦,还有最后一点。这是一个奇怪的怪癖。如果我只打开一个窗口(即只向地图添加一个元素),我可以很好地擦除它。只有在向映射添加两个或多个元素后,尝试删除其中一个元素才会导致分段错误。

EDIT: Problem solved. This was (yet another) situation where the problem wasn't really where it looked like it was. The clue was the use of @0xfeeefefe as a pointer to an object. This is an address that is returned by a windows API function when freeing memory... indicating that the object that was being operated on had been deleted.

I'm receiving a segmentation fault while trying to erase a value from a std::map, but I cannot for the life of me figure out why. From the debugger (gdb) I see:

Program received signal SIGSEGV, Segmentation fault.
0x0048785f in std::less<irr::gui::IGUIWindow*>::operator()(irr::gui::IGUIWindow* const&, irr::gui::IGUIWindow* const&) const (this=0x258ab04, __x=@0x22f778, __y=@0xfeeefefe)
at C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_function.h:227
227           { return __x < __y; }

But the weird part is the following examination of those two input values:

(gdb) x 0x22f778
0x22f778:       0x025e1ef8
(gdb) x 0xfeeefefe
0xfeeefefe:     0x025e1ef8

Some background:
The map is a mapping of pointers to pointers. Specifically, the key is a pointer to a window in a gui system, and the value is a pointer to an object that may send information to be printed to that window. There is also an inverse map from the debuggable object to the window. The reason is that if the window is closed, the debuggable object needs to be informed so it can not waste time by trying to send data to it. The inverse mapping is so that when the manager (the class this code is inside of) receives a packet from a debuggable object, it knows which window to print the information in.

So the question is why would a comparison of two pointer values, return( 0x025e1ef8 < 0x025e1ef8 ) cause a fault?

I only try to erase things at one point in my code, and it's not in a loop so there aren't any iterators to corrupt. I also only insert things into that map at one other place and I have traces that print out when things are being inserted and erased and I can't see anything wrong with that.

I know this isn't enough information to really help, but the code is really large and I'm not sure what I can do to track down the problem. I would be happy to provide any more information if there are suggestions. I'll paste some of the parts of the code for a quick idea of what's going on. Hopefully there is something in here to indicate what my problem is.

Here's the part with the problem

case EGET_ELEMENT_CLOSED:
{
    IGUIWindow* window =
        static_cast<IGUIWindow*>(event.GUIEvent.Caller);

    if( m_debugMap.find(window) != m_debugMap.end())
    {
        IGuiDebuggable* debug = m_debugMap[window];
        debug->removeListener(this);

        cout << "closing window: " << window << " attached"
                " to debuggable: " << debug << endl;

        m_debugMap.erase(window);    /// segfault here
        m_conMap.erase(debug);       /// if above line commented, segfault here
    }

    m_eventMap.erase(window);    /// if above block commented, segfault here
    window->remove();
    return true;
}

And here's the part where an element is added to the map

IGUIElement*    winElmnt    =
                    m_env->getRootGUIElement()->getElementFromId(0,false);

IGUIElement*    editElmnt   = winElmnt->getElementFromId(1);
IGUIWindow*     window      = static_cast<IGUIWindow*>(winElmnt);

cout << "CModelTesterGui: adding " << window << "(" << winElmnt
     << ") to the debug map with edit box " << editElmnt << endl;

m_conMap[debug]             = static_cast<IGUIEditBox*>(editElmnt);
m_debugMap[window]          = debug;

window->setID(-1);
debug->addListener( this );

As you can see I'm printing out the addresses of what is going into and what is attempting to be erased from the map, and they correspond as I would expect so I'm not trying to erase defunct values or anything.

Oh, and a final note. Here's a weird quirk. If I only open one window (i.e. only add one element to the map) I can erase it fine. It's only after adding two or more elements to the map that trying to erase one of them causes a segmentation fault.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

澜川若宁 2024-08-09 10:16:37

在实际比较之前,尝试取消引用 0xfeeefefe 时似乎发生了段错误。

FEEEFEEE 由 Microsoft 使用
HeapFree() 标记已释放的堆内存 (1)

< 的类型有哪些代码>__x 和__y?您能否验证写入 __x__y 的初始值,然后监视内存位置是否有任何更改?

另外,如果您可以在 HeapFree 函数上放置一个断点,您也许能够捕获错误的内存引用。

It looks like segfault occurs trying to dereference 0xfeeefefe, before the actual comparison.

FEEEFEEE Used by Microsoft's
HeapFree() to mark freed heap memory (1)

What are the types of __x and __y? Can you verify the initial values written to __x and __y, and then put a watch on the memory location for any changes?

Also, if you could put a break point on the HeapFree function, you might be able to catch a bad memory reference.

向日葵 2024-08-09 10:16:37

哦,还有最后一点。这里有一个奇怪的
怪癖。如果我只打开一个窗口(即
只向地图添加一个元素)我可以
擦掉就好了。添加后才这样
地图上的两个或多个元素
试图删除其中一个会导致
分段错误。

奇怪的怪癖通常代表内存问题。您尝试过运行 valgrind 吗?

您要插入克隆吗?指针是否在映射中插入和删除之间的某个位置被删除?

Oh, and a final note. Here's a weird
quirk. If I only open one window (i.e.
only add one element to the map) I can
erase it fine. It's only after adding
two or more elements to the map that
trying to erase one of them causes a
segmentation fault.

Weird quirk usually stand for memory issues. Have you tried running valgrind?

Are you inserting a clone? Is the pointer being deleted somewhere between insertion and deletion from your map?

甜心 2024-08-09 10:16:37

我正在查看您的回溯,我正在查看它所说的内容

__x=@0x22f778, __y=@0xfeeefefe

这似乎表明 __x 和 __y 是引用。

在这种情况下,尝试测试( __x < __y )可能会取消引用它们,并且取消引用 0xfeeefefe 可能不是一件好事,除非您的机器安装了 beaucoup 内存。

I'm looking at your traceback, and I'm seeing where it says

__x=@0x22f778, __y=@0xfeeefefe

which seems to suggest that __x and __y are references.

That being the case, trying to test ( __x < __y ) may be dereferencing them, and dereferencing 0xfeeefefe might not be such a good thing to do, unless your machine has beaucoup memory installed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文