Подтвердить что ты не робот

Решение случайных сбоев

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

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

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

EDIT: Многие люди упомянули, что... как я делаю основной сброс, minidump или whatdump? Это первый раз, когда мне нужна отладка postmortem.

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

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

4b9b3361

Ответ 1

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

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

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

Memcheck часть пакета - это, вероятно, место для запуска:

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

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

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

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

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

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

Ответ 2

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

Вот как вы продолжаете.

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

Получить сбой аварийной ситуации

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

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

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

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

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

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

Рассмотрение множественных сбоев и разделение разделов кода, которые обычно являются активными во всех авариях, является реальной экономией времени.

Проверка состояния затяжки

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

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

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

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

Repeat

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

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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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

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

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

Ответ 9

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

И для Windows: Существует отладчик JIT для mingw, называемый DrMingw:

Ответ 10

Это звучит как нечто сложное, как состояние гонки.

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

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

Ответ 11

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

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

Ответ 12

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

  • Положите все на себя!

  • Пока вы на нем, только поставьте одно выражение в assert.

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

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

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

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

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

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

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

Ответ 13

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

Ответ 14

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

Также для Windows ознакомьтесь с Microsoft Инструменты отладки для Windows, и особенно их gflags.

Ответ 15

Здесь есть много хороших ответов, но никто еще не коснулся угла Луа.

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

Одна легкая вещь, которую вы можете сделать, обнаружит многие такие ошибки, чтобы определить макрос lua_assert в luaconf.h. Определение этого (например, стандартного утверждения C) позволит провести множество проверок здравомыслия внутри ядра Lua.

Ответ 16

Еще два указателя/идеи (помимо основного дампа и valgrind в Linux):

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

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

Ответ 17

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