BayZR - как подружиться со статическим анализатором кода С/C++

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

BayZR прежде чем запустить анализатор кода пытается найти с какими параметрами собирается каждый файл проекта, и после этого в формате, понятном для конкретного анализатора кода, передает собранные параметры по каждому файлу.

На текущий момент утилита поддерживает такие статические анализаторы:

clang-analyzer

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

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

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

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

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

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

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:

  1. Checking the length of each line
  2. Checking if variable names are well-formed according to the project's coding standard
  3. Checking if declared interfaces are truly implemented

rpmlint

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

ShellCheck is a GPLv3 tool that gives warnings and suggestions for bash/sh shell scripts

Анализатор поддерживает такие конфигурационные файлы:

  1. bzr.conf
  2. bzr.d/*.conf
  3. 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.
  1. -cc и -cxx - являются командами для служебного пользования. Используется самим анализатором, при настройках replace=on.
  2. -config - позволяет указать не стандартный путь к файлу конфигурации bzr.conf
  3. -diff - список патч файлов для отображения лишь тех строк и файлов в отчете, которые затрагивают патчи. Удобно использовать команду в случае, когда не нужен отчет по всему исходному коду, а лишь по изменившейся части
  4. -files - аналогично -diff, но задается список файлов через запятую, в отчет попадают лишь ошибки из этих файлов
  5. -list - вывести список доступных/известных анализаторов кода
  6. -not-only-local - отобразить в отчете ошибки и замечания файлов не входящих в анализируемый проект(например ошибки и замечания в заголовочных файлов сторонних пакетов и программ, используемых в проекте)
  7. -dry-run - запустить анализ вывода сборки и вывести команды для запуска анализаторов без запуска самих анализаторов. Будет полезна при уникальном вызове анализатора, когда нужно знать все сопутствующие параметры окружения сборки файла, но нужно добавить что-то самостоятельное
  8. -menu - интерактивный диалог по локальной настройке параметров проекта на базе curses(ncurses)