Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Travis CI on hajutatud veebiteenus tarkvara loomiseks ja testimiseks, mis kasutab lähtekoodi hostina GitHubi. Lisaks ülaltoodud tööstsenaariumidele saate tänu ulatuslikele konfiguratsioonivalikutele lisada oma. Selles artiklis konfigureerime Travis CI töötama koos PVS-Studioga, kasutades PPSSPP koodi näidet.

Sissejuhatus

Travis C.I. on veebiteenus tarkvara ehitamiseks ja testimiseks. Tavaliselt kasutatakse seda koos pideva integratsiooni tavadega.

PPSSPP - PSP mängukonsooli emulaator. Programm suudab emuleerida mis tahes mängude käivitamist Sony PSP jaoks mõeldud kettapiltidelt. Programm ilmus 1. novembril 2012. aastal. PPSSPP on litsentsitud GPL v2 alusel. Igaüks saab teha parandusi projekti lähtekood.

PVS-stuudio — staatiline koodianalüsaator programmikoodis vigade ja võimalike haavatavuste otsimiseks. Selles artiklis käivitame vahelduseks PVS-Studio mitte lokaalselt arendaja masinas, vaid pilves ja otsime vigu PPSSPP-st.

Travis CI seadistamine

Vajame GitHubis hoidlat, kus asub vajalik projekt, samuti võtit PVS-Studio jaoks (saate hankida proovivõti või avatud lähtekoodiga projektide jaoks tasuta).

Läheme saidile Travis C.I.. Pärast GitHubi kontoga autoriseerimist näeme hoidlate loendit:

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Testi jaoks harutasin PPSSPP.

Aktiveerime hoidla, mida tahame koguda:

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Hetkel ei saa Travis CI meie projekti ehitada, sest ehitamiseks puuduvad juhised. Seega on aeg seadistada.

Analüüsi käigus on meile kasulikud mõned muutujad, näiteks PVS-Studio võti, mida poleks soovitav konfiguratsioonifailis täpsustada. Nii et lisame keskkonnamuutujad, kasutades Travis CI ehitussätteid:

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Meil on vaja:

  • PVS_USERNAME – kasutajanimi
  • PVS_KEY – võti
  • MAIL_USER – meiliaadress, mida kasutatakse aruande saatmiseks
  • MAIL_PASSWORD – meili parool

Kaks viimast on valikulised. Neid kasutatakse tulemuste posti teel saatmiseks. Kui soovite aruannet muul viisil levitada, ei pea te neid märkima.

Seega oleme lisanud vajalikud keskkonnamuutujad:

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Nüüd loome faili .travis.yml ja asetage see projekti juure. PPSSPP-l oli juba Travis CI konfiguratsioonifail, kuid see oli liiga suur ja näite jaoks täiesti sobimatu, mistõttu pidime seda oluliselt lihtsustama ja jätma ainult põhielemendid.

Esmalt näitame keelt, Ubuntu Linuxi versiooni, mida tahame virtuaalmasinas kasutada, ja ehitamiseks vajalikud paketid:

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'

Kõik loetletud paketid on vajalikud ainult PPSSPP jaoks.

Nüüd näitame montaažimaatriksit:

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

Natuke lähemalt rubriigist maatriks. Travis CI-s on ehitussuvandite loomiseks kaks võimalust: esimene on määrata kompilaatorite, operatsioonisüsteemi tüüpide, keskkonnamuutujate jms loend, mille järel genereeritakse maatriks kõigist võimalikest kombinatsioonidest; teine ​​on maatriksi selgesõnaline märge. Muidugi saate need kaks lähenemisviisi kombineerida ja lisada ainulaadse juhtumi või, vastupidi, selle jaotise abil välistada välistama. Selle kohta saate rohkem lugeda artiklist Travis CI dokumentatsioon.

Jääb üle vaid esitada projektipõhised montaažijuhised:

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 CI võimaldab teil lisada oma käske virtuaalse masina eluea erinevateks etappideks. jaotis enne_installimist käivitatakse enne pakettide installimist. Siis paigaldama, mis järgneb loendist pakettide installimisele addons.aptmillele me eespool osutasime. Kokkupanek ise toimub sisse käsikiri. Kui kõik läks hästi, leiame end sisse pärast_edu (Selles jaotises teostame staatilist analüüsi). Need ei ole kõik sammud, mida saab muuta, kui vajate rohkem, peaksite sisse vaatama Travis CI dokumentatsioon.

Lugemise hõlbustamiseks paigutati käsud eraldi skripti .travis.sh, mis asetatakse projekti juure.

Nii et meil on järgmine fail .travis.yml:

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

Enne pakettide paigaldamist uuendame alammooduleid. Seda on vaja PPSSPP ehitamiseks. Lisame esimese funktsiooni juurde .travis.sh (pange tähele laiendit):

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

Nüüd jõuame otse PVS-Studio automaatse käivitamise seadistamiseni Travis CI-s. Kõigepealt peame süsteemi installima paketi PVS-Studio:

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
}

Funktsiooni alguses travis_install paigaldame keskkonnamuutujaid kasutades vajalikud kompilaatorid. Siis kui muutuja $PVS_ANALYZE talletab väärtust Jah (nimetasime selle jaotises env ehitusmaatriksi seadistamise ajal), installime paketi pvs-stuudio. Lisaks sellele on märgitud ka pakendid libio-socket-ssl-perl и libnet-ssleay-perl, kuid need on tulemuste postitamiseks vajalikud, seega pole need vajalikud, kui olete aruande edastamiseks valinud mõne muu meetodi.

Funktsioon download_extract laadib alla ja pakib lahti määratud arhiivi:

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

On aeg projekt kokku panna. See juhtub jaotises käsikiri:

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
}

Tegelikult on see lihtsustatud algkonfiguratsioon, välja arvatud järgmised read:

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

Selles koodijaotuses määrasime cmmake kompileerimiskäskude eksportimise lipp. See on vajalik staatilise koodianalüsaatori jaoks. Lisateavet selle kohta saate lugeda artiklist "Kuidas käivitada PVS-Studio Linuxis ja macOS-is"

Kui kokkupanek õnnestus, siis jõuame selleni pärast_edu, kus teostame staatilist analüüsi:

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
}

Vaatame lähemalt järgmisi ridu:

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

Esimene rida genereerib litsentsifaili kasutajanimest ja võtmest, mille määrasime Travis CI keskkonnamuutujate seadistamisel kohe alguses.

Teine rida alustab analüüsi otse. Lipp -j määrab analüüsi lõimede arvu, lipp -l tähistab litsentsi, lippu -o määrab faili logide väljastamiseks ja lipu - disableLicenseExpirationCheck prooviversioonide jaoks vajalik, kuna vaikimisi pvs-stuudio-analüsaator hoiatab kasutajat, et litsents hakkab aeguma. Selle vältimiseks saate selle lipu määrata.

Logifail sisaldab töötlemata väljundit, mida ei saa ilma teisendamata lugeda, seega peate esmalt faili loetavaks muutma. Laseme palgid läbi plog-muundurja väljund on html-fail.

Selles näites otsustasin saata aruanded posti teel, kasutades käsku saada email.

Selle tulemusena saime järgmise faili .travis.sh:

#/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;

Nüüd on aeg lükata muudatused git-hoidlasse, misjärel käivitab Travis CI ehituse automaatselt. Ehitamisaruannete avamiseks klõpsake nuppu "ppsspp".

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Näeme praeguse ehituse ülevaadet:

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel
Kui ehitamine on edukalt lõpule viidud, saame staatilise analüüsi tulemustega meili. Loomulikult ei ole postiga saatmine ainus viis aruande saamiseks. Saate valida mis tahes rakendusmeetodi. Kuid on oluline meeles pidada, et pärast ehitamise lõpetamist pole virtuaalse masina failidele juurdepääsetav.

Vea kokkuvõte

Oleme kõige raskema osa edukalt läbinud. Nüüd veendugem, et kõik meie jõupingutused on seda väärt. Vaatame mõnda huvitavat punkti staatilise analüüsi aruandest, mis mulle posti teel jõudis (pole asjata, et ma sellele viitasin).

Ohtlik optimeerimine

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 ) );
}

PVS-Stuudio hoiatus: V597 Kompilaator võib kustutada funktsiooni "memset" kutse, mida kasutatakse "summa" puhvri loputamiseks. Privaatsete andmete kustutamiseks tuleks kasutada funktsiooni RtlSecureZeroMemory(). sha1.cpp 325

See koodijupp asub turvalises räsimoodulis, kuid sisaldab tõsist turvaviga (CWE-14). Vaatame silumisversiooni koostamisel genereeritud koosteloendit:

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

Kõik on korras ja toimib memeset käivitatakse, kirjutades sellega üle olulised andmed RAM-is, kuid ärge rõõmustage veel. Vaatame väljalaske versiooni koosteloendit koos optimeerimisega:

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

Nagu nimekirjast näha, eiras koostaja kõnet memeset. See on tingitud asjaolust, et funktsioonis sha1 pärast kõnet memeset ei viidata enam struktuurile ctx. Seetõttu ei näe kompilaator mõtet raisata protsessori aega selle mälu ülekirjutamisele, mida tulevikus ei kasutata. Saate selle funktsiooni abil parandada RtlSecureZeroMemory või sarnane talle.

Õigesti:

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 ) );
} 

Tarbetu võrdlus

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);
  }
}

PVS-Stuudio hoiatus: V547 Avaldis 'leftvol >= 0' on alati tõene. sceAudio.cpp 120

Kõigepealt pöörake tähelepanu muule harule if. Kood käivitatakse ainult siis, kui kõik tingimused on täidetud vasakvold > 0xFFFF || paremvolt > 0xFFFF || vasakvold < 0 || paremvolt < 0 osutub valeks. Seetõttu saame järgmised väited, mis kehtivad muu haru kohta: leftvol <= 0xFFFF, rightvol <= 0xFFFF, vasakvolt >= 0 и paremvolt >= 0. Pange tähele kahte viimast väidet. Kas on mõtet kontrollida, mis on selle koodijupi täitmiseks vajalik tingimus?

Seega saame need tingimuslaused ohutult eemaldada:

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);
  }
}

Teine stsenaarium. Nende üleliigsete tingimuste taga on peidus mingi viga. Võib-olla nad ei kontrollinud, mida nõuti.

Ctrl+C Ctrl+V lööb tagasi

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

V501 Lahtrist '||' vasakul ja paremal on identsed alamväljendid '!Memory::IsValidAddress(psmfData)' operaator. scePsmf.cpp 703

Pöörake tähelepanu sees olevale tšekile if. Kas teile ei tundu imelik, et me kontrollime, kas aadress on kehtiv? psmfData, kaks korda rohkem? Nii et see tundub mulle imelik... Tegelikult on see muidugi kirjaviga ja mõte oli kontrollida mõlemat sisendparameetrit.

Õige variant:

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

Unustatud muutuja

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");
  }
  ....
}

PVS-Stuudio hoiatus: V547 Avaldis 'suurus == 8' on alati väär. syn-att.c 195

See viga asub kaustas ext, nii et see pole projektiga täpselt seotud, kuid viga leiti enne, kui ma seda märkasin, nii et otsustasin selle jätta. Lõppude lõpuks ei käsitle see artikkel vigade ülevaatamist, vaid integreerimist Travis CI-ga ja analüsaatorit ei konfigureeritud.

Muutuv suurus initsialiseeritakse konstandiga, kuid seda ei kasutata koodis üldse, kuni operaatorini välja if, mis muidugi annab vale tingimusi kontrollides, sest nagu mäletame, suurus võrdne nulliga. Ka hilisematel kontrollidel pole mõtet.

Ilmselt unustas koodifragmendi autor muutuja üle kirjutada suurus enne seda.

Peatus

Siin me tõenäoliselt vigadega lõpetame. Selle artikli eesmärk on demonstreerida PVS-Studio tööd koos Travis CI-ga, mitte analüüsida projekti võimalikult põhjalikult. Kui tahad suuremaid ja ilusamaid vigu, võid neid alati imetleda siin :).

Järeldus

Veebiteenuste kasutamine projektide koostamiseks koos inkrementaalse analüüsi praktikaga võimaldab leida palju probleeme kohe pärast koodi ühendamist. Samas ei pruugi ühest järgust piisata, nii et testimise seadistamine koos staatilise analüüsiga parandab oluliselt koodi kvaliteeti.

Kasulikud lingid

Kuidas konfigureerida PVS-Studio't Travis CI-s PSP mängukonsooli emulaatori näitel

Kui soovite seda artiklit inglise keelt kõneleva publikuga jagada, kasutage tõlkelinki: Maxim Zvjagintsev. Kuidas seadistada PVS-Studio Travis CI-s PSP mängukonsooli emulaatori näitel.

Allikas: www.habr.com

Lisa kommentaar