SlideShare a Scribd company logo
Когда у нас не воспроизводится
Александр Головач
+
+ +
+
+
+
+
О себе
Александр Головач
Системный программист в
Checkpoint Software Technologies Ltd.
Почему отладка сложна
На практике встречаются ситуации, когда:
● Воспроизведение дефекта непредсказуемо
● Дефект проявляется в специфичном окружении, доступ к которому
может быть ограничен
● Для воспроизведения дефекта необходимо время
● Для воспроизведения дефекта необходима определенная
последовательность событий
● Процесс отладки ведет к нарушению работы ПО, что порой крайне не
желательно
3
Прежде чем мы начнем
4
Адресное пространство процесса
5
Пространство ядра
(общее для всех
процессов,
недоступно из
пользовательского
кода)
Пространство
пользователя
(у каждого процесса
свое изолированное)
USER MODE KERNEL MODE
Адресное пространство процесса - UM
6
DLLs
Heap (at least one)
Executable image
Stack (per each thread)
Thread environment block (TEB) – per thread
Process environment block (PEB)
Дамп памяти процесса
7
HEADER
Context info+
info from OS
.DMP
Дамп памяти процесса
8
HEADER
Context info+
info from OS
Где в дампе памяти находится . . . :
● Информация о модулях, командной строке, переменных окружения - PEB
● Глобальные и статические переменные – секция данных модуля
● Локальные переменные – стек
● Динамические данные – куча. Адреса ищи в глобальных или локальных
переменных (см. выше)
● Какой именно код выполнялся в потоке – регистр EIP
● Последовательность вызовов функций – адреса возврата на стеке
.DMP
Как собрать дамп ?
9
● Используйте Procdump !
● Task manager
● Process Explorer
● Отладчик
Отладочные символы
10
● Отладочные символы (debug symbols) – информация о взаимном
соответствии исходного кода и исполняемого модуля.
● Генерируются компоновщиком.
● Различают публичные и приватные отладочные символы
публичные символы не содержат информацию о типах, номерах строк, локальных переменных и
параметрах функций
● Отладочные символы для Microsoft доступны здесь:
https://msdl.microsoft.com/download/symbols
Утечка дескрипторов на объекты ядра
11
Утечка дескрипторов на объекты ядра
12
● Дескриптор (HANDLE) – идентификатор объекта ядра
● Незакрытый дескриптор приводит к тому, что количество ссылок на
объект ядра не станет равным нулю.
● Теряя дескрипторы на объекты ядра, процесс влияет на другие
процессы и систему в целом
Примеры объектов ядра:
Process, Thread, File, GDI objects (windows, brushes, palettes), ……
Предварительный анализ
13
● Начальный анализ рекомендуется провести с использованием утилит
○ Handle
○ Process monitor
○ Process explorer
● Process explorer может показать дескрипторы процесса, их тип и
имена соответсвующих объектов ядра (если применимо)
● Process monitor показывает активность процесса. Открытие ключей
реестра и файлов журналируется, для операций доступен стек
вызова.
Process Explorer
14
Process Monitor
15
HANDLE
16
Application verifier. Pецепт
17
На машине с воспроизведением:
● Добавить свое приложение в список верифицируемых
● В списке Tests указать Basic->Handles
● Запустить приложение, воспроизвести ошибку
● Собрать дамп
На машине разработчика:
● Открыть дамп памяти
● Использовать команды !htrace, !handle в отладчике WinDbg
Application verifier
18
Windbg. Pецепт
19
● Запустить программу под отладчиком
● Поставить точку останова в контрольной точке [1]
● После остановки программы на точке останова выполнить команду
!htrace -enable, продолжить выполнение
● Поставить точку останова в контрольной точке [2]
● После остановки программы на точке останова выполнить команду
!htrace –diff.
При отладке в среде заказчика собрать дамп процесса (.dump /ma file.dmp)
и выполнить команду !htrace во время анализа на стороне
разработчика.
Пример
20
Подведем
итог
21
● Предварительный анализ выполняем
утилитами Sysinternals
● Система может собирать стеки вызовов
(AppVerifier). Требуется перезапуск процесса
● Если есть возможность подключить
отладчик – пользуемся! Проще, перезапуск
приложение не требуется
Утечка памяти
22
Утечка памяти
23
● Основным признаком утечки является постоянное увеличение объема
памяти, используемой приложением.
● Исследование данной категории проблем предполагает отслеживание
выделения и освобождение памяти, сравнение состояния памяти в
разные моменты времени (так называемых memory snapshots)
● Два основных подхода для получения информации о работе с
динамической памятью: перехват системных вызовов и
использование функционала системы по сбору стеков вызовов
(конфигурируется GFlags/AppVerifier/UMDH)
● В некоторых случаях не требуется предварительная конфигурация
системы
Виды динамической памяти
24
Утилита UMDH
25
● Входит в состав Debugging Tools for Windows
● Работает на уровне Heap Manager’a
● Основная идея следующая:
○ Сделать снимок использования памяти перед воспроизведением (контрольная точка А)
○ Сделать снимок использования памяти после воспроизведения (контрольная точка Б)
○ Сравнить полученные снимки.
Утилита UMDH – перед использованием
26
● Перед использованием утилиты необходимо сконфигурировать пути
поиска отлодочных символов в переменной окружения
_NT_SYMBOL_PATH (на стороне разработчика)
● Также необходимо сконфигурировать систему сохранять стеки
вызовов при выделении памяти (Application Verifier или gflags).
В случае отсутствия конфигурации утилита выполнит конфигурацию
самостоятельно.
Утилита UMDH. Pецепт
27
На машине с воспроизведением:
● UMDH -p:PID > first_snapshot_filename
● Воспроизвести утечку памяти
● UMDH -p:PID > second_snapshot_filename
На машине разработчика:
● UMDH first_snapshot_filename second_snapshot_filename > diff
● Проанализировать файл diff
Подведем
итог
28
● Поиск причины утечки памяти может быть
сложным из-за обилия API / уровней работы
с динамической памятью
● Рекомендуется использовать UMDH для
быстрого исследования: не требует
предварительной конфигурации и
перезапуска процесса
Взаимоблокировка потоков
30
Взаимоблокировки
31
Выделим следующие ситуации:
● Взаимоблокировки при использовании CRITICAL_SECTION, в рамках
одного процесса
● Взаимоблокировки при использовании объектов ядра,
межпроцессные взаимоблокировки
● Взаимоблокировки с использованием примитивов синхронизации С++
Взаимоблокировки
32
● В любом случае сделать дамп памяти процесса
● При анализе дампа распечатать все потоки. Выделить заблокированные.
● В случае c CRITICAL_SECTION использовать команды !cs, !locks. Данный
примитив синхронизации содержит информацию о текущем владельце.
Раскручивание таких цепочек наименее трудоемкое
● В случае использования объектов ядра дампа памяти процесса может
быть недостаточно, необходимо знание логики приложения для анализа
цепочки блокировки.
● При наличии межпроцессной блокировки могут понадобиться дампы всех
задействованных процессов и полный дамп памяти системы.
std::mutex и std::recursive_mutex
33
● Объекты синхронизации с++ активно используют «родные» для
Windows примитивы
● Иногда могут содержать информацию о потоке владельце (зависит от
реализации)
● Из коробки, windbg может найти владельца для std::recursive_mutex
(проверено для VS2017 + WinDbg Preview)
● Немного смекалки – и ту же информацию можно получить и о
std::mutex. Подсказка в файле %windbg_root%visualizersstl.natvis и
немного позже в докладе
std::*mutex
34
Подведем
итог
35
● При блокировке потоков получить дамп
● В большинстве случаев необходимо знание
кода для восстановления цепочки ожидания
● Объекты синхронизации С++ могут
содержать информации о владельце
Аварийное завершение
36
Кабы знал, где упасть, соломки бы подостлал
Народная поговорка
Аварийное завершение
37
● При возникновении в потоке исключительной ситуации система
начинает раскрутку стека в поисках обработчика исключения (англ.
exception handler).
● Если ни один из фильтров не обработает исключение, будет вызван
фильтр необработанных исключений
● По умолчанию фильтр необработанных исключений запускает
процесс werfault.exe, который создает отчет об ошибке.
● Процесс принудительно завершается
При аварийном завершении приложения во многих случаях достаточно
дампа памяти, содержащего информацию о необработанном
исключении.
Аварийное завершение
38
Получить дамп при аварийном завершении можно следующими
способами:
● Сконфигурировать Windows error reporting
● Сконфигурировать Just in time debugger
● Реализовать свой фильтр необработанных исключений
Windows error reporting
39
Конфигурация создания дампов памяти при аварийном завершении
находится: HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows
Windows Error ReportingLocalDumps [ImageName.exe]
DumpFolder Путь к каталогу, в котором будут
сохраняться дампы
REG_EXPAND_SZ
DumpCount Максимальное количество дампов. REG_DWORD
DumpType Тип дампа памяти:
• 0: Custom dump
• 1: Mini dump
• 2: Full dump
REG_DWORD
Just in time debugger
40
Функция в ОС Windows позволяет автоматически запустить отладчик и
подключить его к приложению при возникновении необработанного
исключения
Отладчики имеют возможность зарегестрировать себя самостоятельно.
(для windbg это параметр командной строки -I)
В реестре конфигурация сохраняется в
HKLMSoftwareMicrosoftWindows NTCurrentVersionAeDebug
HKLMSoftwareWow6432NodeMicrosoftWindows
NTCurrentVersionAeDebug
Just in time debugger. Visual Studio
41
OK, у нас есть дамп...
42
Начинаем с !analyze –v. Данная команда проведет первичный анализ
дампа. В случае с аварийным завершением постарается восстановить
контекст процессора на момент возникновения исключительной
ситуации.
Дальнейшие действия зависят от конкретной ситуации.
Memory corruption: возможные причины
43
• Нарушение соглашения о вызовах (поврежден стек)
• Неинициализированные переменные
• Переполнение буфера
• Использование памяти после освобождения
• Возврат из функции ссылки / указателя на локальную переменную
• «Забытые» указатели на переменные, которые могут измениться
другими потоками (незавершенный аснхронный ввод-вывод +
отсутствие вызова CancelIO) – также источник heap corruption
Stack corruption
44
• Многие нарушения обнаруживаются компилятором
• В дампе памяти повреждение стека может быть легко определено
командой k.
• При выходе из функции содержимое стека не стирается, меняется только
значение регистра ESP. Как следствие, можно попытаться восстановить
стек
!teb – показать thread environment block. Это даст нам границы стека
dps – print pointer resolve symbol.
k – распечатать стек. Поддерживает переопределение ESP/EBP
d* - распечатать память
Heap corruption
45
Пожалуй, самый тяжелый для отладки класс проблем
При относительно стабильном воспроизведении рекомендуется
использовать application verifier / gflags для конфигурирования
отладочной кучи
Использование отладочной кучи несколько влияет на
производительность приложения, однако позволяет получить намного
больше информации о блоках динамической памяти, включая стек
вызовов. Также предполагается заполнение блоков памяти
специальными паттернами, упрощающую идентификацию их начала и
конца
Конфигурирование отладочной кучи (gflags)
46
Стек вызовов при выделении блока (дамп)
47
Значение, возвращенное функцией malloc
Недостатки дампов памяти
49
● Дамп файл содержит снимок состояния программы в определенный
момент времени
● Невозможно проследить развитие дефекта во времени
Time travel debugging
50
● Во время отладки Windbg записывает выполнение программы в лог
файл, который позже можно повторно воспроизвести.
● Позволяет выполнять инструкции в обратном порядке. Легко понять
причины, которые привели к ошибке.
● Включает модель данных, позволяющую выполнять LINQ запросы к
сохраненной трассировке
● Значительно влияет на производительность (!) . Отлично подходит
для отладки предсказуемых дефектов
Dump file vs TTD trace
51
52
C:>TTD_DEMO
Автоматизация анализа дампов памяти
53
● Экономия времени на поиск источника проблемы: быстрое
определение модуля с ошибкой и ответственного разработчика
● Позволяет приоритезировать задачи: определение дампов с
одинаковой проблемой и автоматическая группировка
● Экономия времени на анализ аварийных завершений: разработчики
даже не открывают дампы с уже известными проблемами
Для автоматизации используется встроенный скриптовый язык. Можно
также применить расширение PyKd и язык Python
Hапоследок
54
Пару практических советов, как сделать отладку приятнее
● Cmdtree
● Произвольные визуализации
55
C:>DEMO
+
+ +
+
+
+
+
Спасибо за внимание!
golovach@checkpoint.com
+
56

More Related Content

PDF
2012 03 14_parallel_programming_lecture05
PDF
Некриптографическое исследование носителей православной криптографии
PDF
Григорий Демченко — Асинхронное программирование и сопрограммы
ODP
презентацияевстафьева
PPTX
Основы и применение статического анализа кода при разработке лекция 1
PDF
Практика Lock-free. RealTime-сервер
PDF
Formal verification of operating system kernels
PPTX
Asynchrony and coroutines
2012 03 14_parallel_programming_lecture05
Некриптографическое исследование носителей православной криптографии
Григорий Демченко — Асинхронное программирование и сопрограммы
презентацияевстафьева
Основы и применение статического анализа кода при разработке лекция 1
Практика Lock-free. RealTime-сервер
Formal verification of operating system kernels
Asynchrony and coroutines

What's hot (20)

PDF
Hunting for a C++ package manager
PDF
Инструменты тестирования ядра Linux
ODP
презентация костина сравнение 8.1 7
PPT
Лекция №8 Организация ЭВМ и систем
PPTX
Применение фреймворка GStreamer в системе видеонаблюдения
PDF
Lightweight Static Analysis for Data Race Detection in Operating System Kernels
PDF
Static Analysis of Transactions Management in Applications for Java EE Platform
PDF
Цена ошибки
PPT
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
DOC
РусКрипто CTF 2010 Full Disclosure (мастер класс)
PDF
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
PDF
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
PDF
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
PPT
Moscow Exchange Test Automation of a Backup System at TMPA-2014 (Trading Syst...
PDF
Запуск тестов с tox и Docker
PPTX
Асинхронность и сопрограммы
PPT
Sencha Complete: Kharkiv JS #1
PPTX
PVS-Studio, решение для разработки современных ресурсоемких приложений
PPTX
Оптимизация трассирования с использованием Expression templates
Hunting for a C++ package manager
Инструменты тестирования ядра Linux
презентация костина сравнение 8.1 7
Лекция №8 Организация ЭВМ и систем
Применение фреймворка GStreamer в системе видеонаблюдения
Lightweight Static Analysis for Data Race Detection in Operating System Kernels
Static Analysis of Transactions Management in Applications for Java EE Platform
Цена ошибки
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
РусКрипто CTF 2010 Full Disclosure (мастер класс)
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
Moscow Exchange Test Automation of a Backup System at TMPA-2014 (Trading Syst...
Запуск тестов с tox и Docker
Асинхронность и сопрограммы
Sencha Complete: Kharkiv JS #1
PVS-Studio, решение для разработки современных ресурсоемких приложений
Оптимизация трассирования с использованием Expression templates
Ad

Similar to Windbg: когда у нас не воспроизводится. Александр Головач ➠ CoreHard Autumn 2019 (20)

PPTX
Контроль качества и сопровождение программ в реальном времени
PPTX
Антон Наумович - Контроль качества и сопровождение в реальном времени
PPTX
Михаил Щербаков "WinDbg сотоварищи"
PPTX
WinDbg со товарищи
PPTX
WinDbg в руках .NET разработчика
PDF
Ievgen Kulyk - Advanced reverse engineering techniques in unpacking
ODP
Valgrind
PPTX
Бинарные уязвимости и эксплойты: технологии и перспективы
PDF
Неудачная попытка сравнить PVS-Studio (VivaMP) и Intel C/C++ ("Parallel Lint")
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
PPTX
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PPT
Низкоуровневая Оптимизация (Андрей Аксенов)
PPT
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
PPT
PPTX
Эффективный C++
PPTX
Статические анализаторы кода как DevSecOps решение
PPTX
Не связывайтесь с поддержкой C++ программистов. Юрий Минаев. CoreHard Spring ...
PPTX
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
PPTX
Автоматический поиск уязвимостей в программах без исходных текстов
PDF
VivaMP, система выявления ошибок в коде параллельных программ на языке С++, и...
Контроль качества и сопровождение программ в реальном времени
Антон Наумович - Контроль качества и сопровождение в реальном времени
Михаил Щербаков "WinDbg сотоварищи"
WinDbg со товарищи
WinDbg в руках .NET разработчика
Ievgen Kulyk - Advanced reverse engineering techniques in unpacking
Valgrind
Бинарные уязвимости и эксплойты: технологии и перспективы
Неудачная попытка сравнить PVS-Studio (VivaMP) и Intel C/C++ ("Parallel Lint")
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
Низкоуровневая Оптимизация (Андрей Аксенов)
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Эффективный C++
Статические анализаторы кода как DevSecOps решение
Не связывайтесь с поддержкой C++ программистов. Юрий Минаев. CoreHard Spring ...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Автоматический поиск уязвимостей в программах без исходных текстов
VivaMP, система выявления ошибок в коде параллельных программ на языке С++, и...
Ad

More from corehard_by (20)

PPTX
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
PPTX
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
PDF
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
PPTX
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
PPTX
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
PPTX
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
PPTX
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
PPTX
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
PPTX
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
PPTX
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
PDF
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
PDF
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
PDF
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
PPTX
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
PDF
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
PDF
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019

Windbg: когда у нас не воспроизводится. Александр Головач ➠ CoreHard Autumn 2019

  • 1. Когда у нас не воспроизводится Александр Головач + + + + + + +
  • 2. О себе Александр Головач Системный программист в Checkpoint Software Technologies Ltd.
  • 3. Почему отладка сложна На практике встречаются ситуации, когда: ● Воспроизведение дефекта непредсказуемо ● Дефект проявляется в специфичном окружении, доступ к которому может быть ограничен ● Для воспроизведения дефекта необходимо время ● Для воспроизведения дефекта необходима определенная последовательность событий ● Процесс отладки ведет к нарушению работы ПО, что порой крайне не желательно 3
  • 4. Прежде чем мы начнем 4
  • 5. Адресное пространство процесса 5 Пространство ядра (общее для всех процессов, недоступно из пользовательского кода) Пространство пользователя (у каждого процесса свое изолированное) USER MODE KERNEL MODE
  • 6. Адресное пространство процесса - UM 6 DLLs Heap (at least one) Executable image Stack (per each thread) Thread environment block (TEB) – per thread Process environment block (PEB)
  • 8. Дамп памяти процесса 8 HEADER Context info+ info from OS Где в дампе памяти находится . . . : ● Информация о модулях, командной строке, переменных окружения - PEB ● Глобальные и статические переменные – секция данных модуля ● Локальные переменные – стек ● Динамические данные – куча. Адреса ищи в глобальных или локальных переменных (см. выше) ● Какой именно код выполнялся в потоке – регистр EIP ● Последовательность вызовов функций – адреса возврата на стеке .DMP
  • 9. Как собрать дамп ? 9 ● Используйте Procdump ! ● Task manager ● Process Explorer ● Отладчик
  • 10. Отладочные символы 10 ● Отладочные символы (debug symbols) – информация о взаимном соответствии исходного кода и исполняемого модуля. ● Генерируются компоновщиком. ● Различают публичные и приватные отладочные символы публичные символы не содержат информацию о типах, номерах строк, локальных переменных и параметрах функций ● Отладочные символы для Microsoft доступны здесь: https://msdl.microsoft.com/download/symbols
  • 11. Утечка дескрипторов на объекты ядра 11
  • 12. Утечка дескрипторов на объекты ядра 12 ● Дескриптор (HANDLE) – идентификатор объекта ядра ● Незакрытый дескриптор приводит к тому, что количество ссылок на объект ядра не станет равным нулю. ● Теряя дескрипторы на объекты ядра, процесс влияет на другие процессы и систему в целом Примеры объектов ядра: Process, Thread, File, GDI objects (windows, brushes, palettes), ……
  • 13. Предварительный анализ 13 ● Начальный анализ рекомендуется провести с использованием утилит ○ Handle ○ Process monitor ○ Process explorer ● Process explorer может показать дескрипторы процесса, их тип и имена соответсвующих объектов ядра (если применимо) ● Process monitor показывает активность процесса. Открытие ключей реестра и файлов журналируется, для операций доступен стек вызова.
  • 17. Application verifier. Pецепт 17 На машине с воспроизведением: ● Добавить свое приложение в список верифицируемых ● В списке Tests указать Basic->Handles ● Запустить приложение, воспроизвести ошибку ● Собрать дамп На машине разработчика: ● Открыть дамп памяти ● Использовать команды !htrace, !handle в отладчике WinDbg
  • 19. Windbg. Pецепт 19 ● Запустить программу под отладчиком ● Поставить точку останова в контрольной точке [1] ● После остановки программы на точке останова выполнить команду !htrace -enable, продолжить выполнение ● Поставить точку останова в контрольной точке [2] ● После остановки программы на точке останова выполнить команду !htrace –diff. При отладке в среде заказчика собрать дамп процесса (.dump /ma file.dmp) и выполнить команду !htrace во время анализа на стороне разработчика.
  • 21. Подведем итог 21 ● Предварительный анализ выполняем утилитами Sysinternals ● Система может собирать стеки вызовов (AppVerifier). Требуется перезапуск процесса ● Если есть возможность подключить отладчик – пользуемся! Проще, перезапуск приложение не требуется
  • 23. Утечка памяти 23 ● Основным признаком утечки является постоянное увеличение объема памяти, используемой приложением. ● Исследование данной категории проблем предполагает отслеживание выделения и освобождение памяти, сравнение состояния памяти в разные моменты времени (так называемых memory snapshots) ● Два основных подхода для получения информации о работе с динамической памятью: перехват системных вызовов и использование функционала системы по сбору стеков вызовов (конфигурируется GFlags/AppVerifier/UMDH) ● В некоторых случаях не требуется предварительная конфигурация системы
  • 25. Утилита UMDH 25 ● Входит в состав Debugging Tools for Windows ● Работает на уровне Heap Manager’a ● Основная идея следующая: ○ Сделать снимок использования памяти перед воспроизведением (контрольная точка А) ○ Сделать снимок использования памяти после воспроизведения (контрольная точка Б) ○ Сравнить полученные снимки.
  • 26. Утилита UMDH – перед использованием 26 ● Перед использованием утилиты необходимо сконфигурировать пути поиска отлодочных символов в переменной окружения _NT_SYMBOL_PATH (на стороне разработчика) ● Также необходимо сконфигурировать систему сохранять стеки вызовов при выделении памяти (Application Verifier или gflags). В случае отсутствия конфигурации утилита выполнит конфигурацию самостоятельно.
  • 27. Утилита UMDH. Pецепт 27 На машине с воспроизведением: ● UMDH -p:PID > first_snapshot_filename ● Воспроизвести утечку памяти ● UMDH -p:PID > second_snapshot_filename На машине разработчика: ● UMDH first_snapshot_filename second_snapshot_filename > diff ● Проанализировать файл diff
  • 28. Подведем итог 28 ● Поиск причины утечки памяти может быть сложным из-за обилия API / уровней работы с динамической памятью ● Рекомендуется использовать UMDH для быстрого исследования: не требует предварительной конфигурации и перезапуска процесса
  • 30. Взаимоблокировки 31 Выделим следующие ситуации: ● Взаимоблокировки при использовании CRITICAL_SECTION, в рамках одного процесса ● Взаимоблокировки при использовании объектов ядра, межпроцессные взаимоблокировки ● Взаимоблокировки с использованием примитивов синхронизации С++
  • 31. Взаимоблокировки 32 ● В любом случае сделать дамп памяти процесса ● При анализе дампа распечатать все потоки. Выделить заблокированные. ● В случае c CRITICAL_SECTION использовать команды !cs, !locks. Данный примитив синхронизации содержит информацию о текущем владельце. Раскручивание таких цепочек наименее трудоемкое ● В случае использования объектов ядра дампа памяти процесса может быть недостаточно, необходимо знание логики приложения для анализа цепочки блокировки. ● При наличии межпроцессной блокировки могут понадобиться дампы всех задействованных процессов и полный дамп памяти системы.
  • 32. std::mutex и std::recursive_mutex 33 ● Объекты синхронизации с++ активно используют «родные» для Windows примитивы ● Иногда могут содержать информацию о потоке владельце (зависит от реализации) ● Из коробки, windbg может найти владельца для std::recursive_mutex (проверено для VS2017 + WinDbg Preview) ● Немного смекалки – и ту же информацию можно получить и о std::mutex. Подсказка в файле %windbg_root%visualizersstl.natvis и немного позже в докладе
  • 34. Подведем итог 35 ● При блокировке потоков получить дамп ● В большинстве случаев необходимо знание кода для восстановления цепочки ожидания ● Объекты синхронизации С++ могут содержать информации о владельце
  • 35. Аварийное завершение 36 Кабы знал, где упасть, соломки бы подостлал Народная поговорка
  • 36. Аварийное завершение 37 ● При возникновении в потоке исключительной ситуации система начинает раскрутку стека в поисках обработчика исключения (англ. exception handler). ● Если ни один из фильтров не обработает исключение, будет вызван фильтр необработанных исключений ● По умолчанию фильтр необработанных исключений запускает процесс werfault.exe, который создает отчет об ошибке. ● Процесс принудительно завершается При аварийном завершении приложения во многих случаях достаточно дампа памяти, содержащего информацию о необработанном исключении.
  • 37. Аварийное завершение 38 Получить дамп при аварийном завершении можно следующими способами: ● Сконфигурировать Windows error reporting ● Сконфигурировать Just in time debugger ● Реализовать свой фильтр необработанных исключений
  • 38. Windows error reporting 39 Конфигурация создания дампов памяти при аварийном завершении находится: HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows Windows Error ReportingLocalDumps [ImageName.exe] DumpFolder Путь к каталогу, в котором будут сохраняться дампы REG_EXPAND_SZ DumpCount Максимальное количество дампов. REG_DWORD DumpType Тип дампа памяти: • 0: Custom dump • 1: Mini dump • 2: Full dump REG_DWORD
  • 39. Just in time debugger 40 Функция в ОС Windows позволяет автоматически запустить отладчик и подключить его к приложению при возникновении необработанного исключения Отладчики имеют возможность зарегестрировать себя самостоятельно. (для windbg это параметр командной строки -I) В реестре конфигурация сохраняется в HKLMSoftwareMicrosoftWindows NTCurrentVersionAeDebug HKLMSoftwareWow6432NodeMicrosoftWindows NTCurrentVersionAeDebug
  • 40. Just in time debugger. Visual Studio 41
  • 41. OK, у нас есть дамп... 42 Начинаем с !analyze –v. Данная команда проведет первичный анализ дампа. В случае с аварийным завершением постарается восстановить контекст процессора на момент возникновения исключительной ситуации. Дальнейшие действия зависят от конкретной ситуации.
  • 42. Memory corruption: возможные причины 43 • Нарушение соглашения о вызовах (поврежден стек) • Неинициализированные переменные • Переполнение буфера • Использование памяти после освобождения • Возврат из функции ссылки / указателя на локальную переменную • «Забытые» указатели на переменные, которые могут измениться другими потоками (незавершенный аснхронный ввод-вывод + отсутствие вызова CancelIO) – также источник heap corruption
  • 43. Stack corruption 44 • Многие нарушения обнаруживаются компилятором • В дампе памяти повреждение стека может быть легко определено командой k. • При выходе из функции содержимое стека не стирается, меняется только значение регистра ESP. Как следствие, можно попытаться восстановить стек !teb – показать thread environment block. Это даст нам границы стека dps – print pointer resolve symbol. k – распечатать стек. Поддерживает переопределение ESP/EBP d* - распечатать память
  • 44. Heap corruption 45 Пожалуй, самый тяжелый для отладки класс проблем При относительно стабильном воспроизведении рекомендуется использовать application verifier / gflags для конфигурирования отладочной кучи Использование отладочной кучи несколько влияет на производительность приложения, однако позволяет получить намного больше информации о блоках динамической памяти, включая стек вызовов. Также предполагается заполнение блоков памяти специальными паттернами, упрощающую идентификацию их начала и конца
  • 46. Стек вызовов при выделении блока (дамп) 47 Значение, возвращенное функцией malloc
  • 47. Недостатки дампов памяти 49 ● Дамп файл содержит снимок состояния программы в определенный момент времени ● Невозможно проследить развитие дефекта во времени
  • 48. Time travel debugging 50 ● Во время отладки Windbg записывает выполнение программы в лог файл, который позже можно повторно воспроизвести. ● Позволяет выполнять инструкции в обратном порядке. Легко понять причины, которые привели к ошибке. ● Включает модель данных, позволяющую выполнять LINQ запросы к сохраненной трассировке ● Значительно влияет на производительность (!) . Отлично подходит для отладки предсказуемых дефектов
  • 49. Dump file vs TTD trace 51
  • 51. Автоматизация анализа дампов памяти 53 ● Экономия времени на поиск источника проблемы: быстрое определение модуля с ошибкой и ответственного разработчика ● Позволяет приоритезировать задачи: определение дампов с одинаковой проблемой и автоматическая группировка ● Экономия времени на анализ аварийных завершений: разработчики даже не открывают дампы с уже известными проблемами Для автоматизации используется встроенный скриптовый язык. Можно также применить расширение PyKd и язык Python
  • 52. Hапоследок 54 Пару практических советов, как сделать отладку приятнее ● Cmdtree ● Произвольные визуализации
  • 54. + + + + + + + Спасибо за внимание! golovach@checkpoint.com + 56

Editor's Notes

  • #4: Упомянуть о стоимости исправления дефекта с ссылкой на, хотя бы, PVS-studio Рассказать о неловких ситуациях во время remote (не потерять бы лицо и заказчика)