Устранение случайных сбоев

Я получаю случайные сбои в моем приложении C ++, оно может не падать в течение месяца, а затем аварийно завершать работу 10 раз в час, а иногда может произойти сбой при запуске, а иногда может произойти сбой после нескольких часов работы (или вообще не произойти сбой).

Я использую GCC в GNU / Linux и MingW в Windows, поэтому я я не могу использовать отладку JIT в Visual Studio ...

Я понятия не имею, как поступить, случайный взгляд на код не сработает, код ОГРОМНЫЙ (и хорошая часть не была моей работой, также на нем есть много хорошего материала), и я также не знаю, как воспроизвести аварию.

РЕДАКТИРОВАТЬ: Многие люди упоминали, что ... как я делаю дамп ядра, мини-дамп или еще что? Это первый раз, когда мне нужна посмертная отладка.

EDIT2: На самом деле, DrMingw перехватил стек вызовов, без информации о памяти ... К сожалению, стек вызовов мне не сильно помог, потому что ближе к концу он внезапно перешел в какой-то момент. библиотека (или что-то), что у меня нет отладочной информации, приводящей только к некоторым шестнадцатеричным числам ... Так что мне все еще нужен приличный дамп, который дает больше информации (особенно о том, что было в памяти ... в частности, что было в место, которое выдало ошибку «нарушение прав доступа»)

Кроме того, мое приложение использует Lua и Luabind, возможно, ошибка вызвана скриптом .lua, но я понятия не имею, как это отладить.

35
задан speeder 11 August 2010 в 05:30
поделиться

15 ответов

Попробуйте Valgrind (бесплатно, с открытым исходным кодом):

В настоящее время дистрибутив Valgrind включает шесть инструментов производственного качества: детектор ошибок памяти, два потока детекторы ошибок, кеш и профайлер предсказания ветвлений, a профилировщик кеша, генерирующий граф вызовов, и профилировщик кучи. Он также включает два экспериментальных инструмента: переполнение кучи / стека / глобального массива детектор и базовый блок SimPoint векторный генератор. Он работает на следующие платформы: X86 / Linux, AMD64 / Linux, PPC32 / Linux, PPC64 / Linux, и X86 / Darwin (Mac OS X).

Valgrind Часто задаваемые вопросы

Часть пакета Memcheck , вероятно, является местом для начала:

Memcheck - это детектор ошибок памяти. Он может обнаружить следующие проблемы которые распространены в программах на C и C ++.

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

  • Использование неопределенных значений, т.е. значений, которые не были инициализированы, или которые были получены из других неопределенные значения.

  • Неправильное освобождение памяти кучи, например двойное освобождение блоков кучи, или несоответствующее использование malloc / new / new [] по сравнению с free / delete / delete []

  • Перекрытие указателей src и dst в memcpy и связанных функциях.

  • Утечка памяти.

29
ответ дан 27 November 2019 в 06:31
поделиться

Если ваше приложение не предназначено для Windows, вы можете попробовать скомпилировать и запустить свою программу на других платформах, таких как Linux (другой дистрибутив, 32/64 бит, ... если у вас есть роскошь ). Это может помочь вызвать ошибки в вашей программе. Конечно, вам следует использовать инструменты, упомянутые в других сообщениях, такие как gdb, valgrind и т. Д.

0
ответ дан 27 November 2019 в 06:31
поделиться

Еще две подсказки/идеи (помимо core dump и valgrind в Linux):

1) Попробуйте Nokia's "Qt Creator". Он поддерживает mingw и может работать как посмертный отладчик.

2) Если это осуществимо, может быть, просто постоянно запускать приложение в gdb?

0
ответ дан 27 November 2019 в 06:31
поделиться

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

1
ответ дан 27 November 2019 в 06:31
поделиться
  1. Начните протоколирование. Поместите операторы протоколирования в те места, где, по вашему мнению, код нестабилен. Сосредоточьтесь на тестировании кода и повторяйте, пока не сузите проблему до модуля или функции.

  2. Ставьте утверждения везде!

  3. Пока вы это делаете, помещайте в утверждение только одно выражение.

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

  5. Напишите больше автоматизированных тестов, которые проверяют проблемный код.

  6. Не добавляйте больше кода поверх плохого кода, который дает сбой. Это просто глупая идея.

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

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

  9. Используйте отладочную сборку. По возможности запускайте отладочную сборку под отладчиком.

  10. Уменьшите ваше приложение, удалив двоичные файлы, модули и т.д., если это возможно, чтобы вам было легче воспроизвести ошибку.

3
ответ дан 27 November 2019 в 06:31
поделиться

Звучит как нечто сложное, вроде состояния гонки.

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

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

3
ответ дан 27 November 2019 в 06:31
поделиться

Первое, что я хотел бы сделать, это отладить дамп ядра с помощью gdb ( как Windows, так и Linux). Второй будет запускать такую ​​программу, как Lint, Prefast (Windows), Clang Analyzer или какую-либо другую программу статического анализа (будьте готовы к множеству ложных срабатываний). В-третьих, это какая-то проверка времени выполнения, такая как Valgrind (или его близкие варианты), Microsoft Application Verifier или Google Perftools .

И логирование. Который не обязательно должен идти на диск. Вы можете, например, войти в глобальный std :: list , который будет сокращен до последних 100 записей. При обнаружении исключения отобразите содержимое этого списка.

3
ответ дан 27 November 2019 в 06:31
поделиться

. Вы уже слышали, как с этим справиться в Linux: проверьте дампы ядра и запустите свой код под valgrind. Итак, первым делом вы можете найти ошибки в Linux, а затем проверить, исчезают ли они в mingw. Поскольку здесь никто не упоминал грязевик , я сделаю это: используйте грязевик, если ваш дистрибутив Linux предоставляет его. Mudflap помогает вам обнаруживать неправильное использование указателя и переполнение буфера, отслеживая информацию, в которой указатель действительно может указывать на:

И для Windows: Для mingw существует JIT-отладчик DrMingw:

4
ответ дан 27 November 2019 в 06:31
поделиться

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

Существует отличный инструмент под названием Process Dumper , который можно использовать для получения аварийного дампа процесса, в котором возникла исключительная ситуация или который неожиданно завершился - вы можете попросить пользователей установить его и настроить правила для вашего приложения. .

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

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

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

6
ответ дан 27 November 2019 в 06:31
поделиться

Похоже, ваша программа страдает от повреждения памяти. Как уже было сказано, лучшим вариантом для Linux, вероятно, является valgrind. Но вот еще два варианта:

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

  • Возможно, вам стоит взглянуть на VMWare Workstation. Я не настраивал его таким образом, но из своих маркетинговых материалов они поддерживают довольно интересный способ отладки: запустить отладчик на «записывающей» виртуальной машине. Когда происходит повреждение памяти, установите точку останова памяти на поврежденном адресе, а затем верните время в виртуальную машину точно к тому моменту, когда эта часть памяти была перезаписана. См. этот PDF-файл о том, как настроить отладку воспроизведения с помощью Linux / gdb. Я считаю, что для Workstation 7 существует 15 или 30-дневная демонстрация, которой может быть достаточно, чтобы избавиться от этих ошибок в вашем коде.

6
ответ дан 27 November 2019 в 06:31
поделиться

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

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

8
ответ дан 27 November 2019 в 06:31
поделиться

Запустите программу под отладчиком (я уверен, что есть отладчик вместе с GCC и MingW) и подождите, пока она не выйдет из строя под отладчиком. В момент сбоя вы сможете увидеть, какое конкретное действие завершается ошибкой, изучить код сборки, регистры, состояние памяти - это часто поможет вам найти причину проблемы.

8
ответ дан 27 November 2019 в 06:31
поделиться

Если ничего не помогает (особенно если производительность в отладчике неприемлема), подробное ведение журнала. Начните с точек входа - является ли приложение транзакционным? Регистрируйте каждую транзакцию по мере ее поступления. Регистрируйте все вызовы конструктора для ваших ключевых объектов. Поскольку сбой настолько прерывистый, вызовы всех функций, которые могут вызываться не каждый день, записываются в журнал.

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

14
ответ дан 27 November 2019 в 06:31
поделиться

Запустите приложение на Linux под valgrind для поиска ошибок памяти. Случайные сбои обычно связаны с повреждением памяти.

Исправьте каждую найденную ошибку с помощью инструмента valgrind's memcheck, и тогда, надеюсь, крах исчезнет.

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

Если этого не произойдет, убедитесь, что coredumps включен (ulimit -a), а затем, когда произойдет сбой, вы сможете найти его с помощью gdb.

4
ответ дан 27 November 2019 в 06:31
поделиться

Во-первых, вам повезло, что ваш процесс дает сбой несколько раз за короткий промежуток времени. Это должно упростить работу.

Вот как вы поступите.

  • Получить аварийный дамп
  • Изолировать набор потенциально подозрительных функций
  • Усилить проверку состояния
  • Повторить

Получить аварийный дамп

Во-первых, вам действительно нужно получить аварийный дамп.

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

Перекомпилируйте двоичный файл с отладочными символами или убедитесь, что вы можете проанализировать аварийный дамп с отладочными символами.

Найдите подозрительные функции

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

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

Просмотр нескольких сбоев и изоляция участков кода, которые обычно активны во всех сбоях, позволяют сэкономить время.

Усиление проверки состояния

Сбой обычно происходит из-за несогласованного состояния. Лучше всего ужесточить государственные требования. Вы делаете это следующим образом.

Для каждой функции, которая, по вашему мнению, может вызвать проблему, задокументируйте, какое правовое состояние должен иметь вход или объект при входе в функцию.(Сделайте то же самое для того, какое правовое состояние должно быть при выходе из функции, но это не слишком важно).

Если функция содержит цикл, задокументируйте юридическое состояние, которое она должна иметь в начале каждой итерации цикла.

Добавить утверждения для всех таких выражений правового государства.

Повторить

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

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

15
ответ дан 27 November 2019 в 06:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: