Best tools noone uses: PREfast
Начитавшись про правильные практики, наконец заставил себя ознакомиться со словом PREfast и вообще статическими анализаторами.
В отличие от других тулзов из сериала, про которые просто мало кто слышал - PREfast вдобавок неплохо спрятан, и, мнэээ, несколько неказуален в применении. Поэтому вдобавок расскажу - где брать, как применять.
Для начала главный вопрос - зачем это все. Статический анализ кода (static code analysis) нужен для автоматического обнаружения code/data flow багов - утечек памяти, выходов за границы, прочих приятных вещей. Компилятор особо глубоким анализом не занимается, поэтому не может. Программист может, но хер когда занимается. Отсюда потребность в роботе, который одновременно умнее компилятора, и усерднее программиста.
Язык C++ непростой, поэтому анализаторов для него мало. Опен-сорсных нет совсем, кроме разве что Oink и брата его Mozilla Pork. Сложности с ними начинаются уже на стадии сборки, причем под родным Linux. Собрать за часок-другой применения напильника мне его (Pork) удалось; а вот добиться работы на приложенном тривиальном тесте уже нет. В общем, если есть лишний год-другой, можно попытаться собрать под Windows (это развлечет вас первые 2-3 месяца) и затем проанализировать боевой проект (а это остаток года). Платных анализаторов есть, но пересчитать удается по щупальцам одного, максимум двух осьминогов; при этом лидеры типа Coverity, Klocwork итп стоят измеримых денег. Это заметно сразу по сайтам, где невозможно найти ни цены, ни кнопки Buy, только предложения связаться с сейлами. Сразу ясно, что цена вопроса далеко не $1000. И правда, Гугл докладывает о ценнике за инсталляцию на 0.5 MLOC порядка $20000-50000. В год. Каждый год. Поэтому, фактически, PREfast - это единственный доступный нам, нищим (см. бесплатно!), работающий, и безусловно полезный анализатор.
Полезность ощутилась сразу. В ходе первого же тестового прогона “для души и смеха” тот PREfast выявил совершенно, конечно, дебильную утечку - однако с последствиями этой утечки (см. тихие мистические вылеты раз в 2-5 дней) по невероятному совпадению я, несмотря на тривиальность бага, недолгими припадками боролся всю прошлую неделю. Эх, знал бы, что и где искать… да, сразу же нашел бы себе клад из золотых червонцев, самогона полный дом, все гори оно огнем. А пока дальше про статический анализ.
PREfast for Drivers (по слухам, это расширенная и углубленная версия “обычного”) берется в составе Windows Driver Kit (WDK). Где брать WDK с целью припасть к наномегатехнологии - английским по белому и довольно подробно рассказано в этой статье. Теоретически, нужна бесплатная регистрация на live.com, затем жалких 12 веб-форм с пиксель-хантом, и золотой ключик наш. Практически, 12й шаг эпопеи кончается секретным линком, который сегодня вел на WDK_6001_18001.iso (632.9 MB) и работал без всяких регистраций. Еще можно успеть.
Упомянутый “обычный” анализатор, кстати, по слухам встроен в Visual Studio начиная с 2005 - прямо в cl.exe, посредством ключа /analyze и тайных строк в меню собственно среды разработки. Проверить не удалось, тк. Team System под руками не очутилось, а в Professional/Standard/Express ничего подобного не наблюдается. Таким образом, доплатив к $300, которые стоит VS 2008 Standard всего лишь $5200, нужных для покупки VS TS 2008 Development Edition, можно легко обойтись без необходимости качать WDK. В такой вопиющей ситуации - лично я бы спрятал напрочь бесплатный WDK минимум на 120 шагов. Налицо недоработка веб-мастеров.
На случай самоликвидации залинкованной статьи (ну или очередных переделок на сайтах MS) кратко скопирую тут шаги:
- Если надо, регистрируемся на login.live.com.
- Идем на connect.microsoft.com, сразу логинимся (Sign In).
- Идем в Connection Directory (есть подозрение, точное название и URL могут меняться).
- Ищем слово WDK, жмем ссылку. (Сегодня ссылка такая.)
- Ищем слово Downloads, жмем ссылку. (Сегодня такая.)
- Ищем слово WDK, жмем.
- PROFIT!!!
Затем скачанное придется поставить. Без сэмплов занимает где-то 1.2 GB. Инсталлятор то ли сглючил лично у меня, то ли просто не умеет, но точечно выбрать подкомпоненты не удалось. Впрочем, можно стереть вручную после установки. Например, убиение C:\WinDDK\lib (размером 835 MB) именно на PREfast никак не влияет.
Затем уже почти можно применять. Путей WDK никаких не прописывает. Поэтому первым делом нужен 1-строчный враппер по кличке prefast.cmd в любой директории из %PATH%:
В идеальном мире после этого оставалось бы только запустить
К несчастью, devenv шибко умнее PREfast, поэтому вызовы компилятора именно из-под devenv PREfast перехватить не осиливает. Шаманские пляски вокруг devenv/vcbuild не помогают, причем не мне одному. Так что “собирать” и анализировать приходится по старинке, пофайлово. Для этого пишем еще один махонький враппер, pfc.cmd:
call “C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat”
set INCLUDE=c:\myown\include;%INCLUDE%
prefast cl /c %*
Строчка про INCLUDE нужна, чтобы вручную выставить сконфигурированные в студии include directories. Злоупотребление 3rd party libs в системе, а не самом проекте, ударит в спину еще и здесь. Ура, PREfast наконец готов к использованию! Берем пример из недавнего поста:
-
void testFunc()
-
{
-
int array[10];
-
array[12] = 0;
-
return;
-
}
И вот оно счастье - выход за границы отловлен. Автоматически!
Setting environment for using Microsoft Visual Studio 2005 x86 tools.
—————————————————————————–
Microsoft (R) PREfast Version 8.0.50727.80118.
Copyright (C) Microsoft Corporation. All rights reserved.
—————————————————————————–
1.cpp
1.cpp
—————————————————————————–
Removing duplicate defects from the log…
—————————————————————————–
PREfast reported 2 defects during execution of the command.
—————————————————————————–
Enter PREFAST LIST to list the defect log as text within the console.
Enter PREFAST VIEW to display the defect log user interface.
Команда prefast view показывает удобный интерфейс, в котором можно скакать по списку дефектов, фильтровать его всячески, смотреть детали.



Удивительно, но есть более-менее приличная документация. Читайте, она хорошая. По личному опыту, на вопросы “почему здесь warning” она дает быстрый и внятный ответ. Например, оказывается, если внутри функции значение вызова strlen() присваивается куда-то, но не используется в операторах сравнения, то будет warning - и такое поведение документировано прямо в статье про тот warning. В принципе, логично - не используешь, не считай. Жалко, что в моем случае это был стратежно задуманный предрасчет таблицы длин. А то бы сразу еще один баг починил.
В местах, где PREfast не догадывается сам - а он анализирует потоки только в пределах одной функции, поэтому догадывается не всегда - ему можно подсказывать. Для этого есть __analysis_assume. Например, вот так изгоняется warning из метода vector::reserve:
-
T * pNew = new T [ m_iLimit ];
-
__analysis_assume ( m_iLength<=m_iLimit );
-
for ( int i=0; i<m_iLength; i++ )
-
pNew[i] = m_pData[i];
Забавно, что если __analysis_assume пересунуть перед вызовом new, то warning останется. Видимо, считается, что аргумент могут и поменять ненароком, поэтому надо зорко озираться и инвалидировать assume.
Наконец, про полезные фокусы для снижения шума. (Они тоже есть вот тут, в доке, но кто бы ее читал сначала?) Во-1х, сигнализируем про конкретное поведение нашего перегруженного оператора new(), чтобы не было нытья про NULL или там про exceptions - это опция /new_failure, например /new_failure=never. Во-2х, дефолтный стек драйвера в 1К это как-то маловато, поэтому /stackhogthreshold=10240, или даже /stackhogthreshold=65536. Наконец, в-3х, стОит отшибить дефолтный режим анализа “это драйвер ядра, который должен сохранять FPU state и все такое” - по уставу это делается подключением driverspec.h и затем макросом __user_mode, однако можно обойтись без непонятных внешних заголовков:
-
#if (_MSC_VER >= 1000) && !defined(__midl) && defined(_PREFAST_)
-
typedef int __declspec("SAL_nokernel") __declspec("SAL_nodriver") __prefast_flag_kernel_driver_mode;
-
#endif
Дешевой вам отладки. (Да, все сэкономленные на отладке или там VSTS средства можно отсылать мне. Пойдут на хостинг блога. По-честному надо в Microsoft, однако у них и так неплохой market cap.)
Tsukrov:
Всё чудно, но похоже prefast, таки да, включен в VS 2008 Pro.
22 October 2008, 5:11 pmУ меня /analyze что-то делает, кидает какие-то предупреждения.
ForestMan:
Очень вовремя статья :), я как раз ищу себе анализатор кода.
22 October 2008, 6:50 pmСпасибо попробуем.
ForestMan:
В VS 2005 Team Suite есть встроенный анализатор кода, который можно включить и настроить на уровне проекта.
22 October 2008, 6:57 pmКто-нибудь использовал его на реальном проекте? Можно ли его сравнивать с PREfast? Он лучше или хуже?
ForestMan:
P.S.Тест приведённый в этой статье анализатор из VS 2005 прошёл успешно.
22 October 2008, 7:01 pmVitaly:
Спасибо за инструкцию
К слову, Coverity настолько дорогой, что не даже отвечает на письма с запросами trial версии :)
22 October 2008, 7:23 pm$ergi0:
запустил студийный анализатор на своём проэкте. 15 минут жду когда он закончить рассказывать про проблемы в WTL
22 October 2008, 11:48 pm$ergi0:
ага, закончил с WTL и на этом решил, что дело сделано. хммм.
22 October 2008, 11:53 pm23Skidoo:
gimpel lint ещё есть, он не такой дорогой и поддерживает C++
23 October 2008, 12:05 amhttp://www.gimpel.com/
Tsukrov:
У меня почему-то ругается на код.
int arr[BIG_SIZE];
int cnt = 0;
if(cnt == BIG_SIZE)return;
arr[cnt++] = 42;
Вроде всё же в порядке? Это же не arr[++cnt]?
23 October 2008, 1:13 amdDIMA:
2 Tsukrov:
23 October 2008, 6:29 amПопробуй if (cnt >= BIG_SIZE) return; Возможно, оно предполагает, что cnt может “перепрыгнуть” за BIG_SIZE?
shvez:
Андрей, а нельзя разве prefast выдернуть, запаковать и выложить куда-нить в пригодном для использования виде?
23 October 2008, 10:08 amshodan:
Tsukrov,
> У меня почему-то ругается на код.
> int arr[BIG_SIZE];
А у меня не ругается.
Полный файл с сорсом и сообщение об ошибке в студию.
Посмотрим, чем встроенный в VS2008 отличается от WDK-шного!
> Андрей, а нельзя разве prefast выдернуть, запаковать и выложить куда-нить в пригодном для использования виде?
Не знаю, не пробовал.
23 October 2008, 10:43 amRageous:
VS2005TS SP1 “cl /analyze …” - ругается на всякое, да
24 October 2008, 5:37 amacefsm:
http://www.parasoft.com/jsp/templates/ads/google/cplusplusgoogle1.jsp;jsessionid=aaa5KI0kXczTAA?redname=cplusplusgoogle1&referred=cplusplusgoogle1
C++test enables coding policy enforcement, static analysis, comprehensive code review, and unit and component testing to provide teams a practical way to ensure that their C and C++ code works as expected.
24 October 2008, 10:55 amgauri:
если кому лень качать wdk — http://rapidshare.com/files/157045475/prefast.rar.html выколупал.
24 October 2008, 12:19 pmесли будут проблемы — пишите. но вроде как работает нормально.
axxie:
Нам удавалось использовать PREfast вместе со студийным проектом. Для этого нужно было запускать devenv с ключом /useenv. Что-то вроде такого:
prefast.exe devenv driver.sln /Build “Debug|x86″ /useenv
Правда, это был проект драйвера, но думаю это несущественно.
25 October 2008, 10:08 ambelaz:
> gauri
убедительная просьба выложить ещё раз - т.к. скачали уже больше 10 раз и заливка протухла…
27 October 2008, 10:37 amhighly professional scums » Blog Archive » Рецепты отладки. Зависший 3D редактор.:
[...] Subscribe in a reader « Best tools noone uses: PREfast [...]
28 October 2008, 9:23 amG-ray:
> gauri
Поддерживаю, ещё раз, пожалуйста.
28 October 2008, 1:46 pmMihaPro:
> gauri
Я тоже в очереди, перезалей плиз.
28 October 2008, 8:14 pmstd.denis:
[b]gauri[/b],
28 October 2008, 11:33 pmна ifolder, пожалуйста. или любой другой, лояльный, файлобомжатник :)
gauri:
оки!
30 October 2008, 10:57 amhttp://ifolder.ru/8814863
http://rapidshare.com/files/158922381/prefast.rar.html
на здоровье.
belaz:
to All
http://depositfiles.com/files/v5k4edono
31 October 2008, 12:58 pmDmitry Tyurev:
Здесь ошибку оно найти уже не может. В топку.
void WinMain()
{
char arr[50];
int n=0;
for (int i=0; i
31 October 2008, 7:04 pmshodan:
> Здесь ошибку оно найти уже не может
Кто-то разве обещал, что оно найдет вообще все ошибки и сразу?
31 October 2008, 9:35 pmDmitry Tyurev:
Все ошибки, конечно не обещал. :) Но я привёл пример простейшей ошибки, которую казалось бы должен искать любой анализатор. И тот факт, что префаст не ищет даже её, говорит о многом. Жаль только код побился форумом. Андрей, можешь поправить?
1 November 2008, 11:41 ambulrathi:
А чем плох valgrind? Или речь идет о анализаторе только под Win платформу?
8 November 2008, 9:09 amewro:
Есть еще Parasoft BugDetective, и он стоит подешевле KlocWork.
20 December 2008, 5:19 pmИ кстати его русские разрабатывают ;)
booker:
По большому секрету могу сообщить, что Klocwork тоже русские разрабатывают (в Канаде и в России) ;)
26 April 2009, 11:35 pm