GDB предотвращает ошибки - PullRequest
       0

GDB предотвращает ошибки

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

Я получил эту проблему на разных проектах C при использовании gdb. Если я запускаю свою программу без нее, она последовательно падает при заданном событии, вероятно, из-за неправильного чтения памяти. Я пытаюсь отладить его с помощью gdb, но при этом сбой, кажется, никогда не происходит!

Есть идеи, почему это могло произойти?

Я использую mingw набор инструментов для Windows.

Ответы [ 4 ]

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

Да, это звучит как состояние гонки или повреждение кучи или что-то еще, что обычно отвечает за Гейзенбагов.Проблема в том, что ваш код в некотором месте, вероятно, неверен, но отладчик должен вести себя, даже если отлаженное приложение делает забавные вещи.Таким образом, проблемы, как правило, исчезают при отладчике.А для условий гонки они часто не появляются в первую очередь, потому что некоторые отладчики могут обрабатывать только один поток за раз, и равномерно все отладчики заставят код работать медленнее, что может уже привести к исчезновению условий гонки.

Попробуйте Valgrind в приложении.Поскольку вы используете MinGW, есть вероятность, что ваше приложение будет компилироваться в среде, в которой может работать Valgrind (даже если он не запускается непосредственно в Windows).Я использую Valgrind уже около трех лет, и он быстро разгадал множество загадок.Первое, когда я получу отчет о сбое в коде, с которым я работаю (который работает на AIX, Solaris, BSD, Linux, Windows), я собираюсь сделать один тестовый запуск кода под Valgrind в x64 и x86 Linuxсоответственно.

Valgrind, и в вашем конкретном случае его инструмент по умолчанию Memcheck, будет эмулировать код.Всякий раз, когда вы выделяете память, она будет помечать все байты в этой памяти как «испорченные», пока вы не инициализируете ее явно.Загрязненное состояние байтов памяти будет унаследовано неинициализированной памятью memcpy и приведет к отчету от Valgrind, как только неинициализированный байт будет использован для принятия решения (if, for, while...).Кроме того, он отслеживает потерянные блоки памяти и сообщит об утечках в конце цикла.Но это еще не все, больше инструментов являются частью семейства Valgrind и тестируют различные аспекты вашего кода, включая условия состязания между потоками (Helgrind, DRD).

Предполагая, что Linux сейчас: убедитесь, что у вас есть все отладкисимволы ваших вспомогательных библиотек установлены.Обычно они входят в *-debug версию пакетов или *-devel.Также обязательно отключите оптимизацию в своем коде и включите символы отладки.Для GCC это -ggdb -g3 -O0.

Еще один совет: у меня было то, что наложение указателей вызвало некоторое горе.Хотя Valgrind смог помочь мне отследить его, мне фактически пришлось сделать последний шаг и проверить созданный код при его разборке.Оказалось, что на -O3 оптимизатор GCC опередил себя и превратил цикл копирования байтов в последовательность инструкций для одновременного копирования 8 байтов, но предполагал выравнивание .Последняя часть была проблемой.Предположение о выравнивании было неверным.С тех пор мы начали строить на -O2 - что, как вы увидите в этой статье Gentoo Wiki , не является худшей идеей.Процитируем соответствующую часть…

-O3: это максимально возможный уровень оптимизации, а также самый рискованный.Скомпилирование вашего кода с этой опцией займет больше времени, и фактически его не следует использовать для всей системы с gcc 4.x.Поведение gcc значительно изменилось с версии 3.x.В 3.x было показано, что -O3 приводит к немного более быстрому времени выполнения по сравнению с -O2, но это больше не относится к gcc 4.x.Компиляция всех ваших пакетов с -O3 приведет к большим бинарным файлам, которые требуют больше памяти, и значительно увеличит шансы сбоя компиляции или неожиданного поведения программы (включая ошибки).Недостатки перевешивают выгоды;помните принцип убывающей отдачи.Использование -O3 не рекомендуется для gcc 4.x.

Поскольку вы используете GCC в MinGW, я считаю, что это вполне может относиться и к вашему делу.

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

Есть идеи, почему это могло произойти?

Есть несколько обычных причин:

  1. Ваше приложение имеет несколько потоков, имеет состояние гонки, и запуск под GDB влияет на время таким образом, что сбой больше не происходит
  2. В вашем приложении есть ошибка, на которую влияет макет памяти (часто чтение неинициализированной памяти), и макет изменяется при работе в GDB.

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

1 голос
/ 20 июня 2014

Хотя уже немного поздно, можно прочитать этот ответ на вопрос, чтобы можно было настроить систему для перехвата coredump без использования gdb. Затем он может загрузить файл ядра, используя

gdb <path_to_core_file> <path_to_executable_file>

, а затем выдать

thread apply all bt

в ГБД.

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

0 голосов
/ 02 декабря 2011

Ваше приложение, вероятно, получает сигналы, и GDB может не передавать их в зависимости от его конфигурации.Вы можете проверить это с помощью информационных сигналов или команды info handle.Это также может помочь опубликовать трассировку стека сбойного процесса.Сбой процесса должен генерировать файл ядра (если он не был отключен), который можно проанализировать с помощью gdb.

...