Сегодня мы поговорим о проблеме достаточно широко распространенной. Темой нашего разговора будут ситуации, когда в штатно функционирующей системе внезапно зависает процесс. Данная проблема, как мне кажется, является знакомой для каждого технического специалиста и, в то же время, крайне неудобной, поскольку вероятных проблем зависания может быть множество. Зависания процесса случаются с завидной регулярностью на широком круге клиентских систем Microsoft, работающих на базе разнообразного аппаратного обеспечения. Никто не застрахован от ошибок, где-то их меньше, где то больше, но присутствуют они абсолютно везде. В серверных конфигурациях, где набор рабочего ПО жестко ограничен и, как правило, достаточно хорошо оттестирован, ошибки встречаются значительно реже. Противоположностью этого являются клиентские операционные системы, где политики требования к программному обеспечению более мягкие, да и спектр ПО, работающего в системе шире. Зачастую возникновение ошибки в коде программы ведет к сбою, который выражается в "падении" (внезапном закрытии) программы, либо зависании. Ну и самый, пожалуй, неприятный вид проблем, это когда процесс зависает либо падает внезапно и с довольно высокой регулярностью.
Давайте немного отклонимся от основной линии повествования и потеоретизируем на тему зависания процесса. Какова её природа? Почему каким причинам программа может зависнуть:
- Внутренняя причина: Ошибка разработчика/модификатора, допустившего ошибку в коде исполняемого модуля.
- Внешняя причина: Бесконечное ожидание внешнего события, являющееся причиной аппаратного сбоя либо исчерпания ресурсов системы; ошибка стороннего исполняемого модуля, влияющего на
процесс исполнения кода основной программы (вирус/антивирус/другое ПО, имеющее подобный функционал).
Пожалуй что все причины я сейчас перечислить не смогу, да оно и не надо. К чему я завел весь этот разговор? Дело в том, что недавно ко мне прилетела одна интересная заявка. Обращался пользователь, у которого периодически вис редактор Winword. Вис он абсолютно на разных стадиях, при редактировании файлов, содержащих большой объем, при создании новых файлов, при изменении маленьких файлов. Одним словом, никаких закономерностей в происходящем выявить пользователю не удавалось. Зависает процесс? Давайте принудительно завершим его и продолжим работу :) Да, действительно, процесс можно было просто убить, если бы это была "штучная" проблема, поскольку никто не застрахован от багов, и в пакетах Microsoft они время от времени всплывают в виде редчайших внезапных сбоев фактически "на отлаженных системах". Но неприятная отличительная особенность данного сбоя была в том, что сбой не был "редким", а происходил с завидной регулярностью, фактически уже на протяжении нескольких дней и по несколько в период рабочего времени.
Запустил Монитор ресурсов (resmon), увидел пустую цепочку ожидания. Значит, проблема, с большой вероятностью, все же внутри процесса, поэтому было принято решение впервые провести отладку зависшего процесса.
Настройка инструментов отладки
Установка Debugging Tools for Windows
Перед тем как приступить непосредственно к отладке зависшего процесса, нам потребуется установить инструментарий под названием Debugging Tools for Windows (DTW), который входит в состав Windows SDK. Процесс установки подробно описан в статье Установка Debugging Tools for Windows, Не упускайте из виду тот факт, что необходимо версия разрядности дистрибутива должна соответствовать разрядности Вашей операционной системы. По окончании инсталляции рабочие директории комплекта Debugging Tools for Windows будут следующими:
- Для версии x86: C:\Program Files (x86)\Debugging Tools for Windows (x86)
- Для версии x64: C:\Program Files\Debugging Tools for Windows (x64)
Но не исключено, что пути могут измениться в последующих версиях дистрибутива.
Настройка отладочных символов
Отладочные символы — информация, позволяющая использовать "символические" (понятные человеку) данные о бинарном файле, такие как имена процедур, функций и переменных, используемых в исходном коде программы.
В ситуации с 32-битным кодом я настоятельно рекомендую настраивать отладчик на работу с отладочными символами. В сети встречается мнение, что отладочные символы не нужны для вычисления сбойного драйвера/модуля (процесса, в контексте которого произошел сбой), но применительно к 32-битному коду часто наблюдал ситуацию, когда разбор стека отладчиком заканчивается результатами, далекими от истины. К тому же, при настроенных символах мы получаем дополнительную информацию по сбою и можем детальнее проанализировать, к примеру, стек вызовов момента сбоя на уровне процедур и функций.
Настроить отладчик на работу с отладочным символам можно несколькими способами. Первый, самый простой и традиционный, заключается в указании составного пути к символам в настройках отладчика WinDbg: srv*c:\symbols*http://msdl.microsoft.com/download/symbols
. Для настройки отладочных символов выберем в меню пункт "File" - "Symbol File Path ..." и просто вставим указанное выше значение в поле ввода, затем нажмем клавишу ОК.
Теперь при запуске процесса отладки, отладчик WinDbg сначала произведет поиск символов для модулей, участвующих в процессе отладки, в локальной папке c:\symbols, если там символов обнаружено не будет, то WinDbg попытается загрузить их из сети Интернет с сайта http://msdl.microsoft.com/download/symbols и закешировать (сохранить) в ту же папку c:\symbols. Отладчик WinDbg загружает символы только по мере необходимости и только к модулям, которые обнаруживаются в процессе анализа дампа. Причем директорию c:\symbols руками создавать не требуется, поскольку отладчик создаст её сам на стадии кеширования символов (в случае наличия у него соответствующих разрешений, конечно же).
Для того, чтобы не настраивать путь поиска символов каждый раз после запуска WinDbg, необходимо сохранить рабочее окружение отладчика. Для этого зайдите в меню "File" и выберите пункт "Save Workspace".
Отладка зависшего процесса
Теперь перейдем непосредственно к изучению подвисшего приложения. Отладку я производил непосредственно на клиентской рабочей машине, хотя тут есть некоторые пространство для маневров.
Все дальнейшие действия производятся от имени имени учетной записи с правами локального администратора.
Запускаем отладчик Windbg, либо непосредственным выбором из меню Пуск, либо можно просто ввести слово Windbg в строке поиска.
В интерфейса выбираем меню File, далее пункт Attach to a process (либо просто жмем клавишу F6):
В открывшемся списке ищем зависший процесс (в нашем случае это WINWORD.EXE), маркируем его и нажимаем кнопку OK. Происходит подключение отладчика к процессу (WINWORD), после чего в основном окне вывода мы наблюдаем следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. *** wait with pending attach Symbol search path is: *** Invalid *** **************************************************************************** * Symbol loading may be unreliable without a symbol search path. * * Use .symfix to have the debugger choose a symbol path. * * After setting your symbol path, use .reload to refresh symbol locations. * **************************************************************************** Executable search path is: ModLoad: 00000001`3f4e0000 00000001`3f63f000 C:\Program Files\Microsoft Office\Office14\WINWORD.EXE ModLoad: 00000000`77a70000 00000000`77c1b000 C:\Windows\SYSTEM32\ntdll.dll ModLoad: 00000000`77850000 00000000`7796f000 C:\Windows\system32\kernel32.dll ModLoad: 000007fe`fd870000 000007fe`fd8da000 C:\Windows\system32\KERNELBASE.dll . . . ModLoad: 000007fe`f87e0000 000007fe`f87e8000 C:\Windows\system32\rasadhlp.dll ModLoad: 000007fe`fa6f0000 000007fe`fa743000 C:\Windows\System32\fwpuclnt.dll ModLoad: 000007fe`f4c50000 000007fe`f4e25000 C:\Windows\System32\msxml3.dll ModLoad: 000007fe`ec120000 000007fe`ec199000 C:\Windows\system32\spool\DRIVERS\x64\3\UNIDRV.DLL ModLoad: 00000000`3da00000 00000000`3db05000 C:\Windows\system32\spool\DRIVERS\x64\3\x2rpclBC.dll ModLoad: 00000000`3eac0000 00000000`3eaf2000 C:\Windows\system32\spool\DRIVERS\x64\3\x2wftuBC.dll (13bc.1420): Break instruction exception - code 80000003 (first chance) *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SYSTEM32\ntdll.dll - . . . *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\kernel32.dll - |
Я намерено сократил вывод, поскольку после подключения к процессу отладчик начинает перечислять модули, загруженные в адресное пространство процесса. Это все те модули/библиотеки, функции которых необходимы для работы основного приложения WINWORD.EXE, либо те модули, которые через специальные системные механизмы были принудительно загружены в адресное пространство процесса. Информационная строка Symbol search path is: *** Invalid ***
, а так же похожие строки ERROR: Symbol file could not be found
для основных системных библиотек говорят нам о том, что отладчик не смог подгрузить символы с локального хранилища либо с сервера символов Microsoft. Это может быть из-за того, что путь к отладочным символам не сконфигурирован, либо доступа к серверу символов попросту нет.
Сразу оговорюсь, что на клиентской станции я прописал путь к символам в соответствии рекомендациями, описанными выше.
После чего сделал повторную попытку загрузки символов посредством ввода команды .reload
:
1 2 3 4 5 |
0:009> .reload Reloading current modules ................................................................ ......................................................... *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SYSTEM32\ntdll.dll - |
Тем не менее, символы по прежнему не загружались, о чем красноречиво свидетельствовала ошибка ERROR: Symbol file could not be found
.
Как выяснилась чуть позже, объяснение этому было достаточно простое: станция пользователя не имела выхода в сеть Интернет, поэтому и доступа к серверу символов Microsoft не было.
В подобной ситуации у нас остается два выхода:
- поднять собственный сервер символов внутри локальной сети. но это отдельная, иногда весьма трудоемкая задача, заниматься которой я в тот момент не хотел.
- продолжить отладку без использования отладочных символов. это существенно осложняло анализ.
К тому же я вспомнил, что получить символы к модулям установленной у клиента операционной системы Windows 7 мы сможем, они то в открытом доступе имеются, но вот отладочные символы к модулям (библиотекам) пакета Microsoft Office 2010 мы никогда не получим, поскольку Microsoft в открытый доступ их попросту не выкладывает. Поэтому я выбрал самый сложный из всех возможных сценариев и отказался от использования символов вообще!
Продолжаем. Наш отладчик в данный момент уже подключен к зависшему процессу WINWORD. И начинаем мы изучение процесса с вывода выполняющихся в его контексте потоков. Заодно данное действие даст нам понимание того, сколько же вообще потоков выполняется в рамках изучаемого нами процесса. Для вывода списка потоков используем команду ~*
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
0:009> ~* 0 Id: 13bc.17d0 Suspend: 1 Teb: 000007ff`fffde000 Unfrozen Start: *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\Office14\WINWORD.EXE - WINWORD+0x1b7c (00000001`3f4e1b7c) Priority: 0 Priority class: 32 Affinity: f 1 Id: 13bc.930 Suspend: 1 Teb: 000007ff`fffda000 Unfrozen Start: ntdll!TpIsTimerSet+0x8a0 (00000000`77a8a1d0) Priority: 0 Priority class: 32 Affinity: f 2 Id: 13bc.1748 Suspend: 1 Teb: 000007ff`fffd8000 Unfrozen Start: *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\office14\mso.dll - mso!Ordinal4349+0x25c (000007fe`e6045014) Priority: 0 Priority class: 32 Affinity: f 3 Id: 13bc.16f8 Suspend: 1 Teb: 000007ff`fffd4000 Unfrozen Start: mso!Ordinal4349+0x39c (000007fe`e6045154) Priority: 0 Priority class: 32 Affinity: f 4 Id: 13bc.1180 Suspend: 1 Teb: 000007ff`fffa6000 Unfrozen Start: *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\WinSxS\amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.23407_none_14556c1e8b95d0b8\gdiplus.dll - gdiplus!GdipPlayTSClientRecord+0x1593c (000007fe`fbee2af4) Priority: 0 Priority class: 32 Affinity: f 5 Id: 13bc.ee0 Suspend: 1 Teb: 000007ff`fffa4000 Unfrozen Start: mso!Ordinal4349+0x25c (000007fe`e6045014) Priority: 0 Priority class: 32 Affinity: f 6 Id: 13bc.afc Suspend: 1 Teb: 000007ff`fffa2000 Unfrozen Start: mso!Ordinal4349+0x25c (000007fe`e6045014) Priority: 0 Priority class: 32 Affinity: f 7 Id: 13bc.79c Suspend: 1 Teb: 000007ff`fffdc000 Unfrozen Start: mso!Ordinal4349+0x25c (000007fe`e6045014) Priority: 0 Priority class: 32 Affinity: f 8 Id: 13bc.1560 Suspend: 1 Teb: 000007ff`fffae000 Unfrozen Start: ntdll!RtlDestroyHandleTable+0x270 (00000000`77a8f5d0) Priority: 0 Priority class: 32 Affinity: f . 9 Id: 13bc.1420 Suspend: 1 Teb: 000007ff`fffac000 Unfrozen Start: ntdll!DbgUiRemoteBreakin (00000000`77b62c50) Priority: 0 Priority class: 32 Affinity: f |
Символ .
напротив 9го потока указывает нам на то, что в данный момент активным является контекст потока #9, в котором, судя по стартовой функции ntdll!DbgUiRemoteBreakin
, у нас выполняется отладчик Windbg. Получается, что в контейнере процесса WINWORD у нас в момент сбоя выполнялось 8 собственных потоков.
Процесс это контейнер, сами по себе процессы не выполняются, всю вычислительную нагрузку несут потоки внутри процесса.
Принимая данный факт во внимание, осознаем, что изучать мы будем потоки внутри процесса. Но какой из восьми потоков завис, то есть какой из потоков является целью для отладки? Для этого давайте, для начала, проведем "беглый" анализ всех потоков процесса:
Поток№ | Старт | Комментарий |
---|---|---|
0 | WINWORD+0x1b7c | Нулевой поток всегда является основным (главным) потоком процесса (WINWORD). В пользу этого факта говорит название модуля, совпадающее с названием основного приложения (WINWORD). |
1 | ntdll!TpIsTimerSet+0x8a0 | Судя по всему проверка статуса системного таймера через функцию TpIsTimerSet библиотеки ntdll.dll. |
2 | mso!Ordinal4349+0x25c | Неизвестная внутренняя функция с ординалом 4349 библиотеки mso.dll. mso.dll является библиотекой в составе Microsoft Office разных версий, в которой сосредоточено большинство внутренних функций, используемых основными приложениями пакета. |
3 | mso!Ordinal4349+0x39c | Неизвестная внутренняя функция с ординалом 4349 библиотеки mso.dll. mso.dll является библиотекой в составе Microsoft Office разных версий, в которой сосредоточено большинство внутренних функций, используемых основными приложениями пакета. |
4 | gdiplus!GdipPlayTSClientRecord+0x1593c | Функция GdipPlayTSClientRecord библиотеки gdiplus.dll. Библиотека gdiplus.dll предоставляет доступ приложений к использованию функций поддержки графики и некоторых текстовых функций при работе с видеоадаптером и принтером. |
5 | mso!Ordinal4349+0x25c | Неизвестная внутренняя функция с ординалом 4349 библиотеки mso.dll. mso.dll является библиотекой в составе Microsoft Office разных версий, в которой сосредоточено большинство внутренних функций, используемых основными приложениями пакета. |
6 | mso!Ordinal4349+0x25c | Неизвестная внутренняя функция с ординалом 4349 библиотеки mso.dll. mso.dll является библиотекой в составе Microsoft Office разных версий, в которой сосредоточено большинство внутренних функций, используемых основными приложениями пакета. |
7 | mso!Ordinal4349+0x25c | Неизвестная внутренняя функция с ординалом 4349 библиотеки mso.dll. mso.dll является библиотекой в составе Microsoft Office разных версий, в которой сосредоточено большинство внутренних функций, используемых основными приложениями пакета. |
8 | ntdll!RtlDestroyHandleTable+0x270 | Функция RtlDestroyHandleTable библиотеки ntdll.dll. Функция уничтожает таблицу дескриптора и освобождает ассоциированные с ней ресурсы. |
9 | ntdll!DbgUiRemoteBreakin | Функция DbgUiRemoteBreakin обрабатывает запуск отладчика. Если отладчик присоединяется к процессу, в этом процессе создается новый поток с функцией DbgUIRemoteBreakin в качестве точки входа. Собственно, наш отладчик Windbg. |
Как думаете, какой нам выбрать поток? Лично мне моя интуиция кивает на поток #0, уже лишь по той причине, что код этого потока выполняется внутри основного модуля, на что красноречиво намекает название WINWORD
. В действительности всё даже проще. Считается, что нулевой поток (поток #0) является главным потоком процесса, и если процесс виснет, то зависает всегда именно главный поток. Поэтому, в первую очередь, всегда обращайте внимание на нулевой поток (поток #0).
И так, начинаем анализ потока #0, для этого переключаемся на него (переключаем контекст выполнения) командой ~0s
:
1 2 3 4 |
0:009> ~0s *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\Office14\wwlib.dll - wwlib!FMain+0x11a957: 000007fe`e95ac97b 443bc5 cmp r8d,ebp |
Отладчик привычно выдает нам предупреждение об отсутствии символов к библиотеке wwlib.dll. wwlib.dll это библиотека, входящая в состав пакета Microsoft Office 2010, а к этому пакету, как мы уже говорили, Microsoft не предоставляет файлов символов. После сообщения об отсутствии отладочных символов, мы наблюдаем относительное смещение инструкции wwlib!FMain+0x11a957
, которая показывает нам, что инструкция находится по смещению 0x11a957 относительно начала функции FMain
в библиотеке wwlib.dll. Далее следует адрес инструкции в виртуальном адресном пространстве процесса, опкод инструкции ассемблера (443bc5) и символическое имя инструкции (cmp r8d,ebp), на которой отладчик остановил выполнение потока. СТОИМ! Неплохо было бы получить стек вызовов потока.
Стек вызовов - цепочка вызовов процедур, начиная от момента запуска потока.
Для получения информации по стеку вызовов потока #0 я использовал команду kL
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
0:000> kL Child-SP RetAddr Call Site 00000000`001ecca0 000007fe`e95ac51f wwlib!FMain+0x11a957 00000000`001ecce0 000007fe`e95a8202 wwlib!FMain+0x11a4fb 00000000`001ecdd0 000007fe`e9583ed9 wwlib!FMain+0x1161de 00000000`001ecfe0 000007fe`e95804fd wwlib!FMain+0xf1eb5 00000000`001ed050 000007fe`e958011a wwlib!FMain+0xee4d9 00000000`001ed0f0 000007fe`e95c149c wwlib!FMain+0xee0f6 00000000`001ed290 000007fe`e95bffb3 wwlib!FMain+0x12f478 00000000`001ed730 000007fe`e95fc99e wwlib!FMain+0x12df8f 00000000`001ed8c0 000007fe`e96aacbf wwlib!FMain+0x16a97a 00000000`001ed900 000007fe`e96aab2a wwlib!FMain+0x218c9b 00000000`001ed940 000007fe`e96a0e2d wwlib!FMain+0x218b06 00000000`001ed970 000007fe`e96a03b4 wwlib!FMain+0x20ee09 00000000`001eda40 000007fe`e95f7088 wwlib!FMain+0x20e390 00000000`001eda80 000007fe`e9492975 wwlib!FMain+0x165064 00000000`001edae0 00000001`3f4e1709 wwlib!FMain+0x951 00000000`001efcf0 00000001`3f4e19eb WINWORD+0x1709 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\kernel32.dll - 00000000`001efd20 00000000`778659bd WINWORD+0x19eb 00000000`001efdd0 00000000`77a9a2e1 kernel32!BaseThreadInitThunk+0xd 00000000`001efe00 00000000`00000000 ntdll!RtlUserThreadStart+0x21 |
Не очень то информативно, верно? Если бы у нас были файлы символов к модулям пакета Microsoft Office 2010, то вместо "голых" смещений вида FMain+0xXXXXXX, мы видели бы символические имена функций (например, что-то вроде wwlib!GetUserInput+0x1a), что сильно упростило хотя бы понимание того, кто кого и зачем вызывал и где искать проблему. С другой стороны, даже при наличии символов мы могли бы получить похожий, мало понятный, вывод, если бы в библиотеке wwlib.dll оказалась действительно одна функция FMain
, одним словом тут уж как повезет. Ну как же быть если нет символов, не отлаживать код вообще? Нет, это не наш выбор. Видно, что практически со старта поток перешел от главного модуля WINWORD к функциям библиотеки wwlib.dll, которые поочередно вызывали друг-друга.
Стек вызовов читается снизу вверх.
По стеку вызовов видно, что на протяжении последних 14 вызовов функций вся работа шла между функциями библиотеки wwlib.dll и самой последней была некая функция wwlib!FMain+0x11a957 (указана на самой вершине стека).
Поскольку у нас нет символов к библиотеке, все смещения показаны относительно единственной обнаруженной отладчиком функции FMain, судя по всему, главной функции библиотеки.
УПЕРЛИСЬ? Имена функций нам ничего не дают, соответственно понять логически что именно происходило в момент зависания процесса мы не можем. Что же делать дальше? В такие моменты главное не падать духом.
Помните одно: неразрешимых ситуаций нет, если только ограничивающее нас собственное знание.
После того, как я успокоился, мысли мои потекли совершенно в другом направлении. Я ясно визуализировал перед собой поток данных, представляющий собой простой блок кода, исполняемых инструкций, каждая из которых на основе заданных правил исполняется процессором, и так команда за командой. Процессору не нужны символы, ему даже не нужно знать что именно он выполняет, он просто исполняет инструкцию за инструкцией. К тому же у нас в руках превосходный инструмент, отладчик, в котором сведено такое количество различных механизмов отладки, что обладая ими в совершенстве мы могли бы достичь невиданных результатов. В сознании постепенно начала разворачиваться концепция дальнейших действий. Попробуем совместить максимум механизмов, предоставляемых нам отладчиком с минимумом знаний. На ум мне пришла идея увидеть код глазами процессора, воспользовавшись пошаговой трассировкой. Смотрим документацию на предмет команды пошаговой трассировки и начинаем трассировать по одной инструкции посредством команды p
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
0:000> p wwlib!FMain+0x11a95a: 000007fe`e95ac97e 7504 jne wwlib!FMain+0x11a960 (000007fe`e95ac984) [br=0] 0:000> p wwlib!FMain+0x11a95c: 000007fe`e95ac980 8b02 mov eax,dword ptr [rdx] ds:00000000`04da0d50=00000002 0:000> p wwlib!FMain+0x11a95e: 000007fe`e95ac982 eb03 jmp wwlib!FMain+0x11a963 (000007fe`e95ac987) 0:000> p wwlib!FMain+0x11a963: 000007fe`e95ac987 448bcd mov r9d,ebp 0:000> p wwlib!FMain+0x11a966: 000007fe`e95ac98a 3b5a0c cmp ebx,dword ptr [rdx+0Ch] ds:00000000`04da0d5c=00000003 0:000> p wwlib!FMain+0x11a969: 000007fe`e95ac98d 7204 jb wwlib!FMain+0x11a96f (000007fe`e95ac993) [br=0] 0:000> p wwlib!FMain+0x11a96b: 000007fe`e95ac98f 448b4a10 mov r9d,dword ptr [rdx+10h] ds:00000000`04da0d60=00000000 0:000> p wwlib!FMain+0x11a96f: 000007fe`e95ac993 3bd8 cmp ebx,eax 0:000> p wwlib!FMain+0x11a971: 000007fe`e95ac995 0f42c3 cmovb eax,ebx 0:000> p wwlib!FMain+0x11a974: 000007fe`e95ac998 4898 cdqe 0:000> p wwlib!FMain+0x11a976: 000007fe`e95ac99a 8b4c821c mov ecx,dword ptr [rdx+rax*4+1Ch] ds:00000000`04da0d74=000002cb 0:000> p wwlib!FMain+0x11a97a: 000007fe`e95ac99e 428d0409 lea eax,[rcx+r9] 0:000> p wwlib!FMain+0x11a97e: 000007fe`e95ac9a2 413bc4 cmp eax,r12d 0:000> p wwlib!FMain+0x11a981: 000007fe`e95ac9a5 7d04 jge wwlib!FMain+0x11a987 (000007fe`e95ac9ab) [br=0] 0:000> p wwlib!FMain+0x11a983: 000007fe`e95ac9a7 ffc3 inc ebx 0:000> p wwlib!FMain+0x11a985: 000007fe`e95ac9a9 ebd0 jmp wwlib!FMain+0x11a957 (000007fe`e95ac97b) 0:000> p wwlib!FMain+0x11a957: 000007fe`e95ac97b 443bc5 cmp r8d,ebp 0:000> p wwlib!FMain+0x11a95a: 000007fe`e95ac97e 7504 jne wwlib!FMain+0x11a960 (000007fe`e95ac984) [br=0] |
Я просто раз за разом вводил одну и ту же команду p
, просто изучая код, смотря, какие команды всплывают из-под нижней границы окна отладчика. Знаете ли, действо это завораживает, чувствуешь себя прикоснувшимся к некой тайне, частью чего то глобального, частью процесса. Смотришь так вот иногда на поток команд и перед глазами возникает во всей красе внутренний мир машины, начинаешь ощущать всю элегантность команд. Еще бы всегда осознавать, что происходит :) Шаг, инструкция jne, вероятный переход, шаг, инструкция mov, относящая в аккумулятор значение из ячейки памяти, шаг, переход на функцию, шаг, шаг, шаг.. Судя по всему это блок работы с какими то внутренними переменными. Тапая команду p
я как-то ушел в себя, задумался, пытаясь осознать назначение кода, только через некоторое краем зрения заметив, что инструкции и адреса как-то разительно похожи друг на друга, я вышел из забытья и ползунком открутил вверх лог отладчика. Появляющиеся передо мной адреса повторялись, образуя программный цикл.
По блоку кода, приведенному выше, я увидел, что код стартовал с адреса 000007fee95ac97e
и пришел к 000007fee95ac97e
. После команды jmp wwlib!FMain+0x11a957, расположенной по адресу 000007fee95ac9a9
управление всегда передается на 000007fee95ac97b
, ну термин "всегда" тут означает ровно то количество итераций, которое я прошел пошаговой трассировкой, скорее этак раз 5-10. По факту поток попал в бесконечный цикл, из которого моя трассировка не смогла выйти на протяжении нескольких итераций. В голове сразу же всплыло главное предположение: а не этот ли цикл всему виной? Очищенный от мусора этот участок кода выглядит следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
000007fe`e95ac97b 443bc5 cmp r8d,ebp 000007fe`e95ac97e 7504 jne 000007fe`e95ac984 000007fe`e95ac980 8b02 mov eax,dword ptr [rdx] 000007fe`e95ac982 eb03 jmp 000007fe`e95ac987 000007fe`e95ac984 ?????? ??? ?????????????? 000007fe`e95ac987 448bcd mov r9d,ebp 000007fe`e95ac98a 3b5a0c cmp ebx,dword ptr [rdx+0Ch] 000007fe`e95ac98d 7204 jb 000007fe`e95ac993 000007fe`e95ac98f 448b4a10 mov r9d,dword ptr [rdx+10h] 000007fe`e95ac993 3bd8 cmp ebx,eax 000007fe`e95ac995 0f42c3 cmovb eax,ebx 000007fe`e95ac998 4898 cdqe 000007fe`e95ac99a 8b4c821c mov ecx,dword ptr [rdx+rax*4+1Ch] 000007fe`e95ac99e 428d0409 lea eax,[rcx+r9] 000007fe`e95ac9a2 413bc4 cmp eax,r12d 000007fe`e95ac9a5 7d04 jge 000007fe`e95ac9ab 000007fe`e95ac9a7 ffc3 inc ebx 000007fe`e95ac9a9 ebd0 jmp 000007fe`e95ac97b 000007fe`e95ac9ab ???? ??? ?????????????? |
Если проанализировать участок кода, то можно выявить несколько возможных переходов, которые не осуществляются из-за невыполняющихся условий.
Это:
- jne wwlib!FMain+0x11a960 (jne 000007fe`e95ac984) - не интересен, какой-то локальный переход. путем грубого предположения отметается;
- jmp wwlib!FMain+0x11a963 (jmp 000007fe`e95ac987) - не интересен, поскольку является частью какого-то условия на языке высокого уровня (C/C++) внутри нашего глобального цикла;
- jb wwlib!FMain+0x11a96f (jb 000007fe`e95ac993) - не интересен, опять локальный переход. переходит всего на несколько байт вперед. путем грубого предположения отметается;
- jge wwlib!FMain+0x11a987 (jge 000007fe`e95ac9ab) - интересен! определенно разрывает цикл, в котором мы застряли, и уходит на дальнейший код.
Некоторые операнды у нас общаются с ячейками 0000000004da0d50
, 0000000004da0d5c
, 0000000004da0d60
, 0000000004da0d74
. Поэтому я решил посмотреть блок памяти по данным адресам:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
0:000> dd 0000000004da0d50 L32 00000000`04da0d50 00000002 00000003 00000004 00000003 00000000`04da0d60 00000000 00000001 00000000 00000000 00000000`04da0d70 00000275 000002cb 001ece71 001ece70 00000000`04da0d80 00000000 00000000 00000000 00000000 00000000`04da0d90 00000000 00000000 00000000 00000000 00000000`04da0da0 00000000 00000000 00000000 00000000 00000000`04da0db0 04dac9e0 00000000 e8b1e7d0 000007fe 00000000`04da0dc0 04daca00 00000000 e8b1e810 000007fe 00000000`04da0dd0 04daca20 00000000 e8b1e810 000007fe 00000000`04da0de0 e731e450 000007fe 038cb700 00000000 00000000`04da0df0 08dbbe00 00000000 02b2eb60 00000000 00000000`04da0e00 00000305 00000000 04da1fc0 00000000 00000000`04da0e10 00000000 00000000 |
Ну и чего мы здесь видим? Скорее всего какие-то переменные, для чего предназначающиеся не понятно. Код их проверяет, ну и что? Откуда мы знаем что они содержат? Лишний ход, мы все-равно не сможем определить принадлежность блока памяти.
По карте памяти процесса, полученной через команду !address
, данный блок маркирован как:
1 |
* 0`04da0000 0`04db0000 0`00010000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE |
Область, не закрепленная ни за каким модулем. Хотя тут моя логика может хромать, поскольку, вероятно, она и не должна быть закреплена, а может просто-напросто представлять собой регион, выделенный для локальных операций?
Одним словом, нам потребуется принудительно "разорвать" цикл, выйдя из него.
Поскольку нас заинтересовал лишь один переход:
1 |
000007fe`e95ac9a5 7d04 jge wwlib!FMain+0x11a987 (000007fe`e95ac9ab) [br=0] |
который при нашей трассировке ни разу не выполнился, предположим что именно из-за отсутствия данного перехода у нас и образовался цикл. Поэтому мы его и используем. Для размыкания цикла необходимо сделать так, что бы условие выполнилось и переход осуществился. Сначала я попытался осуществить данный финт через непосредственное изменение флагов SF и OF с целью сделать условия перехода истинными, но у меня, в силу собственной специфики :) ничего не получилось, переход упорно не хотел выполняться. Плюнув на эту безнадежную затею, я решил попробовать изменить код операнда в памяти. Для этого мы просто вызываем Memory Window (окно памяти) кликом по соответствующему значку на панели инструментов или комбинацией клавиш Alt+5, после чего у нас открывается такое вот окно:
Находим адрес 000007fee95ac9a5
, по которому у нас располагается опкод команды (7D04). На рисунке он маркирован мною красной рамкой. Напомню, что опкод 7D04 означает команду jge
, который трактуется как "переход если больше или равно". Нам же можно попробовать поменять условие на противоположное. В документации к ассемблеру находим следующую инструкцию:
7CXX jl
соответственно, нам надо заменить значение первого байта с 7D
на 7C
. После выполнения замены, изменения применяются мгновенно и можно закрыть окно дампа памяти. Выполнив несколько команд я убедился, что инструкция действительно изменилась и код ушел дальше. Ну что же, настает момент истины и нам требуется проверить правильность наших действий, поскольку в пошаговой трассировке более нет необходимости, я просто запущу поток на исполнение. В командной строке ввожу команду g
и нажимаю на клавиатуре клавишу Enter. Через несколько секунд процесс WINWORD отвис, о чем красноречиво свидетельствовало ожившее окно программы:
После чего пользователь смог сохранить свои данные, которых, к великому моему сожалению, оказалось совсем немного. И я завершил отладчик с закрытием отлаживаемого процесса.
Источник проблемы
Ну ладно, не мытьем так катаньем нам удалось решить проблему зависшего процесса. Но вся особенно именно этой проблемы заключалась в том, что зависания происходят с завидной регулярностью, до нескольких раз за рабочий день. По несколько раз на дню заниматься отладкой совершенно не хотелось, требовалось найти причину возникающих сбоев. Если повнимательнее присмотреть к пакету Microsoft Office 2010, выпущенного уже достаточно давно и успевшего обрасти уже не одним сервис паком и огромным количеством всевозможных хотфиксов, понимаешь, что вряд ли обнаруженная нами проблема является следствием бага в самом пакете, существование подобного сбоя возможно только, разве что, на этапе альфа-тестирования. Поэтому я сделал предположение, что виновником сбоя является что-то внешнее, работающее в контексте процесса WINWORD. Как то в процессе отладки и выводил карту памяти процесса по команде !address
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
0:000> !address . . . BaseAddress EndAddress+1 RegionSize Type State Protect Usage ---------------------------------------------------------------------------------------------------------------------- * 0`00000000 0`00010000 0`00010000 MEM_FREE PAGE_NOACCESS Free * 0`00010000 0`00020000 0`00010000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "PageFile" * 0`00020000 0`00021000 0`00001000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "PageFile" * 0`00021000 0`00030000 0`0000f000 MEM_FREE PAGE_NOACCESS Free * 0`00030000 0`00034000 0`00004000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "PageFile" * 0`00034000 0`00040000 0`0000c000 MEM_FREE PAGE_NOACCESS Free * 0`00040000 0`00043000 0`00003000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "PageFile" * 0`00043000 0`00050000 0`0000d000 MEM_FREE PAGE_NOACCESS Free * 0`00050000 0`00051000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`00051000 0`00060000 0`0000f000 MEM_FREE PAGE_NOACCESS Free * 0`00060000 0`00061000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`00061000 0`00070000 0`0000f000 MEM_FREE PAGE_NOACCESS Free * 0`00070000 0`000d7000 0`00067000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "\Device\HarddiskVolume2\Windows\System32\locale.nls" * 0`000d7000 0`000e0000 0`00009000 MEM_FREE PAGE_NOACCESS Free * 0`000e0000 0`000e1000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`000e1000 0`000f0000 0`0000f000 MEM_FREE PAGE_NOACCESS Free . . . * 0`07fa3000 0`07fb0000 0`0000d000 MEM_FREE PAGE_NOACCESS Free * 0`07fb0000 0`08030000 0`00080000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "\Device\HarddiskVolume2\Users\IvanovII\Desktop\ИСКИ\Ходатайства\Ходатайство (отправка)..doc" * 0`08030000 0`08031000 0`00001000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "\Device\HarddiskVolume2\TEMP\~DF6A7E4DECA13FED43.TMP" |- 0`08031000 0`080b0000 0`0007f000 MEM_MAPPED MEM_RESERVE MemoryMappedFile "\Device\HarddiskVolume2\TEMP\~DF6A7E4DECA13FED43.TMP" * 0`080b0000 0`080bc000 0`0000c000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`080bc000 0`080c0000 0`00004000 MEM_FREE PAGE_NOACCESS Free * 0`080c0000 0`080d0000 0`00010000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`080d0000 0`08141000 0`00071000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE |- 0`08141000 0`08150000 0`0000f000 MEM_PRIVATE MEM_RESERVE * 0`08150000 0`08a80000 0`00930000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "\Device\HarddiskVolume2\Windows\Fonts\StaticCache.dat" * 0`08a80000 0`08a8e000 0`0000e000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "\Device\HarddiskVolume2\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" * 0`08a8e000 0`08a90000 0`00002000 MEM_FREE PAGE_NOACCESS Free * 0`08a90000 0`08a94000 0`00004000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "\Device\HarddiskVolume2\Windows\System32\stdole2.tlb" * 0`08a94000 0`08aa0000 0`0000c000 MEM_FREE PAGE_NOACCESS Free * 0`08aa0000 0`08aa1000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`08aa1000 0`08ab0000 0`0000f000 MEM_FREE PAGE_NOACCESS Free * 0`08ab0000 0`08ab3000 0`00003000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE * 0`08ab3000 0`08ac0000 0`0000d000 MEM_FREE PAGE_NOACCESS Free * 0`08ac0000 0`08ad0000 0`00010000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "PageFile" * 0`08ad0000 0`08ae0000 0`00010000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "PageFile" * 0`08ae0000 0`08af0000 0`00010000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "PageFile" * 0`08af0000 0`08b00000 0`00010000 MEM_FREE PAGE_NOACCESS Free . . . * 1`3f641000 1`80000000 0`409bf000 MEM_FREE PAGE_NOACCESS Free * 1`80000000 1`80001000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`80001000 1`80081000 0`00080000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READ Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`80081000 1`80082000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READWRITE Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`80082000 1`800a6000 0`00024000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`800a6000 1`800a7000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`800a7000 1`800a9000 0`00002000 MEM_IMAGE MEM_COMMIT PAGE_WRITECOPY Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`800a9000 1`800ac000 0`00003000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`800ac000 1`800ad000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_WRITECOPY Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`800ad000 1`800b1000 0`00004000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" |- 1`800b1000 1`800bd000 0`0000c000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files (x86)\Print Audit Inc\Print Audit 6\Client\pa6wtrak64.dll" * 1`800bd000 7fe`da830000 7fd`5a773000 MEM_FREE PAGE_NOACCESS Free . . . * 7fe`ebd1b000 7fe`ebd60000 0`00045000 MEM_FREE PAGE_NOACCESS Free * 7fe`ebd60000 7fe`ebd61000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebd61000 7fe`ebde4000 0`00083000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READ Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebde4000 7fe`ebe1a000 0`00036000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe1a000 7fe`ebe1b000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_WRITECOPY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe1b000 7fe`ebe1c000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe1c000 7fe`ebe1d000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_WRITECOPY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe1d000 7fe`ebe22000 0`00005000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe22000 7fe`ebe24000 0`00002000 MEM_IMAGE MEM_COMMIT PAGE_WRITECOPY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe24000 7fe`ebe27000 0`00003000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe27000 7fe`ebe33000 0`0000c000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe33000 7fe`ebe34000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_WRITECOPY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" |- 7fe`ebe34000 7fe`ebe5c000 0`00028000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Users\IvanovII\AppData\Roaming\ConsultantPlus\Lib\scons64.dll" * 7fe`ebe5c000 7fe`ebe60000 0`00004000 MEM_FREE PAGE_NOACCESS Free . . . * 7fe`f28cc000 7fe`f3b10000 0`01244000 MEM_FREE PAGE_NOACCESS Free * 7fe`f3b10000 7fe`f3b11000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files\Manufacturer\Endpoint Agent\prntm64.dll" |- 7fe`f3b11000 7fe`f3b4a000 0`00039000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READ Image "C:\Program Files\Manufacturer\Endpoint Agent\prntm64.dll" |- 7fe`f3b4a000 7fe`f3b4b000 0`00001000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READWRITE Image "C:\Program Files\Manufacturer\Endpoint Agent\prntm64.dll" |- 7fe`f3b4b000 7fe`f3b67000 0`0001c000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files\Manufacturer\Endpoint Agent\prntm64.dll" |- 7fe`f3b67000 7fe`f3b6a000 0`00003000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Program Files\Manufacturer\Endpoint Agent\prntm64.dll" |- 7fe`f3b6a000 7fe`f3b70000 0`00006000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files\Manufacturer\Endpoint Agent\prntm64.dll" * 7fe`f3b70000 7fe`f4ae0000 0`00f70000 MEM_FREE PAGE_NOACCESS Free . . . |
И после завершения отладки я решил просмотреть записанный мной ранее в отдельный текстовый файл журнал отладки, с целью более детально изучить карту памяти процесса. Дело в том, что карта может показать нам много интересных особенностей. В адресном пространстве содержится всё необходимое для полноценной работы приложения Winword. Тут можно найти и библиотеки, требуемые для работы, можно увидеть и сам редактируемый файл, различные временные файлы, системные структуры, такие как стек, кучи и прочее. Я умышленно вырезал из карты памяти процесса все лишнее, оставив только заинтересовавшие меня области. Что же мне, собственно, удалось обнаружить:
- Надстройка к WINWORD под названием Консультант+ светилась библиотекой scons.dll.
- В пространстве присутствовала некая программа Print Audit, функционал которой обеспечивался библиотекой pa6wtrak64.dll.
- И наконец, самое интересное, своё присутствие засветил такой интересный компонент как Symantec Endpoint Agent (он же Symantec DLP), который был представлен библиотекой prntm64.dll.
Как Вы думаете, на какой из этих процессов я обратил внимание в первую очередь? Правильно, на Symantec DLP, потому как пару раз я уже подавал баг-репорты по обнаруженным внутри DLP проблемам через поставщиков, я уже имел некую накопившуюся базу знаний по данному программному продукту. Подобные, достаточно сложные, контролирующие системы, в силу особенностей архитектуры и необходимости постоянно внедряться везде, где только можно, идеально работать не могут, слишком сложны подобные алгоритмы. Не подумайте, я не хочу кидать камень в огород Symantec, просто выражаю своё собственное мнение на счет данного продукта. Надо заметить, что обнаруженная мной на станции клиента версия DLP не являлась последней, а выпущена была несколько месяцев назад. Вы понимаете, насколько важно поддерживать подобного рода программные средства на должном уровне обновления, поскольку продукт непрерывно буквально дорабатывается и тестируется после каждого серьезного системного обновления операционной системы. Поскольку в этот раз я не смог сопоставить обнаруженный глюк Winword'а непосредственно с какой-либо ошибкой в модуле Sumantec DLP, было принято решение просто удалить продукт. После удаления агента DLP клиентская система вот уже несколько дней работает без сбоев.
Выводы
Приведенный мной пример устранения причины зависшего процесса далек от идеала, поскольку, в некоторых ситуациях, логика зациклившегося кода может быть в разы более сложной. Более того, он может быть вовсе не показательным, поскольку я могу предположить, что "отвисание" зависшего процесса лично в данном эксперименте могло быть связано вовсе не с разомкнутым программным циклом. Однако, не смотря ни на что, данный пример показывает, что не стоит бояться проводить исследования работы кода, поскольку в некоторых случаях причины зависания процесса могут быть достаточно банальными.
Как же мне ещё да-а-а-а-леко до тебя.... :-(
У меня периодически зависает процесс Explorer.exe при наличии в системе PuntoSwitcher (при создании, либо переименовании файлов и папок) на срок от 3-х сек до убийства процесса. Интересно? (для коллекции)
до меня? да брось..
а глюк именно от puntoswitcher зависит? то есть при отключении/деинсталляции проблема уходит?
можно подробности на почту?