Отслеживание segfault с помощью valgrind и понимание выходных данных valgrind - PullRequest
0 голосов
/ 29 мая 2018

Я пытаюсь отладить свою программу на C ++, которая является segfaulting.

  • Я проверил свой код, чтобы выяснить, могу ли я найти причину segfault.Я поместил несколько операторов cout, чтобы сузить место, в котором произошла ошибка.

  • Я нашел вызов функции, которая вызывает ошибку сегмента.Это внутри функции обратного вызова.Это строка

    inputbox->TestFunc();

, хотя для читателя это бессмысленно.

  • Это было подтверждено обратным следомв ГБД.(Я не мог получить более полезную информацию от GDB, кроме обратной трассировки, но я не слишком знаком с инструментами отладки.)

  • Я попытался создать MWE, и потерпел неудачу.Я потерпел неудачу, потому что, когда я сократил части кода для создания MWE, проблема ушла.(Так что я предполагаю, что это что-то тонкое, а не тривиальное.)

  • Я пытался написать MWE с нуля, копировать свои структуры наследования, но это не удалось.

  • Часть моей проблемы заключается в том, что я не могу просто удалить бит «xyz» кода, потому что это изменение одного аргумента функции нарушает множество другого кода из-за существующих структур наследования.

Я провел несколько других тестов, например, переместил «проблемную часть кода» в другие функции, такие как слой чуть ниже int main(), и в этих местах, похоже, нет проблем.

Вызов inputbox->TestFunc2() не завершается.TestFunc2() не является переопределенной виртуальной функцией.TestFunc() есть, и я думаю, что это может указывать на причину проблемы.(Хотя это и не напрямую, поскольку копирование структуры наследования в MWE устраняет проблему.)

Обе эти тестовые функции просто следят за именем функции и затем возвращают.Они ничего не читают и не записывают в память.

  • Я некоторое время ничего не публиковал в SO, потому что не мог сформулировать вопрос таким способом, который мог бы получитькакой-то значимый ответ, однако некоторые поиски в Интернете предложили мне попытаться использовать 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 голосов
/ 29 мая 2018

Проблема решена: информация для будущих читателей.

Маловероятно, что эта информация поможет кому-либо в будущем, но на всякий случай здесь причина проблемы.

Сначаладавайте рассмотрим код в функции, которая вызывала ошибку:

Inputbox *inputbox = new Inputbox(current_window->_ftm_);
inputbox->SetPosition(current_window->Width() / 2, current_window->Height() / 2);
inputbox->TestFunc2();
inputbox->TestFunc();
  • Я понятия не имею, почему TestFunc2 () не взорвался, а TestFunc () сделал.

  • Проблема фактически была вызвана вызовом 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 намекнул на причину проблемы в печатных сообщениях о функциях ширины и высоты.

  • Я до сих пор не до конца понимаю, почемуОднако произошла ошибка.Я думаю, это связано с каким-то оптимизационным переупорядочением?
...