2015-02-05 3 views
1

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

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

SOURCE=mySolver.C ; g++ -m64 -Dlinux64 -DWM_DP -Wall -Wextra -Wno-unused-parameter -Wold-style-cast -O3 -DNoRepository -ftemplate-depth-100 -I/opt/software/openfoam/OpenFOAM-2.0.5/src/dynamicMesh/lnInclude {more linking} -I. -fPIC -c $SOURCE -o Make/linux64Gcc46DPOpt/mySolver.o

и после запуска решателя с соответствующими опциями, он выходит из строя в конце после (или во время) мое возвращение заявление:

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); 
} 

Запуск решателя с БГД с settingset 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) 

Как мне найти реальный источник моей ошибки?

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

/Edit

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

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

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

+0

Если вы используете новый/новый [], вы вызываете delete/delete []? – NathanOliver

+0

@ Nathan solver включает в себя массу других файлов. Я не писал код, поэтому я не хочу искать вручную. Я думаю, что для этой цели есть отладчики. Но как я могу найти проблему (например, отсутствующие операторы удаления)? – EverythingRightPlace

+1

След предполагает, что коррупция происходит в древе глобального объекта типа «Foam :: word». Я бы искал места, где они объявлены, определены или (неправильно) использованы. – user2079303

ответ

2

Valgrind

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

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

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

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

4

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

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

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

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

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

Однако вы можете работать над созданием minimal program that still has the problem. В конце концов, вы должны либо создать фактический минимальный пример, который вы не можете уменьшить, или раскрыть истинную причину.

3

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

Вы можете найти более подробную информацию о objdumphere

+0

Мне нравится эта идея и посмотрел на результат ** objdump **. Адрес в '# 8 0x00002aaab2416866 в __do_global_dtors_aux() из/opt/software/openfoam/myLibs/lib/linux64Gcc46DPOpt/libTMP.so' не выводится в objdump. Я также искал do_global_dtors, который дает мне * something *: '00000000001463c0 <__ do_global_dtors_aux>: 1463c0: 55 push% rbp' и т. Д. ... как действовать? – EverythingRightPlace

2

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

Вы можете попробовать GDB execution flow recording capability:

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

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

Еще один возможный подход - попытаться использовать clang static analyzer или clang-check инструментов вашего кода. Иногда анализатор может дать хороший намек, где может возникнуть проблема с кодом.

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

Еще один способ найти ошибку - создать код с включенными дезинфицирующими устройствами gcc или clang. Вы можете включить их с помощью -fsanitize = «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) 
+0

При использовании 'GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5_5.2)' нет 'target record-full'. Я попробовал «целевую запись», а затем: «установить запись insn-number-max unlimited», которая дает следующую ошибку: «Без символа« неограниченно »в текущем контексте.' – EverythingRightPlace

+0

@EverythingRightPlace. Вы можете просто« записать полную », а затем« target record »вместо« target record-full ». Попытайтесь установить 'insn-number-max' значение 0, оно должно быть таким же, как неограниченное. –

+0

@EverythingRightPlace Попробуйте обновить gdb, если вы можете, мой 'GNU gdb (GDB) Fedora 7.8.2-38.fc21' –

1

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

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

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

+0

Но для моей проблемы заключается в **. Так что **, с которым я не могу остановиться. Или как вы будете действовать по моей конкретной проблеме (см. Вывод gdb)? – EverythingRightPlace

+0

Я бы отказал в ответе, если бы мог; извините, я неправильно понял, я думал, что это был .so из вашего собственного проекта, а не из внешних источников. Как действовать сейчас ... это немного по моим возможностям, я боюсь. Возможно, поскольку OpenFoam является openource, я бы загрузил источник и отлаживал его. – motoDrizzt

+0

У меня есть код, но он очень сложный, и я не привык к C++. Так что * отладка * легче сказать, чем сделать, как я заметил :( – EverythingRightPlace

Смежные вопросы