Verification: a143cc29221c9be0

Non static method cannot be called statically php

Non static method cannot be called statically php



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 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 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
  • ...



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 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 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 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 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 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


Это конфигурационный файл самой программы. Типовой пример с объяснениями:


compilator = gcc c++ cc

extention=c cpp h cxx hpp c++


globaldefs= -Ddef1 -Ipath



bashcmd=bash -c


;filename = -Ddef1 -Ddef2


checkby=cppcheck rats clang

output=html или txt или custom







список файлов которые нужно игнорировать и не проверять

Содержимое файла по-умолчанию

compilator = gcc c++ cc cc1
extention= c cpp h cxx hpp c++
globaldefs= -Dlinux
bashcmd=/bin/bash -c



Конфигурационные файлы для запуска анализатора. Для каждого анализатора(плагина) свой файл

Результатом работы плагина должна быть секция CMD, которая бы запустила анализатор файла исходных кодов, а также секция RESULT, которая описывает как разбирать результат анализа.

Служебные секции:

каждая секция состоит из имени и содержимого [имя]{содержимое}. Содержимое может быть однострочным и многострочным, скобочки содержимого могут быть такого вида:

    1) NAME{descr}
    2) NAME{
    3) NAME{
    4) NAME
    5) NAME

Значения секций:

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 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). 
C=c cc h 
C++=cpp c++ cxx hpp


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. 
/usr/bin/rats $OPTIONS $FILENAME


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).
-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.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
CLEAN=scan-build: Run 'scan-view [\S\s]*/([0-9\-]+)'
/usr/bin/scan-build $OPTIONS $FRESH
make clean


Шаблоны вывода для html. Оформление вывода для формирования удобочитаемого результата. Синтаксис формирования файла строится по правилам:

Шаблон может отобразить такие структуры:

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 ...
            Run as C compiler wrapper
      -config string
            path to configuration file (default "/etc/bzr.conf")
            Run as C++ compiler wrapper
            Show list of generated static analizers options and commands
      -diff string
            List of patch file for get list of patched files
            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 "*")
            Show list of available plugins
            Show console menu for project options configuring
            Show in result errors not only for project files
            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)

Последовательность установки CentOS 7

wget -O /etc/yum.repos.d/home:bayrepo.repo
yum install bayzr -y

установка завершена

Команды необходимо выполнять от пользователя root, на сервере должны быть установлены golang и git

Последовательность сборки

git clone
cd bayzr/rpm

установка и сборка завершены

Исходные коды модуля доступны по адресу

Вариант 1 - проверка на основе данных компиляции кода

Последовательность действий проверки:

скачиваем архив с исходным кодом

  • wget

распаковываем и переходим в папку с исходными кодами

  • unzip
  • cd mod_performance-master/

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

  • cp /etc/bzr.conf ./bzr.conf
  • vi bzr.conf
    compilator = gcc c++ cc cc1
    extention= c cpp h cxx hpp c++
    globaldefs= -Dlinux
    bashcmd=/bin/bash -c

    checkby=cppcheck rats

запускаем анализатор

  • bayzr cmd make

Вариант 2 - на основе списка файлов

Последовательность действий проверки:

скачиваем архив с исходным кодом

  • wget

распаковываем и переходим в папку с исходными кодами

  • unzip
  • cd mod_performance-master/

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

  • cp /etc/bzr.conf ./bzr.conf
  • vi bzr.conf
    compilator = gcc c++ cc cc1
    extention= c cpp h cxx hpp c++
    globaldefs= -D__FREEBSD__ -I/usr/include/httpd/ -I/usr/include/apr-1
    bashcmd=/bin/bash -c

    checkby=cppcheck rats

запускаем анализатор

  • bayzr cmd "find . -name '*.c' | xargs -n 1 echo 'gcc '" - т.е искусственно создается gcc и путь к файлу

Вот такой код был подготовлен для статического анализа:

Искусственный код - пример: buggy_test.c




int function1(char *a){
    printf("Variable 1 = %d\n", strlen(a));
    a = malloc(10*sizeof(char));
    sprintf(a, "This is huge text, more then array size %d\n", 10000000000L);
    return strlen(a);

char *function2(){
    char *internal_buffer = alloca(10 * sizeof(char));
    snprintf(internal_buffer, 12, "Another big string to copy to the buffer\n");
    return internal_buffer;

int function3(int a, int b){
    int c[20];
    int i;
    a = a * i;
    for (i=0;i0){
    strcpy(arr, argv[1]);
    int result = function1(buf);
    printf("Result %d, %s\n", result, arr);
    buf = function2();
    printf("Buf %s\n", buf);
    result = function3(10,20);
    printf("Result %d\n", result);
    return 0;


  1. зайти в папку сканируемого проекта cd ~/check/ в папке находится тестируемый файл
  2. с помощью команды -menu создаются локальные настройки для проекта
  3. далее дается команда -debug-commands cmd gcc -o buggy test.c для сборки проекта, в момент сборки bayzr собирает список файлов для анализа и список параметров сборки
  4. результат сборки и работы bayzr - это файл отчета

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

Анализаторы бывают нескольких типов:

  1. самостоятельно собирающие данные о компилируемых файлах: clang-analyzer, make [группа 1]
  2. несамостоятельные анализаторы. т.е те, которым необходимо передать список определений для более точного анализа проекта, но допускающие отсутствие таких параметров: cppcheck, rats [группа 2]
  3. несамостоятельные анализаторы. т.е те, которым необходимо передать список определений для более точного анализа проекта и строго требующие параметры для анализа:splint, oclint [группа 3]
  4. анализаторы с графическим интерфейсом, которые позволяют провести дальнейший анализ кода: frama-c [группа 4]

А теперь рассмотрим способы анализа проектов bayzr утилитой.

Анализ файлов без компиляции

Способ подходит для анализаторов [группы 2], но в этом случае, параметры для более точного анализа файлов необходимо формировать самостоятельно:

Пример команды для нахождения всех файлов с расширением c. К каждому найденному файлу добавляется строка с gcc, таким образом можно сформировать необходимые -D и -I:

bayzr cmd "find . -name '*.c' | xargs -n 1 echo 'gcc '"

[test@localhost check]$ bayzr cmd "find . -name '*.c' | xargs -n 1 echo 'gcc '"; cat report_buggy_c.txt
--------------------Process of gathering source information is begun-----------------
gcc  ./test.c
--------------------Process of source analyzing is begun-----------------------------
--------------------Process of source analyzing is begun by plugin cppcheck----------------
Analyzer error: stderr scanner error read |0: bad file descriptor
Checking /home/test/check/test.c...
/home/test/check/test.c|9|warning|invalidPrintfArgType_sint|%d in format string (no. 1) requires 'int' but the argument type is 'signed long'.
/home/test/check/test.c|25|error|unknownEvaluationOrder|Expression '++a+a++' depends on order of evaluation of side effects
/home/test/check/test.c|24|error|arrayIndexOutOfBounds|Array 'c[20]' accessed at index 20, which is out of bounds.
/home/test/check/test.c|27|error|negativeIndex|Array index -1 is out of bounds.
/home/test/check/test.c|15|error|bufferAccessOutOfBounds|Buffer is accessed out of bounds.
/home/test/check/test.c|14|warning|allocaCalled|Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.
/home/test/check/test.c|10|error|memleak|Memory leak: a
/home/test/check/test.c|22|error|uninitvar|Uninitialized variable: i
/home/test/check/test.c|36|error|uninitvar|Uninitialized variable: buf

         4|  #include ``
         6|  int function1(char *a){
         7|      printf("Variable 1 = %d\n", strlen(a));
         8|      a = malloc(10*sizeof(char));
//**DETECT** cppcheck:      %d in format string (no. 1) requires 'int' but the argument type is 'signed long'.
         9|      sprintf(a, "This is huge text, more then array size %d\n", 10000000000L);
//**DETECT** cppcheck:      Memory leak: a
        10|      return strlen(a);
        11|  }
        13|  char *function2(){
//**DETECT** cppcheck:      Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.
        14|      char *internal_buffer = alloca(10 * sizeof(char));
//**DETECT** cppcheck:      Buffer is accessed out of bounds.
        15|      snprintf(internal_buffer, 12, "Another big string to copy to the buffer\n");
        16|      return internal_buffer;
        17|  }
        19|  int function3(int a, int b){
        20|      int c[20];
        21|      int i;
//**DETECT** cppcheck:      Uninitialized variable: i
        22|      a = a * i;
        23|      for (i=0;i0){
        34|      strcpy(arr, argv[1]);
        35|      }
//**DETECT** cppcheck:      Uninitialized variable: buf
        36|      int result = function1(buf);
        37|      printf("Result %d, %s\n", result, arr);
        38|      buf = function2();
        39|      printf("Buf %s\n", buf);
        40|      result = function3(10,20);
        41|      printf("Result %d\n", result);

Таким образом можно список файлов для анализа и параметры сборки собрать в отдельный файл и сделать cat check_files.txt

Анализ с компиляцией

Способ подходит для всех типов анализаторов [группы от 1 до 4]

типичный пример использования:

[#]$ ./configure
[#]$ bayzr cmd make VERBOSE=1

В текущем примере используется VERBOSE=1 для раскрытия утилитой make процесса сборки, хоя возможно обойтись и без этого, а с помощью настройки: replace = on в локальном или глобальном bzr.conf. В этом случае переменные окружения CC и CXX будут подменены на bayzr и параметры компиляции будут перехвачены даже при отключенном выводе процесса сборки.

Анализ с компиляцией и выводом команд анализатора

Режим подобен предыдущему, но в отчет попадают команды, которые были сформированы для вызова анализатора статического кода. Такой режим полезен в случае, когда возможностей bayzr не хватает и нужны дополнительные настройки. Например для анализатора [группы 4], frama-c имеет графический анализатор, позволяющий провести дополнительный анализ исходных файлов.

Команды сформированные bayzr можно напрямую вызвать из командной строки с frama-c-gui например.

[test@localhost check]$ bayzr -debug-commands --dry-run cmd gcc -o buggy test.c
--------------------Process of gathering source information is begun-----------------
test.c: In function ‘main’:
test.c:31:20: warning: initializer-string for array of chars is too long [enabled by default]
     char arr[10] = "12345678901";
--------------------Process of source analyzing is begun-----------------------------
--------------------Process of source analyzing is begun by plugin frama-c----------------
/usr/bin/frama-c -no-frama-c-stdlib -cpp-gnu-like -val -va -wp -sparecode -security-slicing -nonterm -cpp-extra-args="   -Dlinux  -IcHeaderFileGeneratedByBzrPrg.h -I/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include -I/usr/local/include -I/usr/include -I. -m64 -mtune=generic"  test.c
[test@localhost check]$ /usr/bin/frama-c-gui -no-frama-c-stdlib -cpp-gnu-like -val -va -wp -sparecode -security-slicing -nonterm -cpp-extra-args="   -Dlinux  -IcHeaderFileGeneratedByBzrPrg.h -I/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include -I/usr/local/include -I/usr/include -I. -m64 -mtune=generic"  test.c

Параметр -dry-run позволяет не запускать анализатор статического кода, а просто выводит сформированные команды для запуска анализатора

Анализ только заданных файлов

Подходит для всех типов анализаторов [группы от 1 до 4], анализ проходят только по тем файлам, которые выбраны для отчета.

[test@localhost mod_performance-master]$ bayzr -files chart.c cmd make
[test@localhost mod_performance-master]$ cat report.txt 

       147|        (*x)[k] = 0;
       148|        (*y)[k] = 0;
       149|      }
       151|      char *bug = malloc(20);
//**DETECT** cppcheck:      Buffer is accessed out of bounds.
       152|      strcpy(bug, "ASDFGHJKLQWERTYUIOPHJKUYTF");
//**DETECT** cppcheck:      Memory leak: bug
       153|      return;
       155|  }
       157|  void
       158|  readmatrix(apr_array_header_t *data, double **a, double **b, double **x,
       466|          }
       467|        if (s->date > cur)
       468|          return 0.0;
       469|      }
       470|    char a[5]="FRTDESWERTYUUU";
//**DETECT** cppcheck:      %d in format string (no. 1) requires 'int' but the argument type is 'char *'.
       471|    printf("%d",a);
       472|    return 0.0;
       473|  }
       475|  apr_array_header_t *
       476|  chart_fill_data(apr_array_header_t *data, int min, int max)
       762|          }
       763|        if (ti.seconds)
       764|          {
       765|            sprintf(buffer, "sec %d", ti.seconds);
       766|            gdImageString(im, fptr, rw - 2 * dx - 10, rh - dup, (unsigned char *)buffer, black);
//**DETECT** cppcheck:      Variable 'dup' is assigned a value that is never used.
       767|            dup -= 10;
       768|          }
       769|      }
       770|    else
       771|      {
       772|        gdImageLine(im, rw - 2 * dx, rh - 40, rw - dx, rh - 40, black);

или вообще, список заданных файлов берется из патч файла:

[test@localhost mod_performance-master]$ cat new-commit.patch 
diff --git a/chart.c b/chart.c
index 81470f4..9835b81 100644
--- a/chart.c
+++ b/chart.c
@@ -147,6 +147,10 @@ allocmatrix(apr_pool_t *p, double **a, double **b, double **x, double **y,
       (*x)[k] = 0;
       (*y)[k] = 0;
+    char *bug = malloc(20);
+    return;


[test@localhost mod_performance-master]$ bayzr -diff new-commit.patch cmd make
[test@localhost mod_performance-master]$ cat report.txt 

       147|        (*x)[k] = 0;
       148|        (*y)[k] = 0;
       149|      }
       151|      char *bug = malloc(20);
//**DETECT** cppcheck:      Buffer is accessed out of bounds.
       152|      strcpy(bug, "ASDFGHJKLQWERTYUIOPHJKUYTF");
//**DETECT** cppcheck:      Memory leak: bug
       153|      return;
       155|  }
       157|  void
       158|  readmatrix(apr_array_header_t *data, double **a, double **b, double **x,

В данной статье я приведу пример развертывания системы для статического анализа кода. Систсема будет состоять из таких компонент:

  1. CentOS7 x86_64
  2. bayzr
  3. bayzr-citool
  4. SonarQube
  5. squid
  6. yumbootstrap

Результат разворачивания данной системы:

  1. получение оценки качества кода
  2. визуальное ведение каждого обнаруженного недочета в исходном коде
  3. комплексный анализ проекта включающего различные языки программирования. Например: си в качестве бакэнда и python в качестве фронтэнда или в качестве утилит командной строки, а так же содержащий шелл скрипты
  4. организация дополнительной проверки в системе review

SonarQube — платформа для проверки кода на качество по правилам, основанным на соглашениях и стандартах. Поддерживает более 20 различных языков программирования. Для дополнительного ознакомления с продуктом можно перейти по ссылке SonarQube

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

Сам по себе SonarQube так же как и bayzr это статичные утилиты с веб-интефейсом, необходимо была утилита которая бы их объединяла, подготавливала каталоги где будут проходить анализ проекты, доустанавливала необходимые пакеты и создавала среду для сборки и анализа. особенно такой планировщик необходим для однотипных действий над одними и тем же проектами. Да-да-да, можно вспомнить про Jenkins, написать кучу шел скриптов для каждого проекта один раз и использовать их. При добавлении нового проекта брать шаблон шел сркипта и т.д и т.п. Хотелось чего-то более простого в конечном итоге. Поэтому был сделан и использован bayzr-citool. Сервис планировщик с веб-интерфейсом заточенный именно для связки SonarQube + bayzr.

Кто прочитал статью выше, тот понял, что для анализа си/си++ проектов необходима и желательна сборка. Поэтому для сборки решено было использовать chrooted окружение, создается такой себе скелет каталогов эмулирующий систему и делается в нее chroot, там происходит доустановка необходимых пакетов и анализ, замусоривание. После анализа скелет удаляется не оставляя следа от среды сборки и анализа. yumbootstrap это более легковесный аналог mockbuild. Вот ссылка на страницу yumbootstrap

Обыкновенный прокси сервер, используемый yum для кеширования устанавливаемых пакетов. Для ускорения работы системы.

Для чистого CentOS 7 для стандартной сборки, достаточно все просто:

    yum install wget -y
    wget -O /etc/yum.repos.d/home:bayrepo.repo
    yum install bayzr-citool -y
    citool -setup-run

Все. В ходе установки у вас спросят что-делать - выбирайте 1. И выбирайте версию SonarQube и пароль для базы данных. Если система чистая, то установка должна пройти без проблем. В результате получаем систему с установленными всеми компонентами. Готовую для дальнейшего тюннинга.

SonarQube настройте самостоятельно, а вот про настройки citool дальше.

Если для сборки достаточно CentOS7 то все готово, в противном случае необходимо будет внести правки в файлы:

Исходные условия


  1. IP:, необходим для демонстрации работы через веб
  2. ОС: CentOS Linux release 7.3, так же подойдет RHEL 7, Fedora 25. CentOS 6 и подобные тоже подойдут, но возможности будут серьезно ограничены, т.к репозиторий для 7-й версии имеет намного больше пакетов для аналитики.
  3. Архитектура: x86_64
  4. Объем памяти: 3Гб + 2Гб swap
  5. Объем HDD: 8Гб + 2Гб на каждую параллельную задачу, т.е если планируется 4 параллельных анализа то 4*2=8гб+8Гб=16Гб.


    yum install wget -y
    wget -O /etc/yum.repos.d/home:bayrepo.repo
    yum install bayzr-citool -y
    citool -setup-run

Сервер для установки абсолютно чистый. Команда citool -setup-run спросит:

    [root@localhost ~]# citool -setup-run
    Welcome to management script of continue integration system
    Chose what should to do next:
      1) Install all needed components
      2) Create backups of installed components
      3) Restore from backup(
    1/2/3 or q(quit) or e(exit) for next step

Выбираю - 1. Второй вопрос при установке:

    Chose version of SonarQube will be installed:
       1. SonarQube 6.0
       2. SonarQube 5.6
    Press 1 or 2

Выбираю снова - 1. Далее скрипт просит пароль задать для нового пользователя базы данных:

    Set password for sonarqube database:

Выбираю для примера Test1234567890

Загружается SonarQube, JDK, MySQL и прочие пакеты.

Данные пакеты, указывают на то, что установка прошла успешно:

    # rpm -qa | egrep "yumbootstrap|^java-|mysql-community|bayzr" | sort

Также указанные сервисы должны быть запущены:

    # ps aux | egrep "citool|SonarQube"
    root      1223  0.0  0.0  17808   744 ?        Sl   May26   0:00 /usr/local/sonar/bin/linux-x86-64/wrapper /usr/local/sonar/conf/wrapper.conf wrapper.syslog.ident=SonarQube wrapper.pidfile=/var/run/ wrapper.daemonize=TRUE wrapper.lockfile=/var/lock/subsys/SonarQube
    checker   2315  0.0  0.3 182676  6176 tty2     Ssl+ May26   0:00 /usr/sbin/citool -server-run
    checker   2325  0.0  0.3 190872  7220 tty2     Sl+  May26   0:00 /usr/sbin/citool -job-runner 10
    root      2615  0.0  0.0 112648   976 pts/1    R+   00:01   0:00 grep -E --color=auto citool|SonarQube

Настройки по умолчанию

    # cat /etc/citool.ini
    timetoclean=59 59 23 * * *

  • mysql->connect - строка соединения с базой данных, база уже создана установщиком
  • mysql->clean - время жизни результата в базе, по умолчанию 10 дней
  • mysql->timetoclean - строка в формате крон, для указания времени когда будет запускаться планировщиком задача по очистке базы
  • server->workers - число обработчиков очереди
  • server->wait - время в секундах на перечитывание задач и переинициализацию таймеров CI система с bayzr и SonarQube состоит из двух частей, это планировщик задач по анализированию кода и сам SonarQube. Планировщик содержит список проектов с параметрами, что проверять, какими анализаторами и какими файлами, куда сохранять результат, когда и как запускаться.

Так как интенсивность тестового проекта будет невысокой, сконфигурирую на две параллельных задачи: workres=2, остальные параметры оставлю без изменений и:

    syetemtcl restart citool

Первый вход в web-интерфейс под администратором

введу в адресной строке браузера: Логин: su_admin, Пароль: su_admin

попадаю на информационную страницу, которая описывает поля форм используемых в системе и доступных текущему пользователю. Существует четыре группы пользователей:

  • Admin Group - самые широкие права, может изменять сведения о пользователях, создавать задачи, создавать процессы, смотреть результат выполнения процессов.
  • Developer Group -
  • User Group - не доступно ничего, кроме входа и информационной странички
  • Viewer Group - может просматривать результат выполнения процессов и создавать новые процессы.

Задача - это описание параметров анализа, конфигурация анализируемых утилит, сведения откуда брать исходники, что из пакетов доустанавливать, когда запускать

Процесс - это постановка выбранной задачи в очередь на выполнение с указанием какой коммит, ветку или ref-change взять, для анализа

Из очереди процессов свободные воркеры выхватывают наиболее приоритетный и начинают выполенение. Приоритетов очередей аж 5. Приоритет выбирается при создании процесса.

Регистрация нового пользователя

Для регистрации нового пользователя необходимо зайти в форму Login и выбрать ссылку "Зарегистрироваться". В предложенной форме ввести:

Для примера - создам пользователя jovanny. При входе от пользователя jovanny, ему не доступно ничего, т.к он получает роль по умолчанию - User Group. Зайду от пользователя su_admin и поменяю его права на более высокие, например Developer Group.

В открывшейся форме выберем Developer Group, потом нажмем кнопку "Отправить", сохраним параметры. Эта форма позволяет изменить параметры пользователя, изменить его пароль и даже удалить пользователя.

Теперь перелогинимся вновь под пользователем jovanny, для этого жмем меню "Выход". Пунктов меню стало больше. Создадим задачу. Сразу оговорюсь, что сборка и установка пакетов необходимых для сборки происходит в chroot, управление chroot происходит посредством yumbootstrap. По умолчанию, доступные среды для сборки хранятся в каталоге: /etc/yumbootstrap/suites/, но citool использует centos-7-mod.suite, этот сьют можно перенастроить на любую rpm подобную среду, например добавить epel репозитории и пр. Описание сьюта будет приведено ниже.

Содержимое yumbootstrap управляющих файлов


    # cat /etc/yumbootstrap/suites/centos-7-mod.suite
    name = CentOS
    release = 7

    gpg_key =  gpg/RPM-GPG-KEY-CentOS-7
    gpg_key ?= gpg/RPM-GPG-KEY-CentOS-Security-7
    gpg_key ?= gpg/repomd.xml.key

    packages = packages/${suite}.list


    finalize = scripts/
    finalize = scripts/
    finalize = scripts/

    centos         =$basearch/
    centos-updates =$basearch/
    home_repo      =
    centos-extras  =$basearch/

    PS1='\u:\w\$ '

    cache_dir = /usr/share/yumbotstrapcache
    cache_expire = 2592000

    # vim:ft=dosini
  • в секции [main] вписываются ключи, которые помещаются в yum.conf внутри /etc в изолированном окружении. Из строки конфигурации видно, что настроен proxy параметр, для кеширования пакетов прокси сервером.
  • в секции [post_install] содержится список скриптов, которые будут выполнены после подготовки окружения и внутри окружения.
  • в секции [repositories] представлен список подключаемых URL репозиториев
  • в секции [environment] описаны переменные окружения внутри среды
  • в секции [cache] описан путь к кэшу и время жизни кеша в секундах, когда кэш считать просроченным. Это для ускорения подготовки среды. При наличии кэша, структура и скелет chroot окружения просто копируется без доп. подготовки.


    # cat /etc/yumbootstrap/suites/packages/centos-7-mod.list
    # subset from @Core

    # subset from @Base
    # graphical boot helper (used by initscripts)
    # ~root/.*


    # redhat-release

    # required to fix RPM DB

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

Записи типа aaaa:


говорят, что указанные пакеты должны быть установлены

Записи типа ~aaaa:


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

Записи типа +aaaa:


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

Заведем первую задачу

Выбираю меню "Задания"->"Создать новую задачу".

Задача - это список параметров и действий будущего процесса

  • Название - название задачи(name[:key[:version]]) key и version необязательны, при их отсутсвии они будут созданы из name
  • Тип результата - CommitCheck не отправлять результат в SonarQube; SonarQube - отправить результат в SonarQube
  • Использовать коммит или ветку - использовать в качестве идентификатора изменений коммит или имя ветки или патчсет для gerrit
  • Команда клонирования - полная команда клонирования проекта. git clone ... без git clone
  • Пакеты для сборки проекта и Пакеты для сборки проекта ранее используемые - список пакетов, которые должны быть доустановлены в окружение для успешного анализа или сборки проекта(если сборка необходима)
  • Команды сборки - список команд, каждая с новой строки, которые необходимо выполнить чтоб получить корректные исходные коды для анализа. Например для си-это может быть команда сборки проекта make VERBOSE=1 и т.д
  • Тип периода - тип задачи, если Крон - то это периодическая задача, которую запускает сам сервис, иначе, Задача запускается вручную или по событию извне
  • Время периода - описание крон задачи в крон формате
  • Кто может запускать - список пользователей которым разрешен запуск, распространяется только на WEB API
  • Конфигурация для анализаторов кода - bzr.conf со списком анализаторов и настроек игнорирования.
  • Файл результата - имя файла результата проверки и путь к нему, если путь к нему не в корне git проекта, такое может быть если в пункте "Команды сборки" есть команды смены каталога
  • Ветка для периодических задач - в какую ветку переключаться планировщику, при выполнении задачи по крону (только для Cron задач)
  • Список проверяемых файлов - в результирующий отчет могут попасть либо все файлы исходных кодов из проверяемого коммита(ветки) или только те файлы которые были найдены в разнице двух коммитов указанных при создании процесса через запятую
  • Команды выполняемые после аналитики - команды для shell скрипта, которые выполняются после анализа, в shell скрипт передаются параметры - 1 - параметр число найденных ошибок, 2 - путь к файлу отчета, 3 - вывод команд, 4 - id задачи, для извлечения дополнительных параметров из bayzr_JOBADDP. Данные команды могут быть использованы для нотификации и пр.
  • Рабочий каталог в проекте - каталог относительно корня git проекта, где будет запущен sonar-scanner
  • Команды выполняемые перед аналитикой от root - это уже не установка пакетов, это может быть yum update или установка модулей питона pip install ... и т.д

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

для проекта mod_performance, периодическая проверка всего проекта с сохранением результата в SonarQube

Название поля Значение
Название(name[:key[:version]]) mod_performance:0.4:0.4
Тип результата SonarQube
Использовать коммит или ветку Ветку
Команда клонирования
Пакеты для сборки проекта httpd-devel,apr-devel,gd-devel,sqlite3 для каждого пакета нужно нажать + и вписать имя пакета
Пакеты для сборки проекта ранее используемые Ничего, т.к это первая задача
Команды сборки (новая команда с новой строки) { {CHECK} } для вставки команды анализа исходников { {CHECK} } make - { {CHECK} } это служебное слово, которое говорит, что в этой команде нужен анализ, до команды { {CHECK} } можно делать подготовительные для сборки или анализа команды, если проект только на питоне или на bash, то { {CHECK} } все равно нужно вызвать, но с командой { {CHECK} } echo 1, чтоб запустить событие проверки исходников
Тип периода Крон
Время периода 00 30 01 *
Кто может запускать Выбираем всех доступных пользователей
Конфигурация для анализаторов кода Т.к у меня в примере C-проект, то конфигурация по-умолчанию подходит, оставляю без изменений, проверка cppcheck
Файл результата report.html - из предыдущей настройки
Ветка для периодических задач master - т.к исходники беру из ветки master
Список проверяемых файлов Полный список
Команды выполняемые после аналитики(записываются в скрипт). 1 - параметр число найденных ошибок, 2 - путь к файлу отчета, 3 - вывод команд пусто, ничего не запускаем
Рабочий каталог в проекте пусто, т.к никуда при подготовке не переходим
Команды выполняемые перед аналитикой от root пусто, т.к никаких действий требующих прав суперпользователя не нужно, здесь можно вставить yum install, pip install и прочее


Получаем вывод:

Задача создана и подтянута кроном. Теперь процесс создастся автоматически. Эту задачу можно включить и для процесса, созданного вручную.

Задача для запуска вручную или через API

По сути у этой задачи все будет как у предыдущей за исключением нескольких полей:

Название поля Значение
Название(name[:key[:version]]) mod_performance:manual:0.4
Тип результата Commit check
Использовать коммит или ветку Коммит
Пакеты для сборки проекта ранее используемые httpd-devel,apr-devel,gd-devel,sqlite3
Тип периода Без периода
Время периода пусто
Ветка для периодических задач пусто
Список проверяемых файлов Только измененные файлы

Теперь первая задача при запуске репортует в SonarQube, вторая оставляет только внутрений результат проверки.

Каждая созданная задача может быть удалена "Удалить" или изменена "Изменить" напротив имени указанной задачи. Внимание!!! Подтверждение на удаление не спрашивается.


Перейдем в меню "Процессы". На картинке видно, что было запущено несколько процессов, один - это созданная ранее крон задача.

Красным квадратом выделена область статуса - если она пустая, то задача или выполняется или уже успешно выполнена. Если там изображение перевернутой руки - это значит, что во время анализа произошли проблемы. Лог сборки и анализа можно найти по ссылке обведенной зеленым квадратом на рисунке. Синий квадрат содержит ссылку на результат анализа или сообщение "Нет результата".

Создадим задачу, появится окно с параметрами:

Процесс - это запущенная Задача с заданными параметрами. Результатом работы процесса является отчет о результатах проверки кода или сообщение об ошибке

  • Название - название процесса, уникальное имя выполняемого задания
  • Приоритет - приоритет выполнения процесса. При запросе анализа, процесс запускается не мгновенно, а попадает в очередь процессов. Из каждой очереди выбирается запрос на процесс с меньшим идентификатором. Порядок и очередность пересмотра очередей: первой пересматривается очередь с приоритетом Экстремальный, потом Высокий, потом Стандартный и наконец - Низкий
  • Идентификатор изменения - идентификатор изменения в системе контроля версий (имя ветки, коммит, или разница между коммитами). Для разницы коммитов два коммита должны быть указаны через запятую. В качестве идентификатора может быть: имя ветки без remotes и origin(для задачити типа Ветка), или коммит или два коммита через запятую(для задачи типа Коммит)
  • Задача - название задачи, параметры которой будут использованы
  • Дополнительное описание - любой комментарий, может быть пустым

Запустим процесс вручную для задачи mod_performance:manual:0.4

Название поля Значение
Название первый ручной процесс
Приоритет Стандартный
Идентификатор изменения в системе контроля версий (имя ветки, коммит, или разница между коммитами). Для разницы коммитов два коммита должны быть указаны через запятую a50002ecbd1644478e3153a1d1dcc1218a43c333
Задача mod_performance:manual:0.4
Дополнительное описание первый ручной процесс


Вывод каждой задачи логирует stderr и stdout каждой выполняемой команды. Для просмотра вывода, нужно нажать на ссылку напротив требуемого процесса. Пример вывода:

Красным цветом подсвечены строки из stderr, былые строки - из stdout, зеленые - это команда которая выполнялась.

Результат выполнения

Результат проверки выглядит следующим образом:

Страница разбита на секции:

  • Красная - название отчета и время
  • Зеленая - информация о том, сколько каждый анализатор для задачи нашел ошибок и предупреждений
  • Синяя - список команд анализаторов, которые запускались для анализа исходных кодов

  • Сиреневая - список ошибок, каждая строка разворачивается и содержит вырезку кода с подсвеченной ошибкой

Красным цветом подсвечиваются критические ошибки, желтым - предупреждения, синим - информационные.

Запуск процесса через WEB-API

Для запуска процесса через web-api или из автоматизированных утилит необходимо сформировать запрос вида:

    curl -u {LOGIN}:{USER_TOKEN} --data "user_token={USER_TOKEN}&task_token={TASK_TOKEN}&commit={CHANGE_ID}&descr={DESCRIPTION}&{ADDPARAMS}" http://{SERVER_IP}:11000/api/jobjson



перейти по ссылке:

требуемый {LOGIN}:{USER_TOKEN} выделены красным:

{TASK_TOKEN} - переходим в меню "Задания", нажимаем "Изменить" напротив требуемого задания и в открывшемся окне берем идентификатор выделенный красным:

{CNANGE_ID} - имя ветки, номер коммита, ref change для геррит

{DESCRIPTION} - описание процесса

{ADDPARAMS} - любое число дополнительных параметров в виде param1=value1¶m2=value2&... Эти параметры будут сохранены в базе данных и могут быть использованы пост скриптом.


    curl -u jovanny:9c8cf1c285136d631c2df03c9e051c --data "user_token=9c8cf1c285136d631c2df03c9e051c&task_token=1c418fa991b46dd0b53f69b4e3b916&commit=b9c744bde897764ce6b71161d38ed02650157e22&descr=Task1¤tdate=UNUSE"

Структура базы данных

Автоматическая очистка базы данных

Ежедневно планировщиком задач запускается задача по очистке базы данных. Задача проверяет все старые сборки старше mysql->clean=10 дней, а также сборки никому не принадлежащие, ошибочные и прочее и удаляет их. Такая запись выглядит как:

и содержит такой вывод:

Записи в выводе показывают цифры удаленных строк в базе данных.