Советы по устранению ошибок сегментации при отсутствии утечек - PullRequest
4 голосов
/ 20 декабря 2011

Я написал приложение на C, которое работает нормально, за исключением очень больших наборов данных в качестве входных данных.

При большом входе я получаю ошибку сегментации на последних шагах функциональности двоичного файла.

Я запустил двоичный файл (с тестовым вводом) с помощью valgrind:

valgrind --tool=memcheck --leak-check=yes /foo/bar/baz inputDataset > outputAnalysis

Эта работа обычно занимает несколько часов, но с valgrind это заняло семь дней.

К сожалению, на данный момент я не знаю, как прочитать результаты, полученные от этого прогона.

Я получаю много таких предупреждений:

...
==4074== Conditional jump or move depends on uninitialised value(s)                                                                                                                  
==4074==    at 0x435900: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x439CC5: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x400BF2: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x402086: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x402A0F: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x41684F: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x4001B8: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x7FEFFFF57: ???                                                                                                                                                      
==4074==  Uninitialised value was created                                                                                                                                            
==4074==    at 0x461D3A: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x43F926: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x416B9B: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x416725: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x4001B8: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x7FEFFFF57: ???
...

Нет частей кода, на которые намекают, нет имен переменных и т. Д. Что я могу сделать с этой информацией?

В конце я, наконец, получаю следующую ошибку, но - как и в случае небольших наборов данных, которые не дают сбоя - valgrind не находит утечек:

...
==4074== Process terminating with default action of signal 11 (SIGSEGV)                                                                                                              
==4074==  Access not within mapped region at address 0x7158E7F7                                                                                                                      
==4074==    at 0x7158E7F7: ???                                                                                                                                                       
==4074==    by 0x4020B8: ??? (in /foo/bar/baz)                                                                                   
==4074==    by 0x6322203A22656D6E: ???                                                                                                                                               
==4074==    by 0x306C675F6E557267: ???                                                                                                                                               
==4074==    by 0x202C22373232302F: ???                                                                                                                                               
==4074==    by 0x6D616E656C696621: ???                                                                                                                                               
==4074==    by 0x72686322203A2264: ???                                                                                                                                               
==4074==    by 0x3030306C675F6E54: ???                                                                                                                                               
==4074==    by 0x346469702E373231: ???                                                                                                                                               
==4074==    by 0x646469662E34372F: ???                                                                                                                                               
==4074==    by 0x722E64616568656B: ???                                                                                                                                               
==4074==    by 0x63656D6F6C756764: ???                                                                                                                                               
==4074==  If you believe this happened as a result of a stack                                                                                                                        
==4074==  overflow in your program's main thread (unlikely but                                                                                                                       
==4074==  possible), you can try to increase the size of the                                                                                                                         
==4074==  main thread stack using the --main-stacksize= flag.                                                                                                                        
==4074==  The main thread stack size used in this run was 10485760.                                                                                                                  
==4074==                                                                                                                                                                             
==4074== HEAP SUMMARY:                                                                                                                                                               
==4074==     in use at exit: 0 bytes in 0 blocks                                                                                                                                     
==4074==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated                                                                                                                    
==4074==                                                                                                                                                                             
==4074== All heap blocks were freed -- no leaks are possible                                                                                                                         
==4074==                                                                                                                                                                             
==4074== For counts of detected and suppressed errors, rerun with: -v                                                                                                                
==4074== ERROR SUMMARY: 1603141870 errors from 86 contexts (suppressed: 0 from 0)
Segmentation fault

Все, для чего я выделяю пространство, получает эквивалентный оператор free, после чего я устанавливаю указатели на NULL.

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


22 декабря 2011 г. - Изменить

Я скомпилировал отладочную версию моего бинарного файла под названием debug-binary, используя следующие флаги компиляции:

-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -DUSE_ZLIB -g -O0 -Wformat -Wall -pedantic -std=gnu99

Когда я запускаю его с valgrind, я не получаю намного больше информации:

valgrind -v --tool=memcheck --leak-check=yes --error-limit=no --track-origins=yes debug-binary input > output

Вот фрагмент вывода:

==25116== 2 errors in context 14 of 14:                                                                                                                                                                                                      
==25116== Invalid read of size 4                                                                                                                                                                                                             
==25116==    at 0x4045E8: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x40682F: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x404F0C: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x401FA4: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x402016: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x403B27: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x40295E: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x31A021D993: (below main) (in /lib64/libc-2.5.so)                                                                                                                                                                           
==25116==  Address 0x539f188 is 24 bytes inside a block of size 48 free'd                                                                                                                                                                    
==25116==    at 0x4A05D21: free (vg_replace_malloc.c:325)                                                                                                                                                                                    
==25116==    by 0x401F6B: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x402016: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x403B27: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x40295E: ??? (in /foo/bar/debug-binary)                                                                                                                                 
==25116==    by 0x31A021D993: (below main) (in /lib64/libc-2.5.so) 

Это проблема с моим двоичным файлом или с системной библиотекой (libc), от которой зависит мое приложение?

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

Ответы [ 3 ]

6 голосов
/ 20 декабря 2011

Valgrind в основном говорит, что нет заметных проблем с управлением кучей.Программа происходит из-за менее сложной ошибки программирования.

Если бы это был я, я бы

  • скомпилировал бы ее с включением gcc -g,
  • файлы дампа основной памяти (ulimit -c unlimited),
  • , нормально запускают программу,
  • и дают ей ошибку
  • используют gdb, чтобы проверить файл ядра и посмотреть, что этоделал, когда он отказывал:

    gdb (программный файл) (основной файл)
    bt

4 голосов
/ 20 декабря 2011

Я не верю, что valgrind может найти все ошибки, когда вы переполнили значение в стеке (но не переполнили сам стек).Итак, вы можете попробовать опцию gcc -f-stack-protector-all.

Вам также следует попробовать mudflap с -fmudflap (однопоточным) или -fmudflapth (многопоточным).

И грязевой флаг, и защита стека должны быть на намного быстрее, чем valgrind.

Кроме того, похоже, что у вас нет отладочных символов, что затрудняет чтение обратных трасс.Добавить -ggdb.Вы, вероятно, также хотите включить генерацию файла ядра (попробуйте ulimit -c unlimited).Таким образом, вы можете попытаться отладить процесс после сбоя, используя gdb program core.

Как указывает @wallyk, ваш segfault может быть довольно просто найти - например, вы можете разыменовать NULL,и GDB может указать вам точную строку (или, ну, в общем, закрыть, если вы не скомпилируете с -O0).Это имело бы смысл, например, если вы просто используете память для своих больших наборов данных и, таким образом, malloc возвращает NULL, и вы забыли проверить это где-то.

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

2 голосов
/ 20 декабря 2011

«Условный переход или перемещение зависит от неинициализированного значения» - серьезная ошибка, которую необходимо исправить. Это указывает на то, что на поведение вашей программы влияет содержимое неинициализированной переменной (включая область неинициализированной памяти, возвращаемую malloc()).

Чтобы получить читаемые следы от valgrind, вам нужно скомпилировать с -g.

...