Предсказуемый код завершения аварийного процесса в Windows

Для процесса, обычно завершающего работу в Windows, код завершения процесса обычно является либо возвращаемым значением из mainили код выхода передан std::exit, %ERRORLEVEL% затем может быть использован для запроса кода выхода, и это может быть использовано для определения, правильно ли выполнялась программа, или были какие-то исключительные входы / сбои, которые указывают на конкретную проблему (специфическую для приложения).

Тем не менее, я заинтересован в коде выхода, если процесс падает. Возьмем очень простой пример программы:

int main()
{
int * a = nullptr;
*a = 0xBAD;
return 0;
}

Когда я компилирую это и запускаю в Windows, в командной строке я получаю:

MyCrashProgram.exe -> crashes
echo %ERRORLEVEL%  -> -1073741819

Код выхода соответствует этому номеру. Что приводит меня к нескольким вопросам:

  • Был код выхода -1073741819 как-то предсказуемо, основано на сбое неправильной записи?
  • Если да, есть ли способ определить тип сбоя, основываясь на коде выхода?
  • Меняется ли это в зависимости от используемого компилятора (я использовал MSVC 2012)?
  • Меняется ли это в зависимости от используемой версии Windows (я использовал Win10 TP)?
  • Меняется ли это с архитектурой (например, x64 — я использовал Win32)?

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

5

Решение

Комментарий о STATUS_ACCESS_VIOLATIONпривел меня к документации по GetExceptionCode:

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

EXCEPTION_ACCESS_VIOLATION карты для STATUS_ACCESS_VIOLATION в списке, который следует. Все исключения в списке с префиксом STATUS прямо определены для кодов исключений с префиксом EXCEPTION, Следуя документации к RaiseException, он объясняет процесс попытки отладки исключения, когда оно происходит, последний шаг:

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

Итак, чтобы ответить на мои вопросы:

  • Да, код выхода был предсказуем, он отображается на EXCEPTION_STATUS_VIOLATION,
  • Другие типы ошибок будут сопоставлены с другими распространенными кодами исключений. Однако при вызове RaiseException с произвольным кодом исключения (который был необработан), код выхода процесса может быть любым
  • Код выхода зависит от Windows SDK, а не от компилятора, выполняющего версию или архитектуру Windows. Хотя это теоретически может измениться с более новыми Windows SDK, это очень маловероятно для обратной совместимости.
4

Другие решения

Вот связанный короткое сообщение в блоге Раймонда Чена (выделение мое):

Не существует стандарта для кодов завершения процесса. Вы можете передать все, что вы
хочу ExitProcess, и это то, что даст GetExitCodeProcess
назад. Ядро не интерпретирует значение. Если хочешь
код 42, чтобы означать «что-то бесконечно невероятное произошло» тогда
больше силы для вас.

Однако существует соглашение, что нулевой код выхода означает
успех (хотя то, что составляет «успех», оставлено на усмотрение
автора программы) и ненулевой код выхода означает сбой
(опять же, с подробностями, оставленными на усмотрение программиста). Часто,
более высокие значения для кода выхода указывают на более серьезные типы ошибок.
Ключевое слово ERRORLEVEL процессора команды было разработано с этими
конвенция в виду.

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

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

2

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

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

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

Посмотрите этот вопрос для получения подробной информации о различных видах ошибок в Windows:
Поймать исключения нарушения прав доступа

Вот еще одна тема для обработка сигналов в Linux

0
По вопросам рекламы [email protected]