BayZR - как подружиться со статическим анализатором кода С/C++
BayZR - утилита позволяющая собирать данные статических анализаторов кода и формировать единый отчет о результате проверки. Отчет может быть предоставлен как в кратком виде для дальнейшей его обработки, так и в расширенном виде - текст с комментариями или html формат.
BayZR прежде чем запустить анализатор кода пытается найти с какими параметрами собирается каждый файл проекта, и после этого в формате, понятном для конкретного анализатора кода, передает собранные параметры по каждому файлу.
Список поддерживаемых анализаторов
На текущий момент утилита поддерживает такие статические анализаторы:
clang-analyzer
The Clang Static Analyzer is a source code analysis tool that finds bugs in C, C++, and Objective-C programs.
Currently it can be run either as a standalone tool or within Xcode. The standalone tool is invoked from the command line, and is intended to be run in tandem with a build of a codebase.
The analyzer is 100% open source and is part of the Clang project. Like the rest of Clang, the analyzer is implemented as a C++ library that can be used by other tools and applications.
cppcheck
Cppcheck is a static analysis tool for C/C++ code. Unlike C/C++ compilers and many other analysis tools it does not detect syntax errors in the code. Cppcheck primarily detects the types of bugs that the compilers normally do not detect. The goal is to detect only real errors in the code (i.e. have zero false positives).
oclint
OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code and looking for potential problems like:
- Possible bugs - empty if/else/try/catch/finally statements
- Unused code - unused local variables and parameters
- Complicated code - high cyclomatic complexity, NPath complexity and high NCSS
- Redundant code - redundant if statement and useless parentheses
- Code smells - long method and long parameter list
- Bad practices - inverted logic and parameter reassignment
- …
rats
The Rough Auditing Tool for Security is an open source tool developed by Secure Software Engineers. Since then it has been acquired by Fortify, which continues to distribute it free of charge. It scans various languages, including C, C++, Perl, PHP and Python. It is very fast and can easily be integrated into a building process without causing noticeable overhead.
splint
Splint is a tool for statically checking C programs for security vulnerabilities and coding mistakes. With minimal effort, Splint can be used as a better lint. If additional effort is invested adding annotations to programs, Splint can perform stronger checking than can be done by any standard lint.
frama-c
Frama-C is a suite of tools dedicated to the analysis of the source code of software written in C. Frama-C gathers several static analysis techniques in a single collaborative framework. The collaborative approach of Frama-C allows static analyzers to build upon the results already computed by other analyzers in the framework. Thanks to this approach, Frama-C provides sophisticated tools, such as a slicer and dependency analysis.
pylint
Pylint is a source code, bug and quality checker for the Python programming language. It follows the style recommended by PEP 8, the Python style guide.[4] It is similar to Pychecker and Pyflakes, but includes the following features:
- Checking the length of each line
- Checking if variable names are well-formed according to the project's coding standard
- Checking if declared interfaces are truly implemented
rpmlint
rpmlint is a tool for checking common errors in rpm packages. It can be used to test individual packages and spec files before uploading or to check an entire distribution. By default all applicable checks are processed but specific checks can be performed by using command line parameters.
shellcheck
ShellCheck is a GPLv3 tool that gives warnings and suggestions for bash/sh shell scripts
Конфигурационные файлы
Анализатор поддерживает такие конфигурационные файлы:
- bzr.conf
- bzr.d/*.conf
- bzr.d/*.tpl
bzr.conf
Это конфигурационный файл самой программы.
Типовой пример с объяснениями:
[default]
compilator = gcc c++ cc
←какую строку в make выводе считать, что это вызов компилятора
extention=c cpp h cxx hpp c++
←какие файлы из вывода make включать в анализ(расширение файла с точкой или без)
stderr=on
← выводить лог ошибок make
globaldefs= -Ddef1 -Ipath
← глобальные специфические параметры добавляемые всем файлам проектов или проекта
outputfile=report.log
←сюда сохраняется результат проверки
replace=on
←включить анализ параметров передаваемых компилятору путем замены gcc или просто читать вывод утилиты
bashcmd=bash -c
←команда для запуска компиллятора(зачастую использует значения по умолчанию и не требует смены).
Меняется в случае если bash или shell оболочка находятся не по стандартному пути PATH
[extended]
;filename = -Ddef1 -Ddef2
←специфические для файла параметры, добавляемые в DEF список или INCLUDE список
[plugins]
checkby=cppcheck rats clang
← список плагинов, которые необходимо применить к анализируемым файлам
output=html
или txt или custom ←формат вывода результата
template=FILE|LINE|SEV|ID|MESSAGE
←шаблон вывода для custom формата
wrapstrings=20
←20 строк до строки с ошибкой и 20 после, только для html и txt отчета
html_template=result_w3.tpl
←файл шаблон оформления результата(для html отчета)
[ignore]
filename1
filename2
список файлов которые нужно игнорировать и не проверять
Содержимое файла по-умолчанию
- bzr.conf
[default] compilator = gcc c++ cc cc1 extention= c cpp h cxx hpp c++ stderr=on globaldefs= -Dlinux outputfile=report.html replace=off bashcmd=/bin/bash -c [plugins] checkby=cppcheck output=html template=FILE;LINE;SEV;ID;MESSAGE wrapstrings=20 html_template=result_w3.tpl
bzr.d/*.conf
Конфигурационные файлы для запуска анализатора. Для каждого анализатора(плагина) свой файл
Результатом работы плагина должна быть секция CMD, которая бы запустила анализатор файла исходных кодов, а также секция RESULT, которая описывает как разбирать результат анализа.
Служебные секции:
каждая секция состоит из имени и содержимого [имя]{содержимое}. Содержимое может быть однострочным и многострочным, скобочки содержимого могут быть такого вида:
1) NAME{descr} 2) NAME{ descr} 3) NAME{ descr } 4) NAME { descr } 5) NAME {descr} ...
Значения секций:
NAME - имя плагина отображаемого при выводе команды help или list(сводится в одну строку)
DESCRIPTION - описание плагина(сводится в одну строку)
ID - идентификатор [a-zA-Z] для использования при конфигурировании(1 строка, остальные не анализируются)
TYPE - тип плагина и анализируемых параметров: 1 - cppcheck подобный вывод, 2 - rats подобный вывод(т.е без шаблона и описание идет одной строкой после вывода ошибки)
OPTIONS - список параметров передаваемых анализатру, параметры разделяются концом строки. Могут содержать переменные, которые начинаются с $, если переменная не описана в конфигурационном файле и анализатор не знает как ее вычислить, то параметр удаляется из списка OPTIONS
LANG - список расширений файлов и соответствия какой язык с или с++, для анализаторов, которые требуют такого анализа
RESULT - список параметров, которые будут разбираться в выходном файле и
разделитель DELIMIT=, каждый параметр через запятую или с новой строки.\\ уровни HIGH,MEDIUM,LOW=с перечислением какие идентификаторы ошибки к чему причислять\\ и STREAM= откуда читать сведения о результате из stderr или stdout\\
CMD - команда для запуска анализатора
DEFS - шаблон, как формировать список опеределений, можно указывать $:, $:, $: и т.д. Это значит что вмеcто первого $: подставится первый параметр, вместо второго - второй и т.д
FILENAME - шаблон, как передавать имя файла, задается как $FILE
INCLUDES - шаблон, как формировать список includes, можно указывать $:, $:, $: и т.д
Переменные:
Переменные делятся на Подстановочные и Кастомные и Генерируемые.
Постановочные:
переменные которые формирует сам анализатор:
STD, ARCH, PLAT - если анализатор не смог сам опреедлить, то берется то, что задано в конфигурационном файле
Генерируемые:
NAME, DESCRIPTION, ID, TYPE, OPTIONS, LANG, RESULT, CMD, DEFS, FILENAME, INCLUDES - эти переменные всегда определяются анализатором на основе заданных секций или если не заданы, то равны пустой строке
Кастомные:
переменные которые полностью определяются конфигурационным файлом
Вид переменной может задаваться как:
_[имя переменной]{ [значение по умолчанию] DEF=[операций командной строки] CMD=[операция командной строки] }
здесь:
DEF - команда, которая формирует значение по умолчанию
CMD - команда для получения значения переменной
значение по умолчанию - если не определено DEF и CMD и не требуется запуск стороннего приложения
Пример файлов анализаторов
- cppcheck.conf
NAME{cppcheck} DESCRIPTION{ Cppcheck is a static analysis tool for C/C++ code. Unlike C/C++ compilers and many other analysis tools it does not detect syntax errors in the code. Cppcheck primarily detects the types of bugs that the compilers normally do not detect. The goal is to detect only real errors in the code (i.e. have zero false positives). } ID{cppcheck} TYPE{1} _STD{c99} ARCH{ 32=__i386__ 64=__x86_64__ DEFAULT=__x86_64__ } PLAT{ linux32=unix32 linux64=unix64 DEFAULT=unix64 } OPTIONS{ --std=$STD --template="{file}|{line}|{severity}|{id}|{message}" -D$ARCH --language=$LANG --platform=$PLAT --enable=warning,style,performance,unusedFunction --suppress=preprocessorErrorDirective --suppress=toomanyconfigs --suppress=variableScope --suppress=variableHidingTypedef --suppress=unusedFunction --inconclusive } LANG{ C=c cc h C++=cpp c++ cxx hpp DEFAULT=C } RESULT{ :FILE :LINE :SEV :ID :MESSAGE DELIMIT=| STREAM=stderr LOW=none,style,information,portability MEDIUM=warning,performance HIGH=error,preprocessorerrordirective } DEFS{-D$:} INCLUDES{-I$:} FILENAME{$FILE} AUTOINCLUDE{ --include= } CMD{ /usr/bin/cppcheck $OPTIONS $DEFS $CUSTOMDEFS $FILENAME }
- rats.conf
NAME{rats} DESCRIPTION{ The Rough Auditing Tool for Security is an open source tool developed by Secure Software Engineers. Since then it has been acquired by Fortify, which continues to distribute it free of charge. It scans various languages, including C, C++, Perl, PHP and Python. } ID{rats} TYPE{2} OPTIONS{ -r --resultsonly -w1 } RESULT{ :FILE :LINE :SEV :MESSAGE DELIMIT=: STREAM=stdout LOW=low MEDIUM=medium HIGH=high } FILENAME{$FILE} AUTOINCLUDE{ -I } CMD{ /usr/bin/rats $OPTIONS $FILENAME }
- clang-analyzer.conf
NAME{clang-analyzer} DESCRIPTION{ scan-build is a command line utility that enables a user to run the static analyzer over their codebase as part of performing a regular build (from the command line). } ID{clang-analyzer} TYPE{1} OPTIONS{ -o . -enable-checker alpha.core.FixedAddr -enable-checker alpha.core.IdenticalExpr -enable-checker alpha.core.PointerArithm -enable-checker alpha.core.PointerSub -enable-checker alpha.core.SizeofPtr -enable-checker alpha.cplusplus.NewDeleteLeaks -enable-checker alpha.deadcode.IdempotentOperations -enable-checker alpha.deadcode.UnreachableCode -enable-checker alpha.security.ArrayBoundV2 -enable-checker alpha.security.ReturnPtrRange -enable-checker alpha.security.MallocOverflow -enable-checker alpha.unix.MallocWithAnnotations -enable-checker alpha.unix.PthreadLock -enable-checker alpha.unix.Stream -enable-checker alpha.unix.cstring.BufferOverlap -enable-checker alpha.unix.cstring.NotNullTerminated -enable-checker alpha.unix.cstring.OutOfBounds -enable-checker security.insecureAPI.strcpy } RESULT{ :FILE :LINE :ID :SEV :MESSAGE DELIMIT=: STREAM=stderr LOW=information MEDIUM=warning HIGH=error CLEAN=scan-build: Run 'scan-view [\S\s]*/([0-9\-]+)' } DEFS{-D$:} INCLUDES{-I$:} FILENAME{$FILE} AUTOINCLUDE{ -I } CMD{ /usr/bin/scan-build $OPTIONS $FRESH } BEFORECMD{ make clean } FRESH{ 1 }
bzr.d/*.tpl
Шаблоны вывода для html. Оформление вывода для формирования удобочитаемого результата. Синтаксис формирования файла строится по правилам: https://golang.org/pkg/html/template/
Шаблон может отобразить такие структуры:
список структур
type reporter.ReporterContainerLineItemLink struct { Number int64 Line string FndStr bool } type reporter.ReporterContainerLineItem struct { Number int64 Line string Value int Plugin string Link []reporter.ReporterContainerLineItemLink } type ListOfErrorsShort struct { Position int64 Error_message string } type ListOfErrorLong struct { Critical int64 Warning int64 Normal int64 List []reporter.ReporterContainerLineItem } type PreparedToOutput struct { ReportName string ListOfCheckers map[string]int64 ListOfShort map[string][]ListOfErrorsShort ListOfLong map[string]ListOfErrorLong ListOfFiles []string Consts []int }
Параметры командной строки
$ bayzr --help Usage of bayzr: bayzr [options] cmd ... -cc Run as C compiler wrapper -config string path to configuration file (default "/etc/bzr.conf") -cxx Run as C++ compiler wrapper -debug-commands Show list of generated static analizers options and commands -diff string List of patch file for get list of patched files -dry-run Show list of generated static analizers options and commands without analitic tool starting -files string List of files should be inserted to report or * for all files(by dafault) (default "*") -list Show list of available plugins -menu Show console menu for project options configuring -not-only-local Show in result errors not only for project files -version Print the version number.
-cc
и-cxx
- являются командами для служебного пользования. Используется самим анализатором, при настройкахreplace=on
.-config
- позволяет указать не стандартный путь к файлу конфигурации bzr.conf-diff
- список патч файлов для отображения лишь тех строк и файлов в отчете, которые затрагивают патчи. Удобно использовать команду в случае, когда не нужен отчет по всему исходному коду, а лишь по изменившейся части-files
- аналогично-diff
, но задается список файлов через запятую, в отчет попадают лишь ошибки из этих файлов-list
- вывести список доступных/известных анализаторов кода-not-only-local
- отобразить в отчете ошибки и замечания файлов не входящих в анализируемый проект(например ошибки и замечания в заголовочных файлов сторонних пакетов и программ, используемых в проекте)-dry-run
- запустить анализ вывода сборки и вывести команды для запуска анализаторов без запуска самих анализаторов. Будет полезна при уникальном вызове анализатора, когда нужно знать все сопутствующие параметры окружения сборки файла, но нужно добавить что-то самостоятельное-menu
- интерактивный диалог по локальной настройке параметров проекта на базе curses(ncurses)