Как отладить до смешного большой код?

Я не программист на С ++, но пытаюсь отлаживать сложный код. Не самые лучшие предпосылки, я знаю …

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

SOURCE = mySolver.C; g ++ -m64 -Dlinux64 -DWM_DP -Wall -Wextra -Wno-неиспользуемый параметр -Wold-style-cast -O3 -DNoRepository -ftemplate-глубина-100 -I / opt / программное обеспечение / openfoam / OpenFOAM-2.0.5 / src / dynamicMesh / lnInclude {дополнительная ссылка} -I. -fPIC -c $ SOURCE -o Make / linux64Gcc46DPOpt / mySolver.o

и после запуска солвера с соответствующими опциями он падает в конце после (или пока) моего оператора return:

BEFORE return 0

*** glibc detected *** /opt/software/openfoam/myLibs/applications/bin/linux64Gcc46DPOpt/mySolver: double free or corruption (!prev): 0x000000000d3b7c30 ***
======= Backtrace: =========
/lib64/libc.so.6[0x31c307230f]
/lib64/libc.so.6(cfree+0x4b)[0x31c307276b]
/opt/software/openfoam/ThirdParty-2.0.5/platforms/linux64/gcc-4.5.3/lib64/libstdc++.so.6(_ZNSsD1Ev+0x39)[0x2b34781ffff9]
/opt/software/openfoam/myLibs/applications/bin/linux64Gcc46DPOpt/mySolver(_ZN4Foam6stringD1Ev+0x18)[0x441e2e]
/opt/software/openfoam/myLibs/applications/bin/linux64Gcc46DPOpt/mySolver(_ZN4Foam4wordD2Ev+0x18)[0x442216]
/lib64/libc.so.6(__cxa_finalize+0x8e)[0x31c303368e]
/opt/software/openfoam/myLibs/lib/linux64Gcc46DPOpt/libTMP.so[0x2b347a17f866]
======= Memory map: ========
...

Мой решатель выглядит так (извините, я не могу опубликовать все части):

#include "stuff1.H"#include "stuff2.H"
int main(int argc, char *argv[])
{
#include "stuff3.H"#include "stuffn.H"
while (runTime.run())
{

...

}

Info<< "BEFORE return 0\n" << endl;

return(0);
}

Запуск решателя с GDB с установка set environment MALLOC_CHECK_ 2 уступает:

BEFORE return 0

Program received signal SIGABRT, Aborted.
0x00000031c3030265 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00000031c3030265 in raise () from /lib64/libc.so.6
#1  0x00000031c3031d10 in abort () from /lib64/libc.so.6
#2  0x00000031c3075ebc in free_check () from /lib64/libc.so.6
#3  0x00000031c30727f1 in free () from /lib64/libc.so.6
#4  0x00002aaab0496ff9 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() ()
from /opt/software/openfoam/ThirdParty-2.0.5/platforms/linux64/gcc-4.5.3/lib64/libstdc++.so.6
#5  0x0000000000441e2e in Foam::string::~string (this=0x2aaaac0bd3c8, __in_chrg=<value optimized out>) at /opt/software/openfoam/OpenFOAM-2.0.5/src/OpenFOAM/lnInclude/string.H:78
#6  0x0000000000442216 in Foam::word::~word (this=0x2aaaac0bd3c8, __in_chrg=<value optimized out>) at /opt/software/openfoam/OpenFOAM-2.0.5/src/OpenFOAM/lnInclude/word.H:63
#7  0x00000031c303368e in __cxa_finalize () from /lib64/libc.so.6
#8  0x00002aaab2416866 in __do_global_dtors_aux () from /opt/software/openfoam/myLibs/lib/linux64Gcc46DPOpt/libTMP.so
#9  0x0000000000000000 in ?? ()
(gdb)

Как мне найти настоящий источник моей ошибки?

Btw. Я видел этот а также этот что похоже, но не решает мою проблему. Кроме того, Valgrind не работает правильно для меня. Я знаю, что это связано с неправильным (де) распределением, но я не знаю, как на самом деле найти проблему.

/Редактировать

Я не смог найти свою проблему еще …

Я думаю, что обратная трассировка, которую я разместил выше (позиция № 8), показывает, что проблема в коде, который компилируется в libTMP.so, в Сделать / варианты файл я добавил опцию -DFULLDEBUG -g -O0. Я думал, что тогда можно отследить ошибку, но я не знаю как.

Любая помощь высоко ценится!

1

Решение

Если вы имели дело со всеми предупреждениями компилятора и ошибками valgrind, но проблема остается, тогда Разделяй и властвуй.

Вырежьте половину кода (используйте #if директивы, удаляйте файлы из Makefile или удаляйте строки и восстанавливайте их позже, используя систему контроля версий).

Если проблема исчезнет, ​​скорее всего, это вызвано тем, что вы только что удалили. Или, если проблема остается, то это, конечно, в коде, который все еще остается.

Повторите процедуру рекурсивно, пока вы не определите проблемное местоположение.

Это не всегда работает, потому что неопределенное поведение может проявиться позже, чем строка, вызвавшая его.

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

5

Другие решения

Если у вас нет ничего конкретного после использования gdb а также valgrind Я думаю, что вы можете попробовать разобрать свой так использование библиотеки objdumpКак вы можете видеть в обратном следе, он дал вам адрес ошибок, я долго пробовал такой подход в своем проекте при отладке проблемы. После дизассемблирования вы сопоставляете адрес ошибки с адресом выписки в вашей библиотеке, это может дать вам представление о местонахождении ошибки.
Команда на разборку objdump -dR <library.so>

Вы можете найти больше информации о objdump Вот

3

Valgrind

Хорошо, я рискую быть застреленным за ответ одним словом, но терпите меня. Попробуйте Вальгринд. Создайте самую отладочную версию, в которой у вас все еще есть проблемы, и просто выпустите:

Путь valgrind / к / программе

Скорее всего, первая проблема будет источником вашей проблемы. Вы даже можете заставить valgrind запустить сервер GDB и позволить вам присоединиться для отладки кода, ведущего к первой проблеме с памятью. Увидеть:

http://tromey.com/blog/?s=valgrind

2

Некоторые другие варианты, которые еще не были перечислены:

Вы можете попробовать GDB возможность записи потока выполнения:

$ gdb target_executable
(gdb) b main
(gdb) run
(gdb) target record-full
(gdb) set record full insn-number-max unlimited

Затем, когда программа выйдет из строя, вы сможете выполнить поток в обратном направлении с reverse-next а также reverse-step команды. Обратите внимание, что программа работает очень медленно в этом режиме.

Другой возможный подход — попробовать Clang. статический анализатор или же лязг проверка инструменты в вашем коде. Иногда анализатор может дать хороший совет, где может быть проблема в коде.

Кроме того, вы можете связать свой код с jemalloc и использовать его возможности отладки. Опции «opt.junk», «opt.quarantine», «opt.valgrind» и «opt.redzone» могут быть полезны. В общем, это заставляет malloc выделять некоторую дополнительную память, которая используется для мониторинга операций записи и чтения после окончания буферов, чтения освобожденной памяти и так далее. Увидеть справочная страница. Эти параметры могут быть включены с mallctl функция.

Еще один способ найти ошибку — создать свой код с включенными дезинфицирующими средствами gcc или clang. Вы можете включить их с -fsanitize = «sanitizer», где «sanitizer» может быть одним из: address, thread, leak, undefined, Компилятор снабдит приложение дополнительным кодом, который выполнит дополнительные проверки и распечатает отчет. Например:

#include <vector>
#include <iostream>

int main() {
std::vector<int> vect;
vect.resize(5);
std::cout << vect[10] << std::endl; // access the element after the end of vector internal buffer
}

Скомпилируйте его с включенным дезинфицирующим средством и запустите:

$ clang++ -fsanitize=address test.cpp
$ ./a.out

Дает вывод:

==29920==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000dff8 at pc 0x0000004bad10 bp 0x7fff16d63e10 sp 0x7fff16d63e08
READ of size 4 at 0x60400000dff8 thread T0
#0 0x4bad0f in main (/home/pablo/a.out+0x4bad0f)
#1 0x7f0b6ce43fdf in __libc_start_main (/lib64/libc.so.6+0x1ffdf)
#2 0x4baaac in _start (/home/pablo/a.out+0x4baaac)

0x60400000dff8 is located 0 bytes to the right of 40-byte region [0x60400000dfd0,0x60400000dff8)
allocated by thread T0 here:
#0 0x435b9b in operator new(unsigned long) (/home/pablo/a.out+0x435b9b)
#1 0x4c1f49 in __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (/home/pablo/a.out+0x4c1f49)
#2 0x4c1d05 in __gnu_cxx::__alloc_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (/home/pablo/a.out+0x4c1d05)
#3 0x4bfd51 in std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (/home/pablo/a.out+0x4bfd51)
#4 0x4bdb2a in std::vector<int, std::allocator<int> >::_M_fill_insert(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, unsigned long, int const&) (/home/pablo/a.out+0x4bdb2a)
#5 0x4bbe49 in std::vector<int, std::allocator<int> >::insert(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, unsigned long, int const&) (/home/pablo/a.out+0x4bbe49)
#6 0x4bb358 in std::vector<int, std::allocator<int> >::resize(unsigned long, int) (/home/pablo/a.out+0x4bb358)
#7 0x4bacaa in main (/home/pablo/a.out+0x4bacaa)
#8 0x7f0b6ce43fdf in __libc_start_main (/lib64/libc.so.6+0x1ffdf)
2

Я частично согласен с Мэттом: разделяй и властвуй это путь. Но я частично согласен, потому что я частично не согласен: изменение кода, который вы пытаетесь отлаживать, может привести вас к поиску неправильного пути, даже больше, если вы пытаетесь отлаживать огромный и сложный код, не принадлежащий вам на языке, который вы не используете. т мастер.

Вместо этого следуйте методу «разделяй и властвуй» в сочетании со стратегией «сверху вниз»: начните с добавления нескольких точек останова в коде на более высоком уровне, скажем, на главном, затем запустите программу и посмотрите, какие точки взлома достигнуты, а какие нет до сбоя. , Теперь у вас есть общее представление о том, где ошибка; удалите все точки останова и добавьте новые немного глубже, в области, которую вы только что нашли, и повторяйте до тех пор, пока вы не нажмете процедуру, вызывающую сбой.

Это может быть утомительно, я знаю, но это работает, и, более того, при этом это даст вам намного лучшее понимание того, как работает вся система. Таким образом я исправил ошибки в неизвестных приложениях, состоящих из десятков тысяч строк кода, и это всегда работает; Может быть, это может занять целый день, но это работает.

1
По вопросам рекламы [email protected]