Строим основу для тестирования нештатных сценариев Windows с помощью Application Verifier
· Го Комура · Разработка Windows, Расследование сбоев, Промышленная камера, Application Verifier, Тестирование нештатных сценариев, Утечка хендлов
Application Verifier — мощный инструмент, если вы хотите заранее выявить аномалии, возникающие в нативном коде Windows и на границе Win32. Особенно если нужно протестировать аномалии хендлов, повреждение кучи и пути отказа при нехватке ресурсов, он позволяет довольно быстро вывести на поверхность проблемы, невидимые при одном лишь тестировании штатных сценариев.
В первой части, «Когда приложение управления промышленной камерой неожиданно падает через месяц (часть 1) — как искать утечки хендлов и проектировать логи для долгой эксплуатации», мы разобрали случай, когда причиной падения управляющего приложения после долгой работы оказалась утечка хендлов. Но одно лишь усиление логов — это только половина дела. По-настоящему нужно заранее проверить, сохранится ли в будущем, если из-за очередной непредвиденной ошибки программиста возникнет утечка памяти, утечка хендлов, частичный отказ или пропущенное освобождение, состояние «понятно, что произошло».
Именно для этого мы использовали Application Verifier. Это инструмент, который позволяет вставлять во время выполнения проверки и fault injection для кода, работающего в нативном коде Windows и на границе Win32. Особенно удобно на практике то, что можно заранее вызвать поломки, похожие на нехватку памяти или ресурсов, не доводя реальную память машины до истощения.
Во второй части разберём, что такое Application Verifier, что он умеет и как встроить его в основу для тестирования нештатных сценариев — в контексте приложения управления промышленной камерой.
Содержание
- Сначала — вывод (в двух словах)
- Что такое Application Verifier
- 2.1. Если коротко
- 2.2. В каких ситуациях он эффективен
- 2.3. В чём польза
- Что умеет Application Verifier
- 3.1. Basics: Handles / Heaps / Locks / Memory / TLS и другое
- 3.2. Low Resource Simulation: заранее вызвать нехватку памяти и ресурсов
- 3.3. Page Heap и отладчик
- 3.4.
!avrf/!htrace/ логи
- Зачем мы внедрили его в этот раз
- 4.1. Цель — не только «найти баг»
- 4.2. Вызываем явление, похожее на нехватку памяти
- 4.3. Проверяем, можно ли отследить аномалию хендла, когда она случится
- Как вызывать явления, похожие на нехватку памяти и ресурсов
- 5.1. Идея Low Resource Simulation
- 5.2. Что можно заставить отказать
- 5.3. Как применять это на практике
- Как смотреть на аномалии хендлов
- 6.1. Проверка
Handles - 6.2. Смотрим стек open / close через
!htrace - 6.3. Как сочетать это с собственными логами
- 6.1. Проверка
- Как строить основу для тестирования нештатных сценариев
- 7.1. Переносим единицу запуска в harness
- 7.2. Разделяем меню тестов
- 7.3. Что собирать
- 7.4. Критерии приёмки
- 7.5. Предостережения
- Как выбирать (кратко)
- Итог
- Справочные материалы
1. Сначала — вывод (в двух словах)
- Application Verifier — инструмент, который упрощает выявление во время выполнения неправильного использования на немаржированной / нативной границе Windows
- Ценность не только в том, чтобы «найти баг», но и в том, чтобы заранее вызвать редко проявляющиеся нештатные сценарии
Handlesвыявляет недействительные хендлы,Heapsпроявляет повреждение кучи, аLow Resource Simulationвыполняет fault injection ситуаций, похожих на нехватку памяти и ресурсов- Полностью перекладывать расследование утечки долго резидентного EXE на один Application Verifier — плохая стратегия; реалистичный путь — сочетать его с собственными логами
Handle Countи жизненного цикла ресурсов - В основе для тестирования нештатных сценариев результаты проще читать, если разделить прогон verifier по штатному пути и прогон с fault injection
- Даже если нужно протестировать DLL, Application Verifier включается для тестового EXE, который реально её запускает
Иначе говоря, Application Verifier — это инструмент, вытаскивающий на свет «неприятные баги», живущие вокруг нативной / Win32-границы Windows. Он особенно хорошо подходит для миров вроде приложений управления оборудованием, где обычным делом смешиваются native SDK, P/Invoke и Win32 API.
2. Что такое Application Verifier
2.1. Если коротко
Application Verifier — это инструмент рантайм-верификации для пользовательских приложений Windows. Он наблюдает за тем, как работающее приложение использует API ОС и обращается с ресурсами, позволяет выявлять подозрительное использование и намеренно вносить отказы.
В отличие от «статического анализа» или «модульных тестов», это инструмент, показывающий, как всё ломается при реальном прохождении данного пути кода. Поэтому он хорошо подходит для выявления путей отказа, невидимых в обычном функциональном тестировании.
flowchart LR
A[Тестовый harness] --> B[Управляющее приложение / обёртка SDK]
B --> C[Application Verifier]
C --> D[Win32 API / native DLL / ресурсы ОС]
C --> E[verifier stop]
C --> F[вывод отладчика]
C --> G[логи AppVerifier]
B --> H[Собственный structured log]
2.2. В каких ситуациях он эффективен
Особенно эффективен он в таких ситуациях.
- вы вызываете native DLL или SDK камеры;
- пересекаете границы P/Invoke или COM;
- прямо или косвенно активно используете хендлы, кучу, блокировки, виртуальную память;
- на обычном штатном пути приложение почти не падает, но на нештатных путях управление жизненным циклом выглядит хрупким;
- «изредка возвращает странный отказ» проявляется раньше, чем «падает».
И наоборот, он не является инструментом для отслеживания графа объектов в чисто управляемом мире. Поэтому даже в C#-приложении он приносит немалую пользу, если граница native SDK или Win32 достаточно толстая, но не является единственным инструментом для полного расследования утечек чисто управляемой кучи.
2.3. В чём польза
На практике польза сводится примерно к трём пунктам.
- Быстро останавливать неправильное использование на нативной границе
- недействительные хендлы;
- повреждение кучи;
- неправильное использование блокировок;
- неправильное использование API виртуальной памяти и т. д.
- Заранее выявлять формы поломки, проявляющиеся только при нехватке ресурсов
- эквиваленты
mallocизредка отказывают; CreateEventиCreateFileизредка отказывают;- отказывает
VirtualAlloc.
- эквиваленты
- Проще отслеживать в сочетании с отладчиком
!avrf!htrace!heap -p -a- логи verifier stop.
В приложениях управления оборудованием мешает именно «непонимание того, что произошло на нештатном пути». Application Verifier довольно эффективно снижает эту «непонятность».
3. Что умеет Application Verifier
3.1. Basics: Handles / Heaps / Locks / Memory / TLS и другое
Базовый набор Application Verifier — это Basics.
Здесь собраны проверки, которые чаще всего используются на практике.
| Слой | Что отслеживает | Где применимо в этом контексте |
|---|---|---|
Handles |
Использование недействительных хендлов | Не наступаем ли на закрытые / повреждённые хендлы |
Heaps |
Повреждение кучи | Выявление порчи буфера и use-after-free на границе native SDK |
Leak |
Ресурсы, не освобождённые к моменту выгрузки DLL | Тесты короткоживущих harness, случаи, включающие unload |
Locks / SRWLock |
Неправильное использование блокировок | Проверка гонок между reconnect и shutdown |
Memory |
Неправильное использование VirtualAlloc / MapViewOfFile и подобного |
Проверка аномалий вокруг больших буферов и разделяемой памяти |
TLS |
Неправильное использование API Thread Local Storage | Подстраховка для нативного кода со сложными границами потоков |
Threadpool |
Согласованность API threadpool и состояния worker-ов | Подспорье при обилии callback-ов и асинхронной обработки |
Суть в том, чтобы останавливать подозрительное использование на месте, а не «понимать это, читая уже после краша». Для дефектов долгой работы такое опережение окупается весьма заметно.
3.2. Low Resource Simulation: заранее вызвать нехватку памяти и ресурсов
Это по-настоящему удобная часть на практике. Потому что можно вызвать явление, близкое к нехватке памяти или ресурсов, не доводя реальную оперативную память до истощения.
Идея простая.
- берём определённый вызов API;
- с определённой вероятностью;
- намеренно заставляем его отказать.
Так можно пройти по путям ошибок, которые обычно почти никогда не проходятся.
Конкретно так становится легко намеренно вызывать такие явления.
- отказывают
HeapAllocиVirtualAlloc; - отказывает
CreateFile; - отказывает
CreateEvent; - отказывает
MapViewOfFile; - отказывают выделения OLE/COM вроде
SysAllocString.
Это заметно удобнее, чем пытаться реально вызвать нехватку памяти и мучить всю машину целиком. Более того, можно нацелить fault injection на конкретную DLL. Для конфигураций вроде приложений управления оборудованием, где смешаны собственные обёртки и SDK производителя, это весьма практично.
3.3. Page Heap и отладчик
Для повреждения кучи сильна связка Heaps и page heap.
В частности, full page heap за счёт guard page даёт преимущество — останавливаться близко к моменту повреждения.
Однако это довольно тяжеловесно. Вместо длительного полного перебора удобнее сузиться до сценариев, близких к воспроизведению, и прогонять их под отладчиком.
Поэтому реалистичен такой порядок работы.
- сначала широко применить
Basics; - если куча выглядит подозрительной, использовать full page heap;
- если слишком тяжело, опуститься до light page heap;
- для длительных тестов, приближённых к продакшену, полагаться в основном на собственные логи.
В конечном счёте AppVerifier — не волшебная палочка, а инструмент, у которого лезвие меняется в зависимости от ситуации.
3.4. !avrf / !htrace / логи
Application Verifier не просто выдаёт stop и заканчивает на этом. Благодаря расширениям отладчика и логам легче проследить, что произошло.
!avrf- смотрим текущие настройки verifier и происходящий сейчас stop;
!htrace- смотрим стеки open / close / обращений к недействительному хендлу;
!heap -p -a- в сочетании с page heap прослеживаем повреждённый блок кучи;
- логи AppVerifier
- можно сохранять логи на момент возникновения stop.
Особенно приятно, что при включении Handles автоматически включается handle tracing.
Это заметно упрощает последующее выяснение, «где этот хендл открыли, а где закрыли».
4. Зачем мы внедрили его в этот раз
4.1. Цель — не только «найти баг»
Цель в этот раз была не просто «найти один баг с помощью AppVerifier». Говоря более практично, мы хотели проверить следующее.
- если в будущем на каком-то другом пути отказа снова случится утечка ресурса;
- останется ли в логах должный контекст;
- сможем ли мы проследить всё до конца вместе с информацией отладчика;
- не окажемся ли мы в состоянии «непонятно, что произошло».
Иначе говоря, мы использовали его не только как детектор, но и как тест собственной инфраструктуры наблюдения.
4.2. Вызываем явление, похожее на нехватку памяти
По-настоящему вызвать нехватку памяти на обычной машине разработки довольно хлопотно. Более того, если из-за этого вся машина станет нестабильной, сам тест захлебнётся в шуме.
Поэтому мы пошли по пути использования Low Resource Simulation, чтобы намеренно наступать на пути отказа, которые вероятно вызовет нехватка памяти или ресурсов.
Это заметно упрощает ответы на такие вопросы.
- если
CreateEventотказывает, остаются ли в логахcameraIdиphase? - действительно ли выполняется очистка после половинчатой инициализации?
- если
VirtualAllocотказывает, не ломает ли состояние повторная попытка? - возвращается ли хендл, если
CreateFileотказывает на пути сохранения?
Хотим подчеркнуть: сама по себе цель — не вызвать аномалию, а сделать так, чтобы форма поломки была читаемой при её возникновении.
4.3. Проверяем, можно ли отследить аномалию хендла, когда она случится
Как и с утечкой хендлов из первой части, вокруг хендлов место, где всё в итоге упало, и истинная причина легко расходятся.
Поэтому мы хотели подтвердить следующее.
- если возникает stop из-за недействительного хендла, можно ли отследить open / close через
!htrace; - связывается ли это с
resourceId/sessionId/phaseв собственных логах; - возвращается ли handle count после отказа;
- легко ли читать разницу утечки, если harness сделать короткоживущим процессом.
Дойдя до этого уровня, можно перейти от простого «баг проявился» к тому, «у какой именно ответственности сломалось управление жизненным циклом».
5. Как вызывать явления, похожие на нехватку памяти и ресурсов
5.1. Идея Low Resource Simulation
Low Resource Simulation — это, попросту говоря, fault injection. Идея не в том, чтобы достоверно воссоздать среду с низкими ресурсами, а в том, чтобы искусственно подмешать представительные отказы API, характерные для нехватки ресурсов.
Поэтому область применения довольно чёткая.
- проверка очистки на путях отказа;
- проверка устойчивости retry / reconnect;
- проверка инициализации, где смешаны частичные успехи и частичные отказы;
- проверка того, что логи сохраняются даже для «отказов, которые обычно никогда не случаются».
Хитрость здесь — не заставлять отказывать всё сразу. Если сразу включить всё на полную, логи взрываются, и становится непонятно, «на что вообще смотреть».
5.2. Что можно заставить отказать
С Low Resource Simulation можно вероятностно заставлять отказывать примерно такие классы API.
| Класс | Примеры | Пример в приложении управления оборудованием |
|---|---|---|
Heap_Alloc |
Выделение кучи | Временные буферы, метаданные изображений, внутренние выделения в обёртке SDK |
Virtual_Alloc |
Выделение виртуальной памяти | Более крупные буферы кадров, кольцевые буферы |
File |
CreateFile и подобное |
Открытие путей сохранения и файлов логов |
Event |
CreateEvent и подобное |
Уведомление о готовности кадра, синхронизация stop/reconnect |
MapView |
CreateMapView и подобное |
Разделяемая память и memory mapped file |
Ole_Alloc |
SysAllocString и подобное |
Граница COM / OLE |
Wait |
Семейство WaitForXXX |
Вокруг отказов ожидания синхронизации |
Registry |
Обращение к реестру | Чтение/запись настроек и параметров вокруг драйверов |
На практике важно не открывать всё одновременно, а сужаться, начиная с классов, ближе всего к интересующему на этот раз пути отказа.
5.3. Как применять это на практике
Как набросок командной строки, это выглядит, например, так.
appverif /verify CameraHarness.exe
appverif /verify CameraHarness.exe /faults
appverif -enable lowres -for CameraHarness.exe -with heap_alloc=20000 virtual_alloc=20000 file=20000 event=20000
appverif -query lowres -for CameraHarness.exe
Подход выглядит примерно так.
- сначала прогнать штатный путь с одним лишь
Basics; - затем добавить
Low Resource Simulationи прогнать с fault injection; - при необходимости назначить вероятности только тем отказам, которые хотим увидеть — например,
fileилиevent; - если нужно нацелиться на конкретную DLL, ограничить injection этой DLL.
Сокращение /faults удобно, но само по себе оно сосредоточено в основном на OLE_ALLOC и HEAP_ALLOC.
Если нужно посмотреть на пути отказа CreateFile или CreateEvent, надёжнее явно прописать -enable lowres -with file=... event=....
В приложениях управления оборудованием часто проще читать результаты, если сузить injection до обёртки камеры или DLL пути сохранения, а не разбрасывать отказы по всему приложению.
Например, можно построить такие сценарии.
- отказ
CreateEventсразу после начала reconnect; - отказ
CreateFileпри начале сохранения; - отказ выделения временного буфера;
- отказ
SysAllocStringпри преобразовании COM; - проверка путей отказа API ожидания.
Всё это практически невозможно пройти обычным тестированием штатного пути. Именно поэтому намеренно наступать на них — оправданно.
6. Как смотреть на аномалии хендлов
6.1. Проверка Handles
Для всего, что связано с хендлами, начинают с Handles.
Это упрощает выявление использования недействительных хендлов.
Типично он ловит такие происшествия.
- повторное использование хендла после его закрытия;
- передачу повреждённого значения хендла;
- использование хендла, оставшегося неинициализированным из-за частичного отказа;
- обращение из другого потока при нарушенном времени жизни.
Там, где долгая работа показала бы лишь «изредка появляется странная ошибка», под verifier можно остановиться прямо на месте. Это опережение помогает очень сильно.
6.2. Смотрим стек open / close через !htrace
Handles ценен тем, что хорошо сочетается с handle tracing.
windbg -xd av -xd ch -xd sov CameraHarness.exe
!avrf
!htrace 0x00000ABC
С !htrace хочется увидеть примерно следующее.
- где этот хендл был открыт;
- где он был закрыт;
- был ли он использован как недействительный хендл;
- не накапливается ли opens больше ожидаемого.
Утечки хендлов и их неправильное использование неприятны тем, что API, на котором всё в итоге упало, не является истинной причиной.
С !htrace можно довольно конкретно проследить историю этого хендла.
6.3. Как сочетать это с собственными логами
Тем не менее одного Application Verifier недостаточно. В частности, вести расследование утечки долго резидентного EXE только на нём одном — довольно тяжело.
Поэтому на практике мы сочетаем следующее.
- периодический
Handle Count; sessionId;resourceId;phase;- логи жизненного цикла create/open и close/dispose;
- дампы и вывод отладчика в момент verifier stop.
С этим можно проследить, например, так.
- heartbeat показывает, что наклон
Handle Countподозрителен; - логи жизненного цикла сужают круг до ресурса, у которого есть
Create, но нетClose; - прогон verifier заранее выявляет недействительный хендл или неправильное использование;
!htraceпоказывает стеки open / close.
Эта комбинация заметно упрощает расследование.
7. Как строить основу для тестирования нештатных сценариев
7.1. Переносим единицу запуска в harness
Application Verifier нельзя включить задним числом для уже работающего процесса. Сначала настройка, затем запуск.
К тому же настройка сохраняется, пока её явно не удалить. Поэтому на практике удобнее нацеливаться на тестовый harness EXE, а не на само продуктивное приложение.
Например, такая конфигурация.
flowchart LR
A[Scenario Runner] --> B[CameraHarness.exe]
B --> C[CameraSdkWrapper.dll]
C --> D[SDK производителя]
B --> E[Structured Log]
B --> F[Дамп / отладчик]
Это даёт такие преимущества:
- можно запускать по одному сценарию на процесс;
- разницу утечек легко видеть;
- легко переключать включение/выключение настроек AppVerifier;
- при тестировании DLL можно оперировать через сторону EXE.
Команды выглядят так.
appverif /verify CameraHarness.exe
appverif /n CameraHarness.exe
Включение — до запуска, отключение — явное. Если прогонять это, исходя из harness, легче избежать и происшествий с настройками.
7.2. Разделяем меню тестов
В основе для тестирования нештатных сценариев лучше не делать всё за один прогон. Разделение примерно на три следующих направления делает результаты понятнее.
- Штатный путь + Basics
- не вносим ни одного отказа;
- подтверждаем, что verifier stop не возникает.
- Направление fault injection
Low Resource Simulation;- целенаправленно вызываем отказы
event/file/heap_alloc/virtual_allocи подобных.
- Направление углублённого анализа кучи
Heaps;- full page heap;
- воспроизводим локально под отладчиком.
Такое разделение не даёт смешаться «ломается ли это при обычном использовании» и «ломается ли это только при нехватке ресурсов».
Наличие или отсутствие fault injection особенно сильно меняет проходимые пути кода. Поэтому стоит прогонять и прогон без fault, и прогон с fault.
7.3. Что собирать
Как минимум стоит фиксировать следующее.
| Категория | Что нужно |
|---|---|
| Логи приложения | cameraId, sessionId, phase, handleCount, код ошибки |
| Состояние процесса | Handle Count, Private Bytes, Thread Count |
| Информация отладчика | !avrf, !htrace, при необходимости !heap -p -a |
| Дампы | В момент verifier stop или при аварийном завершении |
| Логи AppVerifier | Записи stop, при необходимости экспорт в XML для агрегации |
При необходимости логи со стороны AppVerifier тоже можно экспортировать в XML и агрегировать. Но одних их часто недостаточно, чтобы замкнуть причину, поэтому практичнее читать их вместе с собственными логами.
Сам по себе большой объём логов ничего не стоит. Важно, чтобы причинно-следственную связь можно было восстановить позже.
7.4. Критерии приёмки
Критерий приёмки «не упало» тоже слишком слаб. В этом контексте нам требовалось как минимум следующее.
- в прогоне штатного пути + Basics нет verifier stop;
- даже при fault injection ожидаемые отказы остаются в логах;
- половинчато инициализированные ресурсы аккуратно приводятся в порядок;
- после reconnect / retry
Handle Countвозвращается близко к baseline; - при возникновении verifier stop его можно проследить по
sessionId/phase/ стеку; - ни один отказ не превращается в «непонятно, что произошло».
Здесь важно оценивать «не ломается» и «прослеживаемость при поломке» как отдельные вещи.
7.5. Предостережения
Application Verifier весьма удобен, но это не волшебство.
- пути кода, реально не пройденные, не верифицируются;
- full page heap тяжеловесен;
- stop может возникать и внутри стороннего SDK;
- проходимые пути кода заметно отличаются с fault injection и без;
- это не единственный инструмент для расследования утечек чисто управляемой кучи.
Поэтому позиционирование такое.
- наклон долгой работы — собственные логи и счётчики;
- неправильное использование на нативной границе — Application Verifier;
- восстановление причинно-следственной связи при аномалии — structured log + дамп + отладчик.
Такое разделение труда наиболее практично.
8. Как выбирать (кратко)
- Подозреваете недействительный хендл или двойной close
Handles+!htrace
- Подозреваете повреждение кучи / use-after-free
Heaps+ full page heap +!heap -p -a
- Хотите вызвать явление, похожее на нехватку памяти или ресурсов
Low Resource Simulation
- Постепенно ломается при долгой работе
- сначала собственный
Handle Count/Private Bytes/ лог жизненного цикла
- сначала собственный
- Хотите протестировать DLL
- включите Application Verifier для harness EXE, вызывающего эту DLL
Если сразу включить всё на полную, обычно получается туман из логов. Применение лезвия, ближайшего к интересующему пути отказа, заметно понятнее.
9. Итог
Позиционирование Application Verifier — это рантайм-верификатор нативной / Win32-границы Windows. С помощью Handles / Heaps / Locks / Memory / TLS / Low Resource Simulation и остального можно заранее заставить пройти редко проявляющиеся пути отказа.
В этом контексте окупились следующие моменты: аномалии хендлов стало легко отслеживать через !htrace в момент их возникновения; явления, похожие на нехватку памяти и ресурсов, удалось вызывать, не ломая всю машину целиком; и мы смогли подтвердить, действительно ли собственные логи будут полезны в этот момент.
Что касается практического способа прогона: разделите прогон штатного пути + Basics и прогоны с fault injection, подготовьте harness EXE и прогоняйте сценарии через короткоживущие процессы. Дополнительно сочетайте это с собственными логами, дампами и информацией отладчика, а сам наклон долгих утечек отслеживайте собственными счётчиками — таково разделение труда.
Application Verifier — это инструмент, чтобы «выходить навстречу» редким аномалиям, а не «ждать», пока они случатся.
В приложениях управления оборудованием важно не только не ломаться, но и одинаково важно уметь объяснить, что произошло, когда что-то всё же сломалось. В этом смысле мы считаем его весьма практичным инструментом.
10. Справочные материалы
- Часть 1: Когда приложение управления промышленной камерой неожиданно падает через месяц (часть 1) — как искать утечки хендлов и проектировать логи для долгой эксплуатации
- Application Verifier - Overview
- Application Verifier - Testing Applications
- Application Verifier - Tests within Application Verifier
- Application Verifier - Debugging Application Verifier Stops
- Application Verifier - Features
- !htrace (WinDbg)
- GetProcessHandleCount function (processthreadsapi.h)
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Расследование краша промышленной камеры при длительной работе — часть про утечку хендлов
Разбираем, как смотреть на Windows-приложение, которое неожиданно падает после длительной работы, на примере приложения управления промыш...
Почему TCP-ретрансмиссии останавливают связь с промышленной камерой, и как это диагностировать
Разбираем, как искать причину, когда связь с промышленной камерой останавливается на несколько секунд из-за TCP-ретрансмиссий: потери пак...
Реагирование на инциденты не заканчивается восстановлением — шаблон постмортема (предотвращения повторения) для небольших команд разработки
Считать инцидент закрытым сразу после исправления и извинений — гарантированный способ повторить его снова. Адаптируем blameless-постморт...
Спящий режим, гибернация, Modern Standby и долго работающие приложения — как проектированием предотвратить «остановилось ночью»
Разбираем, почему долго работающее Windows-приложение оказывается «остановленным к утру», начиная с различий между спящим режимом S3, гиб...
Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу
Разбираем практический план начала эксплуатации и сопровождения бизнес-системы, у которой нет ни исходного кода, ни спецификаций. Охватыв...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Расследование ошибок и долгие сбои
Периодические сбои, диагностика связи, сбои после длительной работы и проверка путей отказа.
Связанные примеры проектов
В этих примерах используется сходный подход к анализу, расстановке приоритетов или переработке.
Инфраструктура тестирования ошибочных сценариев с Application Verifier
Кейс о создании основы для тестирования ошибочных сценариев, которая упрощает последующие расследования.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Расследование ошибок и причин
Application Verifier и основа для тестирования нештатных сценариев — центральная тема расследования сбоев и анализа первопричин, которая продвигает воспроизведение сбоя и определение причины.
Технические консультации и ревью дизайна
Если нужно продумать, насколько глубоко закладывать в проектирование тестирование нештатных сценариев и точки наблюдения, это можно рассмотреть в рамках технической консультации и ревью архитектуры.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Что такое Application Verifier?
- Инструмент рантайм-верификации для пользовательских приложений Windows. Он наблюдает за тем, как работающее приложение использует API ОС и обращается с ресурсами, позволяет выявлять подозрительное использование — вроде обращения к недействительному хендлу или повреждения кучи — и намеренно вносить отказы. В отличие от статического анализа или модульных тестов, это инструмент, показывающий, как всё ломается при реальном прохождении данного пути кода, поэтому он хорошо подходит для выявления путей отказа, невидимых в обычном функциональном тестировании.
- Можно ли с помощью Application Verifier воспроизвести нехватку памяти?
- С Low Resource Simulation можно заранее вызвать явление, близкое к нехватке памяти или ресурсов, не доводя реальную оперативную память машины до истощения. Механизм — это fault injection: вызовы API вроде HeapAlloc, VirtualAlloc, CreateFile, CreateEvent намеренно завершаются отказом с заданной вероятностью. Можно нацелить отказы и на конкретную DLL, поэтому это удобно и в конфигурации, где смешаны собственная обёртка и SDK производителя. Тем не менее, если сразу включить отказ для всего подряд, логи станет невозможно читать, поэтому хитрость в том, чтобы сужать выбор, начиная с того, что ближе всего к интересующему пути отказа.
- Можно ли использовать Application Verifier для расследования утечки хендлов?
- Включив проверку Handles, можно выявлять использование недействительных хендлов — например, повторное использование уже закрытого хендла, — а поскольку при этом автоматически включается и handle tracing, через !htrace можно проследить стек open / close для конкретного хендла. Тем не менее полностью перекладывать расследование утечки долго резидентного EXE на один только Application Verifier нереалистично. На практике удобнее сочетать его с периодической записью Handle Count и собственными логами жизненного цикла ресурсов: обнаружение наклона — через собственные логи, обнаружение неправильного использования — через verifier.
- Как использовать Application Verifier для тестирования DLL?
- Application Verifier включается для тестового EXE, который реально запускает эту DLL. Включить его для уже работающего процесса задним числом нельзя — нужно сначала настроить, а затем запускать. К тому же настройка сохраняется, пока её явно не удалят, поэтому удобнее применять её к тестовому harness EXE, а не к самому продуктивному приложению. Если запускать один сценарий на один процесс, разницу утечек легче увидеть, а включение и выключение настройки — легче переключать.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.
Публичные ссылки