Необработанные исключения
У всех потоков Windows имеется обработчик исключений, который занимается необработанными исключениями. Этот обработчик исключений объявляется внутренней Windows-функцией запуска потока (start-of-thread).
Эта функция запускается, когда пользователь создает процесс или любые дополнительные потоки. Она вызывает процедуру запуска потока, предоставляющего среду в контекстной структуре исходного потока, которая, в свою очередь, вызывает предоставляемую пользователем процедуру запуска потока, указанную в вызове CreateThread.
Просмотр реального пользовательского стартового адреса для Windows-потоков.
Тот факт, что каждый Windows-поток начинает свое выполнение с функции, предоставляемой системой (а не пользователем), объясняет, почему стартовый адрес для потока 0 одинаков для каждого Windows-процесса, имеющегося в системе (и почему стартовые адреса для вторичных потоков также одинаковы). Для просмотра адреса функции, предоставленной пользователем, нужно воспользоваться средством Process Explorer или отладчиком ядра.
Поскольку большинство потоков в Windows-процессах берут начало в одной из предоставленных системой функциях-оболочках, Process Explorer при отображении стартового адреса потока в процессе пропускает исходный фрейм вызова, представляющий функцию-оболочку, и вместо него показывает второй фрейм в стеке. Например, обратите внимание на стартовый адрес потока того процесса, в котором запущена программа Notepad.exe.
Process Explorer при выводе стека вызовов выводит полную иерархию вызовов. Обратите внимание на следующие результаты, появляющиеся после щелчка на кнопке Stack.
В строке 18 предыдущей копии экрана показан первый фрейм стека — стартовый адрес внутренней оболочки потока. Второй фрейм (строка 17) представляет собой оболочку потока подсистемы окружения — в данном случае kernel32, поскольку вы имеете дело с приложением подсистемы Windows. Третий фрейм (строка 16) представляет собой основную точку входа в Notepad.exe.
Общий код для стартовых функций внутреннего потока имеет следующий вид:
VOID RtlUserThreadStart(VOID)
{
LPVOID lpStartAddr = (R/E)AX; // Located in the initial thread context structure
LPVOID lpvThreadParam = (R/E)BX; // Located in the initial thread context structure
LPVOID lpWin32StartAddr;
lpWin32StartAddr = Kernel32ThreadInitThunkFunction ? Kernel32ThreadInitThunkFunction
: lpStartAddr;
__try
{
DWORD dwThreadExitCode = lpWin32StartAddr(lpvThreadParam);
RtlExitUserThread(dwThreadExitCode);
}
__except(RtlpGetExceptionFilter(GetExceptionInformation()))
{
NtTerminateProcess(NtCurrentProcess(), GetExceptionCode());
}
}
VOID Win32StartOfProcess(
LPTHREAD_START_ROUTINE lpStartAddr,
LPVOID lpvThreadParam)
{
lpStartAddr(lpvThreadParam);
}
Следует заметить, что фильтр необработанных исключений Windows вызывается в том случае, если у потока есть такое необработанное исключение. Цель данной функции заключается в предоставлении системно-независимого поведения при наличии необработанного исключения, которое выражается в запуске процесса WerFault.exe. Но в исходной конфигурации служба Windows Error Reporting, которая будет рассмотрена далее, обработает исключение, и этот фильтр необработанных исключений не будет задействован ни при каких условиях.
WerFault.exe проверяет содержимое параметра реестра HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug и убеждается в том, что процесс не находится в списке исключений. В этом параметре есть два важных значения: Auto и Debugger. Значение Auto сообщает фильтру необработанных исключений, нужно ли автоматически запускать отладчик, или же следует спросить у пользователя, что нужно делать.
Установка таких средств разработки, как Microsoft Visual Studio, изменяет это значение, если оно уже установлено, на 0. (Если значение не установлено, то 0 является настройкой по умолчанию.) Значение Debugger является строкой, указывающей путь к исполняемому отладчику для его запуска в случае наличия необработанного исключения, и WerFault передает ID аварийного процесса и имя события сигналу при запуске отладчика в виде аргументов командной строки, используемой для его запуска.