Сбой приложения без объяснения причин - PullRequest
5 голосов
/ 07 марта 2011

Я хотел бы заранее извиниться, потому что это не очень хороший вопрос.

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

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

Каждый отдельный поток в приложении обернут в try/catch (...) (что-либо выброшенное из обработчика исключений / специально не перехвачено), __try/__except (структурированные исключения) и try/catch (конкретные исключения C ++). Приложение скомпилировано с / EHa, поэтому перехват всех также будет перехватывать структурированные исключения.

Все эти обработчики исключений делают одно и то же. Сначала создается аварийный дамп. Во-вторых, запись записывается в новый файл на диске. В-третьих, запись регистрируется в журналах приложений. В случае этих сбоев ничего этого не происходит . Самый нижний обработчик исключений (try/catch (...)) ничего не делает, он просто завершает поток. Основной поток приложения спит и не имеет возможности вызвать исключение.

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

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

Мы пытались запустить его с подключенным windbg (нет возможности использовать Visual Studio, слишком высокие накладные расходы), но он ничего не сообщил, когда произошел сбой.

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

Ответы [ 4 ]

7 голосов
/ 07 марта 2011

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

1) Генерируется исключение верхнего уровня, и для этого типа исключения нет соответствующего блока catch.

2) У вас есть соответствующий catch block (например, catch(...)), но вы генерируете исключение в этом обработчике.Когда это произойдет, Windows вырвет кости из вашей программы.Ваше приложение просто перестанет существовать.Дамп не будет сгенерирован, и практически ничего не будет записано. Это последняя попытка Windows не дать программе-мошеннику уничтожить всю систему.

Примечание о catch(...).Это явно зло.В рабочем коде (почти) никогда не должно быть catch(...).Люди, которые пишут catch(...), обычно утверждают одну из двух вещей:

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

-или-

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

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

Последний - благородный и надежный подход, но реализация его гораздо болееТрудно, что это может показаться, и это чревато опасностью.Проблема в том, что вы должны избегать генерации каких-либо дополнительных исключений в вашем обработчике исключений, и ваша машина уже находится в очень шатком состоянии.Операции, которые обычно совершенно безопасны, внезапно становятся ручными гранатами.new, delete, любые функции CRT, форматирование строк и даже выделение на основе стека, такие как char buf[256], могут заставить ваше приложение перейти> POOF <и исчезнуть.Вы должны предположить, что стек и куча лежат в руинах.Нет распределения безопасно.</p>

Кроме того, могут возникать исключения, которые блок catch просто не может перехватить, например, исключения SEH.По этой причине я всегда пишу обработчик необработанных исключений и регистрирую его в Windows через SetUnhandledExceptionFilter .В моем обработчике исключений я выделяю каждый байт, который мне нужен, через статическое распределение, даже до запуска программы.Лучшая (наиболее надежная) вещь, которую нужно сделать в этом обработчике, - запустить отдельное приложение, которое сгенерирует файл MiniDump извне вашего приложения.Тем не менее, вы можете создать MiniDump из самого обработчика, если вы очень осторожны и не вызываете какую-либо функцию CRT прямо или косвенно.По сути, если это не функция API, которую вы вызываете, она, вероятно, небезопасна.

1 голос
/ 08 марта 2011

Это не очень хороший ответ, но, надеюсь, он может вам помочь.

Я однажды столкнулся с этими симптомами, и, проведя несколько мучительных часов в поисках причины, я обнаружил забавную вещь о Windows(от MSDN ):

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

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

Есть некоторый технический фон в IsBadXxxPtr Рэймонда Чена, который действительно должен называться CrashProgramRandomly

1 голос
/ 07 марта 2011

Анализ памяти в обработчике сигналов

http://msdn.microsoft.com/en-us/library/xdkz3x12%28v=VS.100%29.aspx

1 голос
/ 07 марта 2011

Я видел сбои, подобные этим, происходящие из-за повреждения памяти. Запускали ли вы свое приложение в отладчике памяти, таком как Purify, чтобы выяснить, проливает ли это свет на потенциальные проблемные области?

...