Факт сбоя в работе сразу нескольких программ насторожил меня уже
по-настоящему. Поскольку ЦП в моей системе работал на повышенных частотах, я
начал грешить на перегрев процессора и другие побочные эффекты разгона, после
чего с великой неохотой вернул множитель ЦП к заводским значениям. Сделав это я
с ужасом убедился в том, что глюки не прекратились. Следующим пунктом в
программе подозрений значились дефекты RAM, но выявить проблему при помощи
Windows Vista Memory Diagnostic мне так и не удалось.
Поэтому, когда выяснилось, что железо здесь не причем, я подумал, что стоит
взглянуть на дамп процесса, который приводит к сбою, чтобы определить в чем же
причина бага. И я стал его искать. Встроенное в Windows XP системное приложение
Application Error Reporting, прежде чем выдать сообщение об аварийном
прекращении работы приложения, всегда создает дамп процесса, местоположение
которого можно посмотреть, кликнув по ссылке на диалоговом окне сообщения и
изучив техническую информацию, содержащуюся в отчете:
Аналогичное окно в Windows Vista, к сожалению, уже не предлагает ознакомиться
с детальной информацией, связанной с вылетом и не делает снимка аварийного
приложения, если не получит на это соответствующего запроса службы Microsoft
Windows Error Reporting (WER). К счастью, WerFault, процесс, который отвечает за
вывод на экран сообщения об ошибке, сохраняет детали о сбойном процессе до тех
пор, пока ты не нажмешь на кнопку Close Program, что, в принципе, позволяет
воспользоваться отладчиком для изучения этого процесса. Доказательство того, что
за вывод сообщения о сбое в Windows Media Player отвечает именно WerFault,
приведено на расположенном ниже скриншоте из Process Explorer:
Когда случился очередной вылет приложения, я запустил WinDbg, отладчик
Windows из пакета утилит
Debugging Tools for Windows, который можно бесплатно скачать с сайта
Microsoft. Убедившись, что в диалоговом окне Symbol File Path этого отладчика
установлен правильный путь к публичному серверу символов Microsoft (к примеру,
вот такой: srv*c:\symbols*http://msdl.microsoft.com/download/symbols), я перешел
к меню File и выбрал пункт под названием "Attach to a Process...":
Выбор этого пункта в WinDbg приводит к диалоговому окну выбора процесса,
приведенный в котором список я и начал пролистывать для того, чтобы найти
вылетающий процесс. Обнаружив его, я открыл этот процесс в WinDbg и встретил все
тот же интерфейс, который можно увидеть в Windows XP при просмотре сохраненного
дампа, только в WinDbg есть еще дополнительная возможность исполнения встроенной
команды !analyze, которую можно выполнить во время загрузки сбойного процесса.
Эта команда запускает эвристический анализ при помощи которого можно попытаться
определить причину сбоя. Хотя, если ты прикрепляешь отладчик к какому-то
определенному процессу, эта функция тебе вряд ли будет полезна, поскольку
расскажет о том, что ты уже и так знаешь.
Для поиска возможной причины неисправности требуется просмотр стека каждого
потока в процессе, поэтому я открыл необходимые мне соответствующие диалоговые
окна Processes and Threads и Call Stack в меню View:
Изучение потоков я начал с выбора первого пункта в списке диалогов:
Окно WinDbg во время запроса обычно становится серым и отображает слово
"Busy", поскольку в этот момент WinDbg получает информацию от службы символов,
после чего появляется окно стека, в котором содержится указание на процесс, в
рамках которого на момент сбоя был запущен выбранный поток. Я по очереди
проверил стек каждого потока, переключаясь между ними при помощи стрелок и
клавиши Enter. Целью моей охоты было найти процесс или функцию, в названии
которых содержатся такие слова, как "exception" или "fault". И ближе к самому
концу списка такой процесс мне все-таки удалось обнаружить:
Я заметил, что верхняя часть списка полна функций, содержащих в своем
названии слово "Exception". Просматривая список по направлению к началу стека, я
добрался и до причины проблемы, ею оказалась функция в Nvappfilter вызываемая из
Kernel32.dll под названием HeapFree. Исключение при выполнении какой-нибудь
типичной операции в HeapFree означало либо обращение к фиктивному адресу кучи,
либо то, что во время выполнения функции куча уже была повреждена. Можно было бы
предположить, что источником вызова процедуры служит системная DLL Windows,
однако WinDbg не смог предоставить информацию об именах функций с сервера
символов Microsoft, и я подумал, что это, вероятнее всего, какая-то сторонняя
DLL. Впоследствии мне удалось подтвердить свою догадку при помощи команды lm
(list module), позволившей просмотреть информацию о версии.
Nvappfilter теперь претендовал на роль главного подозреваемого, но прямых
доказательств его вины у меня все еще не было. Я продолжил работать на
компьютере и проделывал аналогичные вышеописанным мероприятия каждый раз, когда
происходили сбои. Обнаружилось, что стек потоков практически идентичен вне
зависимости от того, какое приложение выпадает (IE, WMP или игра) и всегда
содержит Nvappfilter, запускающую HeapFree. Исчерпывающих улик все еще не было,
но связь между сбоями и этой dll прослеживалась совершенно четко.
Выявив ее, я решил проверить возможное наличие обновлений для Nvappfilter, но
у меня не было четкого представления о том, к какому набору программных средств
она принадлежит. Введя ее имя и воспользовавшись интернет-поиском, я установил,
что данная библиотека является частью пакета FirstPacket, разработанного nVidia
для того, чтобы поднять приоритет обработки данных, создаваемых играми. Этот
пакет входит в состав программного обеспечения для материнских плат на базе
nForce:
Я перешел на сайт nVidia и скачал самую свежую версию драйверов для nForce,
но обновить таким образом Nvappfilter.dll мне не удалось, и вылеты никуда не
исчезли.
Панель управления nVidia не предлагает никаких инструментов, при помощи
которых можно было бы остановить загрузку Nvappfilter, поэтому единственной
возможностью сделать это было отключение данной dll вручную. Поскольку функции
пакета FirstPacket мне были не нужны, а его отсутствие не причинило бы мне
неудобств, я взялся за изучение того, за счет чего этот программный пакет
подгружает себя в системе. Для того, чтобы это выяснить, я воспользовался
Autoruns, с помощью которой и обнаружил ссылки на 32-х и 64-битные версии
Nvappfilter в разделе Winsock Layered Service Provider (LSP):
Я удалил все записи, связанные с Nvappfilter, перезагрузил машину, и после
этого уже не испытывал никаких проблем с вылетами. Во время написания данной
статьи я еще раз проверил пакет драйверов для nForce на предмет наличия в них
обновленных версий Nvappfilter. Насколько мне удалось понять, последние версии
этого ПО вообще не содержат Nvappfilter или каких-то других компонентов Winsock
LSP, поэтому, похоже, проблема больше не актуальна.
В заключение отмечу, что после проведения расследования я начал пользоваться
функциональностью, предлагаемой пакетом SP1 для Vista. Она позволяет мне
делать автоматические дампы любого сбоя, с которым мне приходится
сталкиваться. Создав в реестре ключ HKLM\Software\Microsoft\Windows\Windows
Error Reporting\LocalDumps, при помощи WerFault у тебя всегда будет возможность
сохранить дамп. Путь сохранения по умолчанию - %LOCALAPPDATA%\Crashdumps, однако
его можно изменить, внеся соответствующие исправления в Реестре. Также можно
управлять и максимальным числом сохраняемых дампов.
Источник:
http://blogs.technet.com/markrussinovich/
|