使用valgrind跟踪segfault,并了解valgrind输出

时间:2018-05-29 19:53:14

标签: c++ valgrind

我正在尝试调试我的C ++程序,即segfaulting。

  • 我检查了我的代码,看看能否找到段错误的原因。我放置了一些cout语句来缩小发生故障的位置。

  • 我找到了产生段错误的函数调用。它在回调函数中。这条线是

    inputbox->TestFunc();

虽然这对读者来说毫无意义。

  • GDB中的回溯证实了这一点。 (除了回溯之外,我无法从GDB获得更多有用的信息,但我对调试工具不太熟悉。)

  • 我试图生产MWE,但失败了。我失败了,因为当我剥离部分代码以生成MWE时,问题就消失了。 (所以我猜这是微妙的,不是微不足道的。)

  • 我尝试从头开始编写MWE,复制我的继承结构,但这失败了。

  • 我的部分问题是我不能简单地删除" xyz"一点代码,因为这个改变的一个函数参数由于存在的继承结构而破坏了许多其他代码。

我做了一些其他的测试,例如移动代码的"问题部分"对于不同的功能,例如int main()下面的图层,在这些地方,似乎没有问题。

inputbox->TestFunc2()的调用不会崩溃。 TestFunc2()不是重写的虚函数。 TestFunc()是,我认为这可能会暗示问题的原因。 (虽然不是直接的,因为将inhertance结构复制到MWE会使问题消失。)

这两个测试函数只是cout函数的名称然后返回。他们不会把任何东西读/写到记忆中。

  • 我暂时没有发布任何内容,因为我无法以能够得到一些有意义的回复的方式提出问题,但是一些互联网搜索建议我尝试使用valgrind来调试问题。

有了这个,这里是valgrind输出

==8379== Memcheck, a memory error detector
==8379== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8379== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==8379== Command: ./a.out
==8379== 
==8379== Conditional jump or move depends on uninitialised value(s)
==8379==    at 0x4C32EA6: rawmemchr (vg_replace_strmem.c:1402)
==8379==    by 0x5E8C3C1: _IO_str_init_static_internal (strops.c:41)
==8379==    by 0x5E7FB96: vsscanf (iovsscanf.c:40)
==8379==    by 0x5E7A306: sscanf (sscanf.c:32)
==8379==    by 0xEC17E4A: ??? (in /usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0)
==8379==    by 0xEC18182: ??? (in /usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0)
==8379==    by 0xEC1BBF8: drmGetDevice (in /usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0)
==8379==    by 0xD7622D6: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379==    by 0xD761694: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379==    by 0xD735988: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379==    by 0xD731B9A: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379==    by 0xD731FD1: glXQueryExtensionsString (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379== 
==8379== Syscall param writev(vector[...]) points to uninitialised byte(s)
==8379==    at 0x5EF6E70: __writev_nocancel (syscall-template.S:84)
==8379==    by 0x94BB41C: ??? (in /usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0)
==8379==    by 0x94BB81C: ??? (in /usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0)
==8379==    by 0x94BB89C: xcb_writev (in /usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0)
==8379==    by 0x6D6EA7D: _XSend (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379==    by 0x6D6EF71: _XReply (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379==    by 0x6D59E2E: XInternAtom (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379==    by 0x4EFE46A: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x4EFF364: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x4EEF2EF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x4EEF07E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x4E55456: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==  Address 0xd1a9813 is 35 bytes inside a block of size 16,384 alloc'd
==8379==    at 0x4C2DBC5: calloc (vg_replace_malloc.c:711)
==8379==    by 0x6D5EEC5: XOpenDisplay (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379==    by 0x4EFD53F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x4EEF02B: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x4E55456: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x10CF85: main (main.cpp:61)
==8379== 
_ftm_ address: 0x12a0b610
SetPosition(0, 0)
Inputbox::TestFunc2()
Inputbox::TestFunc()
Inputbox::Draw()

0,0
SetPosition(0, 600)
refreshdelay set to: 16
ENTERED MAIN
SetPosition(0, 0)
Inputbox::TestFunc2()
Inputbox::TestFunc()
Inputbox::Draw()
derived2::function()
function was called ok
Window address: 0xffefffa00
Window 0
Window::TestFunc()
this=0xffefffa00
FontTextureManager::TestFunc()
this=0x12a0b610
current_window->_ftm_ address: 0x12a0b610
==8379== Conditional jump or move depends on uninitialised value(s)
==8379==    at 0x4EEBA2D: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x128278: Window::Height() const (Window.hpp:773)
==8379==    by 0x12794E: fc_open(Window*) (FunctionCallback.cpp:133)
==8379==    by 0x10D257: main (main.cpp:109)
==8379== 
==8379== Use of uninitialised value of size 8
==8379==    at 0x4EEBA32: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x128278: Window::Height() const (Window.hpp:773)
==8379==    by 0x12794E: fc_open(Window*) (FunctionCallback.cpp:133)
==8379==    by 0x10D257: main (main.cpp:109)
==8379== 
==8379== Use of uninitialised value of size 8
==8379==    at 0x12827D: Window::Height() const (Window.hpp:774)
==8379==    by 0x12794E: fc_open(Window*) (FunctionCallback.cpp:133)
==8379==    by 0x10D257: main (main.cpp:109)
==8379== 
==8379== Conditional jump or move depends on uninitialised value(s)
==8379==    at 0x4EEBA23: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x12823C: Window::Width() const (Window.hpp:766)
==8379==    by 0x127966: fc_open(Window*) (FunctionCallback.cpp:133)
==8379==    by 0x10D257: main (main.cpp:109)
==8379== 
==8379== Use of uninitialised value of size 8
==8379==    at 0x4EEBA28: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379==    by 0x12823C: Window::Width() const (Window.hpp:766)
==8379==    by 0x127966: fc_open(Window*) (FunctionCallback.cpp:133)
==8379==    by 0x10D257: main (main.cpp:109)
==8379== 
==8379== Use of uninitialised value of size 8
==8379==    at 0x128241: Window::Width() const (Window.hpp:767)
==8379==    by 0x127966: fc_open(Window*) (FunctionCallback.cpp:133)
==8379==    by 0x10D257: main (main.cpp:109)
==8379== 
SetPosition(400, 300)
INPUTBOX...
Inputbox::TestFunc2()
==8379== Invalid read of size 8
==8379==    at 0x1279BF: fc_open(Window*) (FunctionCallback.cpp:136)
==8379==    by 0x10D257: main (main.cpp:109)
==8379==  Address 0x340 is not stack'd, malloc'd or (recently) free'd
==8379== 
==8379== 
==8379== Process terminating with default action of signal 11 (SIGSEGV)
==8379==  Access not within mapped region at address 0x340
==8379==    at 0x1279BF: fc_open(Window*) (FunctionCallback.cpp:136)
==8379==    by 0x10D257: main (main.cpp:109)
==8379==  If you believe this happened as a result of a stack
==8379==  overflow in your program's main thread (unlikely but
==8379==  possible), you can try to increase the size of the
==8379==  main thread stack using the --main-stacksize= flag.
==8379==  The main thread stack size used in this run was 8388608.
==8379== 
==8379== HEAP SUMMARY:
==8379==     in use at exit: 29,970,438 bytes in 46,548 blocks
==8379==   total heap usage: 109,878 allocs, 63,330 frees, 61,448,020 bytes allocated
==8379== 
==8379== LEAK SUMMARY:
==8379==    definitely lost: 461,536 bytes in 124 blocks
==8379==    indirectly lost: 176 bytes in 4 blocks
==8379==      possibly lost: 28,306,879 bytes in 43,538 blocks
==8379==    still reachable: 1,201,847 bytes in 2,882 blocks
==8379==         suppressed: 0 bytes in 0 blocks
==8379== Rerun with --leak-check=full to see details of leaked memory
==8379== 
==8379== For counts of detected and suppressed errors, rerun with: -v
==8379== Use --track-origins=yes to see where uninitialised values come from
==8379== ERROR SUMMARY: 23 errors from 9 contexts (suppressed: 0 from 0)
Segmentation fault

关键字似乎是Invalid read of size 8 at 0x1279BF: fc_open(Window*) (FunctionCallback.cpp:136)

这些信息意味着什么,我应该在我的代码中寻找可能导致此错误的内容?

代码段:

void fc_open(Window *const current_window)
{

    derived2 *object = new derived2;
    object->function();
    std::cout << "function was called ok" << std::endl;

    std::cout << "Window address: " << current_window << std::endl;
    std::cout << current_window->TestName() << std::endl;
    current_window->TestFunc();
    current_window->_ftm_->TestFunc();
    std::cout << "current_window->_ftm_ address: " << current_window->_ftm_ << std::endl;
    Inputbox *inputbox = new Inputbox(current_window->_ftm_);
    std::cout << "inputbox=" << inputbox << std::endl;
    inputbox->SetPosition(current_window->Width() / 2, current_window->Height() / 2);
    std::cout << "INPUTBOX..." << std::endl;
    inputbox->TestFunc2();
    inputbox->TestFunc(); // BOOM

}

1 个答案:

答案 0 :(得分:0)

问题已解决:未来读者的信息。

此信息不太可能在将来帮助任何人,但以防万一,这就是导致问题的原因。

首先,让我们检查导致segfault的函数中的代码:

Inputbox *inputbox = new Inputbox(current_window->_ftm_);
inputbox->SetPosition(current_window->Width() / 2, current_window->Height() / 2);
inputbox->TestFunc2();
inputbox->TestFunc();
  • 我不知道为什么TestFunc2()没有爆炸,而TestFunc()也没有。

  • 问题实际上是由对SetPosition的调用引起的,SetPosition需要2个整数作为参数。

现在让我们检查宽度和高度函数:

int Width() const
{
    int *w;
    SDL_GetWindowSize(_window_.get(), w, nullptr);
    return *w;
}

这显然是错误的,是由于没有引起注意而引起的。它应该是:

int Width() const
{
    int w;
    SDL_GetWindowSize(_window_.get(), &w, nullptr);
    return w;
}

Valgrind在有关宽度和高度功能的打印消息中暗示了问题的原因。

  • 我仍然不完全理解为什么会发生段错误。我猜这是由于某种优化重新排序?