Краткий обзор статических анализаторов кода на C/C++

11 мая 2016

При написании кода на C и C++ люди допускают ошибки. Многие из этих ошибок находятся благодаря -Wall, ассертам, тестам, дотошному code review, предупреждениям со стороны IDE, сборкой проекта разными компиляторами под разные ОС, работающие на разном железе, и так далее. Но даже при использовании всех этих мер ошибки часто остаются незамеченными. Немного улучшить положение дел позволяет статический анализ кода. В этой заметке мы познакомимся с некоторыми инструментами для произведения этого самого статического анализа.

CppCheck

CppCheck является бесплатным кроссплатформенным статическим анализатором с открытым исходным кодом (GPLv3). Он доступен в пакетах многих *nix систем из коробки. Также CppCheck умеет интегрироваться со многими IDE. На момент написания этих строк CppCheck является живым, развивающимся проектом.

Пример использования:

cppcheck ./src/

Пример вывода:

[some.c:57]: (error) Common realloc mistake: 'numarr' nulled but not
freed upon failure

[some.c:154]: (error) Dangerous usage of 'n' (strncpy doesn't always
null-terminate it)

CppCheck хорош тем, что он довольно быстро работает. Нет повода не добавить его прогон в систему непрерывной интеграции, чтобы исправлять прямо все-все-все выводимые им предупреждения. Даже несмотря на то, что многие из них на практике оказываются ложно-положительными срабатываниями.

Официальный сайт: http://cppcheck.sourceforge.net/

Clang Static Analyzer

Еще один бесплатный кроссплатформенный статический анализатор с открытыми исходным кодом. Является частью так называемого LLVM-стэка. В отличие от CppCheck работает существенно медленнее, но и ошибки находит куда более серьезные.

Пример построения отчета для PostgreSQL:

CC=/usr/local/bin/clang38 CFLAGS="-O0 -g" \
  ./configure --enable-cassert --enable-debug
gmake clean
mkdir ../report-201604/
/usr/local/bin/scan-build38 -o ../report-201604/ gmake -j2

Пример построения отчета для ядра FreeBSD:

# использование своего MAKEOBJDIR позволяет собирать ядро не под рутом
mkdir /tmp/freebsd-obj
# сама сборка
COMPILER_TYPE=clang /usr/local/bin/scan-build38 -o ../report-201604/ \
  make buildkernel KERNCONF=GENERIC MAKEOBJDIRPREFIX=/tmp/freebsd-obj

Идея, как несложно догадаться, заключается в том, чтобы сделать clean, а затем запустить сборку под scan-build.

На выходе получается очень симпатичный HTML-отчет с подробнейшими пояснениями, возможностью фильтровать ошибки по их типу, и так далее. Обязательно посмотрите на офсайте как это примерно выглядит.

В данном контексте не могу не отметить, что в мире Clang/LLVM есть еще и средства динамического анализа, так называемые «санитайзеры». Их много, они находят очень крутые ошибки и работают быстрее, чем Valgrind (правда, только под Linux). К сожалению, обсуждение санитайзеров выходит за рамки настоящей заметки, поэтому ознакомьтесь с ними самостоятельно.

Официальный сайт: http://clang-analyzer.llvm.org/

PVS-Studio

Закрытый статический анализатор, распространяемый за деньги. PVS-Studio работает только под Windows и только с Visual Studio. Есть многочисленные сведения о существовании Linux-версии, но на официальном сайте она не доступна. Насколько я понял, цена лицензии обсуждается индивидуально с каждым клиентом. Доступен триал.

Я протестировал PVS-Studio 6.02 на Windows 7 SP1 работающей под KVM с установленной Visual Studio 2013 Express Edition. Во время установки PVS-Studio также дополнительно скачался .NET Framework 4.6. Выглядит это примерно так. Вы открываете проект (я тестировал на PostgreSQL) в Visual Studio, в PVS-Studio жмете «сейчас я начну собирать проект», затем в Visual Studio нажимаете Build, по окончании сборки в PVS-Studio жмете «я закончил» и смотрите отчет.

PVS-Studio действительно находит очень крутые ошибки, которые Clang Static Analyzer не видит (например). Также очень понравился интерфейс, позволяющий сортировать и фильтровать ошибки по их типу, серьезности, файлу, в котором они были найдены, и так далее.

С одной стороны, печалит, что чтобы использовать PVS-Studio, проект должен уметь собираться под Windows. С другой стороны, использовать в проекте CMake и собирать-тестировать его под разными ОС, включая Windows, при любом раскладе является очень неплохой затеей. Так что, пожалуй, это не такой уж и большой недостаток. Кроме того, по следующим ссылкам можно найти кое-какие подсказки касательно того, как людям удавалось прогонять PVS-Studio на проектах, которые не собираются под Windows: раз, два, три, четыре.

Дополнение: Попробовал бета-версию PVS-Studio для Linux. Пользоваться ею оказалось очень просто. Создаем pvs.conf примерно такого содержания:

lic-file=/home/afiskon/PVS-Studio.lic
output-file=/home/afiskon/postgresql/pvs-output.log

Затем говорим:

make clean
./configure ...
pvs-studio-analyzer trace -- make
# будет создан большой (у меня ~40 Мб) файл strace_out
pvs-studio-analyzer analyze --cfg ./pvs.conf
plog-converter -t tasklist -o result.task pvs-output.log

Дополнение: PVS-Studio для Linux вышел из беты и теперь доступен всем желающим.

Официальный сайт: http://www.viva64.com/en/pvs-studio/

Coverity Scan

Coverity считается одним из самых навороченных (а следовательно и дорогих) статических анализаторов. К сожалению, на официальном сайте невозможно скачать даже его триал-версию. Можно заполнить форму, и если вы какой-нибудь IBM, с вами может быть свяжутся. При очень сильном желании Coverity какой-нибудь доисторической версии можно найти через неофициальные каналы. Он бывает для Windows и Linux, работает примерно по тому же принципу, что и PVS-Studio. Но без серийника или лекарства отчеты Coverity вам не покажет. А чтобы найти серийник или лекарство, нужно иметь не просто очень сильное желание, а очень-очень-очень сильное.

К счастью, у Coverity есть SaaS версия — Coverity Scan. Мало того, что Coverity Scan доступен для простых смертных, он еще и совершенно бесплатен. Привязки к конкретной платформе нет. Однако анализировать с помощью Coverity Scan разрешается только открытые проекты.

Вот как это работает. Вы регистрируете свой проект через веб-интерфейс (или присоединяетесь к уже существующему, но это менее интересный кейс). Чтобы посмотреть отчеты, нужно пройти модерацию, которая занимает 1-2 рабочих дня.

Отчеты строятся таким образом. Сначала вы локально собираете свой проект под специальной утилитой Coverity Build Tool. Утилита эта аналогична scan-build из Clang Static Analyzer и доступна под все мыслимые платформы, включая всякую экзотику типа FreeBSD или даже NetBSD.

Установка Coverity Build Tool:

tar -xvzf cov-analysis-linux64-7.7.0.4.tar.gz
export PATH=/home/eax/temp/cov-analysis-linux64-7.7.0.4/bin:$PATH

Готовим тестовый проект (я использовал код из заметки Продолжаем изучение OpenGL: простой вывод текста):

git clone git@github.com:afiskon/c-opengl-text.git
cd c-opengl-text
git submodule init
git submodule update
mkdir build
cd build
cmake ..

Затем собираем проект под cov-build:

cov-build --dir cov-int make -j2 demo emdconv

Важно! Не меняйте название директории cov-int.

Архивируем директорию cov-int:

tar -cvzf c-opengl-text.tgz cov-int

Заливаем архив через форму Upload a Project Build. Также на сайте Coverity Scan есть инструкции по автоматизации этого шага при помощи curl. Ждем немного, и можно смотреть результаты анализа. Примите во внимание, что чтобы пройти модерацию, нужно отправить на анализ хотя бы один билд.

Ошибки Coverity Scan ищет очень хорошо. Уж точно лучше, чем Clang Static Analyzer. При этом ложно-положительные срабатывания есть, но их намного меньше. Что удобно, в веб-интерфейсе есть что-то вроде встроенного багтрекера, позволяющего присваивать ошибкам серьезность, ответственного за их исправление и подобные вещи. Видно, какие ошибки новые, а какие уже были в предыдущих билдах. Ложно-положительные срабатывания можно отметить как таковые и скрыть.

Заметьте, что чтобы проанализировать проект в Coverity Scan, не обязательно быть его владельцем. Мне лично вполне успешно удалось проанализировать код PostgreSQL без присоединения к уже существующему проекту. Думается также, что при сильном желании (например, используя сабмодули Git), можно подсунуть на проверку немного и не очень-то открытого кода.

Официальный сайт: https://scan.coverity.com/

Заключение

Вот еще несколько статических анализаторов, не попавших в обзор:

Каждый из рассмотренных анализаторов находят такие ошибки, которые не находят другие. Поэтому в идеале лучше использовать их сразу все. Делать это вот прямо постоянно, скорее всего, объективно не получится. Но делать хотя бы один прогон перед каждым релизом точно будет не лишним. При этом Clang Static Analyzer выглядит наиболее универсальным и при этом достаточно мощным. Если вас интересует один анализатор, который нужно обязательно использовать в любом проекте, используйте его. Но все же я бы рекомендовал дополнительно использовать как минимум PVS-Studio или Coverity Scan.

А какие статические анализаторы вы пробовали и/или регулярно использовали и каковы ваши впечатления от них?

Дополнение: Эту статью перевели на английский язык — An Overview of Static Analyzers for C/C++ Code

Метки: , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.