Pull to refresh

Comments 11

Интересная статья, вообще хотелось бы побольше статей о возможностях пакета Microsoft Debugging Tools for Windows.
У Джона Роббинса в книжке Debugging Applications for Microsoft Windows несколько глав посвящены WinDBG. Эту книжку кстати бесплатно раздавали некоторое время назад как часть «Боекомплекта разработчика». Так что, если хорошо поискать, можно найти pdf на русском (не распознанный, а оригинальный).

Ещё есть на CodeProject неплохой для старта WinDbg Tutorial. Но лучше конечно Джона Роббинса почитать.
Спасибо, не знал про эту книгу.
Бесплатный? — хорошо, попробуем. А на Линуксе — valgrind
Мне вот как раз на винде долго не хватало valgrind'a. А потом я узнал про AppVerifier.
Но ошибка будет обнаружена только в том случае, если читаемая/записываемая память уже недоступна.
То есть выход за пределы массива (в некоторых случаях) или чтение из памяти, которая была освобождена, но потом снова выделена (ведь система может дать программе блок памяти, который был только что освобождён) — к сожалению автоматически не обнаружить.

Так что стоит помнить, что это — не панацея.
В данном случае была запись в освобожденную, но ещё не выделенную память. Если бы память была уже выделена, ошибки бы как раз не было — просто испортили бы чужие данные.

Ну и да, конечно не панацея. Но в некоторых случаях помогает.
Спасибо, интересная статья. Вопрос — насколько реально таким образом ловить ошибки в больших приложениях, то есть какой процент оверхеда при запуске с приатаченной тулзой? И сколько памяти уходит под дополнительные дампы?
Вопрос — насколько реально таким образом ловить ошибки в больших приложениях
Ну вот я пытаюсь ловить периодически. Иногда даже получается :)

Недавно пытаясь воспроизвести багу нашел ошибку работы с памятью в совершенно независимом коде, который уже некоторое время работал без нареканий. Просто он вызывался во время инициализации приложения и пропустить его я не мог, а он с влюченным AppVerifier падал :)

то есть какой процент оверхеда при запуске с приатаченной тулзой? И сколько памяти уходит под дополнительные дампы?
Это сильно зависит от настроек — какие проверки включить, какие нет.

С включенным Full Page Heap затормаживается раза в 2-3 и потребление памяти вырастает существенно (не могу сказать на сколько, но были случаи, когда софт не мог стартануть до конца потому что malloc возвращал 0 (в нормальном режиме Working Set до 1.8 GB доходит, тут дошел до 2.5). Выключение Full Page Heap сильно снижает потребление памяти и тормоза, но возможно что потом !heap -p -a не покажет стек.

DeCommit уменьшает потребление памяти, но понижает вероятность страбатывания Verifier Stop'a.

Если вдруг нужно отловить не overrun, а underrun — приходится включать Backward, который в принудительном порядке включает Full. Это ещё сильнее увеличивает потребление памяти и тормоза.

Ещё можно в Dlls указать, чтобы проверки применялись не ко всему коду, а только к коду из указанных dll. Тоже существенно снижает оверхед, но надо быть уверенным, что ошибка в определенном модуле.
У меня был такой вариант отладки:
* при ошибке приложения на целевом ПК и появлении стандартного окна «Отправить отчет» переходил в детальное описание. Там содержится информация о дампе памяти приложения по адресу c:\documents and settings\%username%\Temp\TMPbla-bla-bla\.dmp При этом ни каких студий, пакетов отладчиков на том ПК не было, но мое приложение было собрано в отладочном режиме.
* копировал содержимое этой папки не закрывая окна отправки отчета (при закрытии содержимое папки и сама папка удаляются)
* уже на своей рабочей машине открывал дамп в WinDBG с подгрузкой исходников и спокойно рассматривал содержимое всех переменных, стек и прочие детали.

ошибка нашлась достаточно быстро, оверхеда не было вообще, если не считать того, что само приложение было не релизной версии :)
Релизы тоже можно так отлаживать, если они были собраны с отладочной инфой. Сами pdb не обязательно кому-то отдавать, главное чтобы они присутствовали на той машине, где будет открываться дамп и соответствовали бинарям, с которых снят дамп. Отладчик правда может ошибаться на пару строк, неправильно показывать значения некоторых переменных, но по крайней мере будет видно стек.

А описанный вами способ подходит для некоторых случаев, когда по коллстеку сразу видно, в чем ошибка. С этого надо начинать. Но не всегда так везёт. Например, если приведенный пример запускать без AppVerifier, он будет падать в цикле вывода в cout. И попробуй потом догадайся, кто же испортил память.
Sign up to leave a comment.

Articles