Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
Травис ЦИ је дистрибуирани веб сервис за прављење и тестирање софтвера који користи ГитХуб као хостинг изворног кода. Поред горе наведених оперативних сценарија, можете додати своје захваљујући опсежним опцијама конфигурације. У овом чланку ћемо конфигурисати Травис ЦИ да ради са ПВС-Студио користећи пример ППССПП кода.

Увод

Травис ЦИ је веб сервис за прављење и тестирање софтвера. Обично се користи заједно са праксама континуиране интеграције.

ППССПП — емулатор ПСП играће конзоле. Програм је у стању да емулира покретање било које игре са слика диска намењених за Сони ПСП. Програм је објављен 1. новембра 2012. године. ППССПП је лиценциран под ГПЛ в2. Свако може да побољша изворни код пројекта.

ПВС-Студио — статички анализатор кода за тражење грешака и потенцијалних рањивости у програмском коду. У овом чланку, за промену, покренућемо ПВС-Студио не локално на машини програмера, већ у облаку и потражити грешке у ППССПП.

Подешавање Травис ЦИ

Требаће нам спремиште на ГитХуб-у, где се налази пројекат који нам је потребан, као и кључ за ПВС-Студио (можете добити пробни кључ или бесплатно за пројекте отвореног кода).

Идемо на сајт Травис ЦИ. Након ауторизације помоћу вашег ГитХуб налога, видећемо листу складишта:

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
За тест сам рачвао ППССПП.

Активирамо спремиште које желимо да прикупимо:

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
Тренутачно, Травис ЦИ не може да изгради наш пројекат јер нема упутства за изградњу. Дакле, време је за конфигурацију.

Током анализе, неке варијабле ће нам бити корисне, на пример, кључ за ПВС-Студио, који би било непожељно навести у конфигурационој датотеци. Дакле, хајде да додамо променљиве окружења користећи подешавања изградње у Травис ЦИ:

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
Требаће нам:

  • ПВС_УСЕРНАМЕ - корисничко име
  • ПВС_КЕИ - кључ
  • МАИЛ_УСЕР - имејл који ће се користити за слање извештаја
  • МАИЛ_ПАССВОРД - лозинка е-поште

Последња два су опциона. Они ће се користити за слање резултата поштом. Ако желите да дистрибуирате извештај на други начин, не морате их назначити.

Дакле, додали смо променљиве окружења које су нам потребне:

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
Сада направимо датотеку .травис.имл и ставите га у корен пројекта. ППССПП је већ имао конфигурациону датотеку за Травис ЦИ, међутим, она је била превелика и потпуно неприкладна за пример, па смо морали да је увелико поједноставимо и оставимо само основне елементе.

Прво, назначимо језик, верзију Убунту Линук-а коју желимо да користимо у виртуелној машини и потребне пакете за прављење:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

Сви пакети који су наведени су потребни искључиво за ППССПП.

Сада означавамо матрицу склапања:

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"
      env: PPSSPP_BUILD_TYPE=Linux

Још мало о секцији матрица. У Травис ЦИ постоје два начина за креирање опција изградње: први је навођење листе компајлера, типова оперативног система, променљивих окружења, итд., након чега се генерише матрица свих могућих комбинација; други је експлицитна индикација матрице. Наравно, можете комбиновати ова два приступа и додати јединствен случај, или, напротив, искључити га помоћу одељка искључити. Више о овоме можете прочитати у Травис ЦИ документација.

Све што остаје је да обезбедите упутства за монтажу специфична за пројекат:

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

Травис ЦИ вам омогућава да додате сопствене команде за различите фазе живота виртуелне машине. Секција бефоре_инсталл извршава се пре инсталирања пакета. Онда инсталирати, који прати инсталацију пакета са листе аддонс.апткоје смо горе назначили. Сама скупштина се одржава у скрипта. Ако је све прошло како треба, онда се налазимо у афтер_суццесс (у овом одељку ћемо покренути статичку анализу). Ово нису сви кораци који се могу изменити, ако вам је потребно више, онда бисте требали погледати Травис ЦИ документација.

Ради лакшег читања, команде су смештене у посебну скрипту .травис.сх, који се налази у корену пројекта.

Дакле, имамо следећу датотеку .травис.имл:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

Пре инсталирања пакета, ажурираћемо подмодуле. Ово је потребно за изградњу ППССПП. Додајмо прву функцију у .травис.сх (обратите пажњу на проширење):

travis_before_install() {
  git submodule update --init --recursive
}

Сада долазимо директно до подешавања аутоматског покретања ПВС-Студио у Травис ЦИ. Прво морамо да инсталирамо ПВС-Студио пакет на систем:

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}

На почетку функције травис_инсталл ми инсталирамо компајлере који су нам потребни користећи променљиве окружења. Затим ако променљива $ПВС_АНАЛИЗЕ чува вредност да (навели смо то у одељку енв током конфигурације матрице изградње), инсталирамо пакет пвс-студио. Поред овога, назначени су и пакети либио-соцкет-ссл-перл и либнет-сслеаи-перл, међутим, они су потребни за слање резултата поштом, тако да нису неопходни ако сте изабрали други метод за испоруку извештаја.

Функција довнлоад_ектрацт преузима и распакује наведену архиву:

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

Време је да саставите пројекат. Ово се дешава у одељку скрипта:

travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}

У ствари, ово је поједностављена оригинална конфигурација, осим ових редова:

if [ "$PVS_ANALYZE" = "Yes" ]; then
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi

У овом делу кода смо поставили за цмаке заставица за извоз команди компилације. Ово је неопходно за статички анализатор кода. Више о томе можете прочитати у чланку „Како покренути ПВС-Студио на Линук-у и мацОС-у".

Ако је скупштина успела, онда идемо афтер_суццесс, где вршимо статичку анализу:

travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}

Погледајмо ближе следеће редове:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                -o PVS-Studio-${CC}.log 
                                --disableLicenseExpirationCheck
plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html

Први ред генерише датотеку лиценце од корисничког имена и кључа које смо навели на самом почетку приликом подешавања варијабли окружења Травис ЦИ.

Други ред директно започиње анализу. Застава поставља број нити за анализу, заставицу означава лиценцу, заставу дефинише датотеку за излаз дневника и заставицу -дисаблеЛиценсеЕкпиратионЦхецк потребно за пробне верзије, пошто је подразумевано пвс-студио-анализер ће упозорити корисника да ће лиценца ускоро истећи. Да бисте спречили да се то догоди, можете одредити ову заставицу.

Датотека евиденције садржи необрађени излаз који се не може прочитати без конверзије, тако да прво морате учинити датотеку читљивом. Хајде да прођемо кроз трупце плог-конвертер, а излаз је хтмл датотека.

У овом примеру, одлучио сам да шаљем извештаје поштом користећи команду шаљи имејл.

Као резултат, добили смо следећу датотеку .травис.сх:

#/bin/bash

travis_before_install() {
  git submodule update --init --recursive
}

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}
travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}
travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}
set -e
set -x

$1;

Сада је време да се измене унесу у гит спремиште, након чега ће Травис ЦИ аутоматски покренути буилд. Кликните на „ппсспп“ да бисте отишли ​​на извештаје о изградњи:

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
Видећемо преглед тренутне градње:

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример
Ако се изградња успешно заврши, добићемо е-поруку са резултатима статичке анализе. Наравно, слање путем поште није једини начин да добијете извештај. Можете одабрати било који метод имплементације. Али важно је запамтити да након што се градња заврши, неће бити могуће приступити датотекама виртуелне машине.

Резиме грешке

Успешно смо завршили најтежи део. Сада хајде да се уверимо да су сви наши напори вредни тога. Погледајмо неке интересантне тачке из извештаја о статичкој анализи који ми је стигао поштом (нисам узалуд назначио).

Опасна оптимизација

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  memset( &ctx, 0, sizeof( sha1_context ) );
}

Упозорење ПВС-Студио: ВКСНУМКС Компајлер би могао да избрише позив функције 'мемсет', који се користи за испирање бафера 'сум'. Функцију РтлСецуреЗероМемори() треба користити за брисање приватних података. сха1.цпп 325

Овај део кода се налази у безбедном хеш модулу, међутим, садржи озбиљну безбедносну грешку (ЦВЕ-14). Хајде да погледамо списак склопова који се генерише приликом компајлирања верзије за отклањање грешака:

; Line 355
  mov r8d, 20
  xor edx, edx
  lea rcx, QWORD PTR sum$[rsp]
  call memset
; Line 356

Све је у реду и функција мемсет се извршава, чиме се преписују важни подаци у РАМ меморији, међутим, немојте се још радовати. Хајде да погледамо списак склопа верзије Релеасе са оптимизацијом:

; 354  :
; 355  :  memset( sum, 0, sizeof( sum ) );
; 356  :}

Као што се може видети из листинга, компајлер је игнорисао позив мемсет. Ово је због чињенице да у функцији схаКСНУМКС после позива мемсет нема више позивања на структуру цтк. Према томе, компајлер не види смисао у трошењу процесорског времена на преписивање меморије која се не користи у будућности. Ово можете поправити коришћењем функције РтлСецуреЗероМемори или слично њеној.

Тачно:

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  RtlSecureZeroMemory(&ctx, sizeof( sha1_context ) );
} 

Непотребно поређење

static u32 sceAudioOutputPannedBlocking
             (u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    if (leftvol >= 0) {
      chans[chan].leftVolume = leftvol;
    }
    if (rightvol >= 0) {
      chans[chan].rightVolume = rightvol;
    }
    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

Упозорење ПВС-Студио: ВКСНУМКС Израз 'лефтвол >= 0' је увек тачан. сцеАудио.цпп 120

Прво обратите пажњу на грану елсе if. Код ће бити извршен само ако су испуњени сви услови лефтвол > 0кФФФФ || ригхтвол > 0кФФФФ || лефтвол < 0 || десни вол < 0 испоставиће се лажним. Дакле, добијамо следеће изјаве, које ће важити за грану елсе: лефтвол <= 0кФФФФ, десни вол <= 0кФФФФ, леви вол >= 0 и десни вол >= 0. Обратите пажњу на последње две изјаве. Да ли има смисла проверити шта је неопходан услов за извршење овог дела кода?

Дакле, можемо безбедно да уклонимо ове условне изјаве:

static u32 sceAudioOutputPannedBlocking
(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    chans[chan].leftVolume = leftvol;
    chans[chan].rightVolume = rightvol;

    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

Други сценарио. Иза ових сувишних услова крије се нека врста грешке. Можда нису проверили шта је потребно.

Цтрл+Ц Цтрл+В узвраћа ударац

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfData) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

ВКСНУМКС Постоје идентични подизрази '!Мемори::ИсВалидАддресс(псмфДата)' лево и десно од '||' оператер. сцеПсмф.цпп 703

Обратите пажњу на чек унутра if. Не мислите ли да је чудно што проверавамо да ли је адреса важећа? псмфДата, дупло више? Тако да ми ово делује чудно... У ствари, ово је, наравно, грешка у куцању, а идеја је била да се провере оба улазна параметра.

Исправна опција:

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfStruct) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

Заборављена променљива

extern void ud_translate_att(
  int size = 0;
  ....
  if (size == 8) {
    ud_asmprintf(u, "b");
  } else if (size == 16) {
    ud_asmprintf(u, "w");
  } else if (size == 64) {
    ud_asmprintf(u, "q");
  }
  ....
}

Упозорење ПВС-Студио: ВКСНУМКС Израз 'сизе == 8' је увек нетачан. син-атт.ц 195

Ова грешка се налази у фасцикли лок, тако да није баш релевантно за пројекат, али грешка је пронађена пре него што сам је приметио, па сам одлучио да је оставим. На крају крајева, овај чланак није о прегледу грешака, већ о интеграцији са Травис ЦИ, а конфигурација анализатора није извршена.

Вариабле величина је иницијализован константом, међутим, уопште се не користи у коду, све до оператора if, што, наравно, даје лажан проверавајући услове, јер, како се сећамо, величина једнака нули. Накнадне провере такође немају смисла.

Очигледно је аутор фрагмента кода заборавио да препише променљиву величина пре тога.

Стоп

Овде ћемо вероватно завршити са грешкама. Сврха овог чланка је да демонстрира рад ПВС-Студио заједно са Травис ЦИ, а не да анализира пројекат што је могуће детаљније. Ако желите веће и лепше грешке, увек им се можете дивити овде :).

Закључак

Коришћење веб сервиса за прављење пројеката заједно са праксом инкременталне анализе омогућава вам да пронађете многе проблеме одмах након спајања кода. Међутим, једна градња можда неће бити довољна, тако да ће постављање тестирања заједно са статичком анализом значајно побољшати квалитет кода.

Корисни линкови

Како подесити ПВС-Студио у Травис ЦИ користећи ПСП емулатор као пример

Ако желите да поделите овај чланак са публиком која говори енглески, користите линк за превод: Максим Звјагинцев. Како подесити ПВС-Студио у Травис ЦИ на примеру емулатора ПСП конзоле за игру.

Извор: ввв.хабр.цом

Додај коментар