A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
A Travis CI egy elosztott webszolgáltatás olyan szoftverek készítésére és tesztelésére, amelyek a GitHubot használják forráskód-tárhelyként. A fenti működési forgatókönyvek mellett a kiterjedt konfigurációs lehetőségeknek köszönhetően hozzáadhatja a sajátját is. Ebben a cikkben a Travis CI-t úgy konfiguráljuk, hogy a PPSSPP kódpélda segítségével működjön együtt a PVS-Studióval.

Bevezetés

Travis C.I. egy webszolgáltatás szoftverek készítésére és tesztelésére. Általában a folyamatos integrációs gyakorlatokkal együtt használják.

PPSSPP — PSP játékkonzol emulátor. A program képes emulálni bármilyen játék elindítását a Sony PSP-hez szánt lemezképekről. A program 1. november 2012-jén jelent meg. A PPSSPP a GPL v2 licenccel rendelkezik. Bárki javíthat rajta projekt forráskódja.

PVS-Stúdió — statikus kódelemző a programkód hibáinak és lehetséges sebezhetőségeinek keresésére. Ebben a cikkben a változtatás kedvéért nem lokálisan, a fejlesztő gépén, hanem a felhőben indítjuk el a PVS-Studio-t, és a PPSSPP-ben keressük a hibákat.

A Travis CI beállítása

Szükségünk lesz egy adattárra a GitHubon, ahol a szükséges projekt található, valamint egy kulcsra a PVS-Studio számára (megszerezheti próba kulcs vagy ingyenes nyílt forráskódú projektekhez).

Menjünk az oldalra Travis C.I.. A GitHub-fiókkal történő engedélyezés után látni fogjuk a tárolók listáját:

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
A teszthez a PPSSPP-t villámoztam.

Aktiváljuk az összegyűjteni kívánt tárolót:

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
Jelenleg a Travis CI nem tudja megépíteni a projektünket, mert nincsenek utasítások az építkezéshez. Tehát itt az ideje a konfigurációnak.

Az elemzés során néhány változó hasznos lesz számunkra, például a PVS-Studio kulcsa, amelyet nem kívánatos megadni a konfigurációs fájlban. Tehát adjunk hozzá környezeti változókat a Travis CI összeállítási beállításaival:

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
Szükségünk van:

  • PVS_USERNAME – felhasználónév
  • PVS_KEY - kulcs
  • MAIL_USER - e-mail, amely a jelentés elküldésére szolgál
  • MAIL_PASSWORD – e-mail jelszó

Az utolsó kettő nem kötelező. Ezeket az eredményeket postai úton küldjük el. Ha a jelentést más módon kívánja terjeszteni, azt nem kell jeleznie.

Tehát hozzáadtuk a szükséges környezeti változókat:

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
Most hozzunk létre egy fájlt .travis.yml és helyezze a projekt gyökerébe. A PPSSPP-nek már volt egy konfigurációs fájlja a Travis CI-hez, azonban az túl nagy volt, és teljesen alkalmatlan a példára, ezért nagyon le kellett egyszerűsítenünk, és csak az alapelemeket hagytuk meg.

Először jelöljük meg a nyelvet, az Ubuntu Linux verzióját, amelyet használni szeretnénk a virtuális gépben, és a szükséges csomagokat a buildhez:

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'

Az összes felsorolt ​​csomag kizárólag a PPSSPP-hez szükséges.

Most jelezzük az összeállítási mátrixot:

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

Egy kicsit bővebben a szakaszról mátrix. A Travis CI-ben kétféleképpen hozhatunk létre összeállítási beállításokat: az első a fordítók, operációs rendszertípusok, környezeti változók stb. listájának megadása, amely után az összes lehetséges kombináció mátrixa generálódik; a második a mátrix explicit jelzése. Természetesen kombinálhatja ezt a két megközelítést, és hozzáadhat egyedi esetet, vagy éppen ellenkezőleg, kizárhatja a szakasz segítségével kizár. Erről bővebben itt olvashat Travis CI dokumentáció.

Nincs más hátra, mint a projektspecifikus összeszerelési utasítások megadása:

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

A Travis CI lehetővé teszi saját parancsok hozzáadását a virtuális gép életének különböző szakaszaihoz. Szakasz a telepítés előtt csomagok telepítése előtt végrehajtva. Akkor telepíteni, amely a listából a csomagok telepítését követi addons.aptamelyet fentebb jeleztünk. Maga az összeszerelés ben történik forgatókönyv. Ha minden jól ment, akkor ott találjuk magunkat a_siker után (ebben a részben végezzük el a statikus elemzést). Ezek nem mind módosítható lépések, ha többre van szükséged, akkor nézz utána Travis CI dokumentáció.

A könnyebb olvashatóság érdekében a parancsokat külön szkriptben helyeztük el .travis.sh, amely a projekt gyökerében van elhelyezve.

Tehát a következő fájl áll rendelkezésünkre .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

A csomagok telepítése előtt frissítjük az almodulokat. Ez szükséges a PPSSPP felépítéséhez. Adjuk hozzá az első függvényt .travis.sh (jegyezd meg a kiterjesztést):

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

Most közvetlenül a PVS-Studio automatikus indításának beállításához érkezünk a Travis CI-ben. Először telepítenünk kell a PVS-Studio csomagot a rendszerre:

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
}

A funkció elején travis_install környezeti változók segítségével telepítjük a szükséges fordítókat. Majd ha a változó $PVS_ANALYZE értéket tárol Igen (a részben jeleztük env mátrix konfigurálása során) telepítjük a csomagot pvs-stúdió. Ezen kívül a csomagokat is feltüntetik libio-socket-ssl-perl и libnet-ssleay-perl, azonban az eredmények postázásához szükségesek, így nem szükségesek, ha más módszert választott a jelentés kézbesítésére.

Funkció letöltés_kivonat letölti és kicsomagolja a megadott archívumot:

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

Ideje összeállítani a projektet. Ez a szakaszban történik forgatókönyv:

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
}

Valójában ez egy egyszerűsített eredeti konfiguráció, kivéve a következő sorokat:

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

A kódnak ebben a szakaszában beállítottuk cmake jelző a fordítási parancsok exportálásához. Ez szükséges egy statikus kódelemzőhöz. Erről bővebben a " cikkben olvashatA PVS-Studio futtatása Linuxon és macOS-en”.

Ha az összeszerelés sikeres volt, akkor eljutunk a_siker után, ahol statikus elemzést végzünk:

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
}

Nézzük meg közelebbről a következő sorokat:

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

Az első sor egy licencfájlt generál abból a felhasználónévből és kulcsból, amelyet a Travis CI környezeti változók beállításakor a legelején adtunk meg.

A második sor közvetlenül indítja az elemzést. Zászló -j beállítja az elemzéshez szükséges szálak számát, flag -l engedélyt, zászlót jelez -o meghatározza a naplók kimeneti fájlját és a zászlót -DisableLicenseExpirationCheck próbaverziókhoz szükséges, hiszen alapértelmezés szerint pvs-studio-analyzer figyelmezteti a felhasználót, hogy a licenc hamarosan lejár. Ennek elkerülése érdekében megadhatja ezt a jelzőt.

A naplófájl nyers kimenetet tartalmaz, amely nem olvasható konverzió nélkül, ezért először olvashatóvá kell tennie a fájlt. Engedjük át a rönköket plog-konverter, a kimenet pedig egy html fájl.

Ebben a példában úgy döntöttem, hogy e-mailben küldöm a jelentéseket a parancs segítségével küldjön e-mailt.

Ennek eredményeként a következő fájlt kaptuk .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;

Most itt az ideje, hogy a változtatásokat a git tárolóba helyezzük, ami után a Travis CI automatikusan futtatja a buildet. Kattintson a „ppsspp” elemre az összeállítási jelentések eléréséhez:

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
Áttekintést fogunk látni a jelenlegi felépítésről:

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával
Ha a build sikeresen befejeződött, e-mailt kapunk a statikus elemzés eredményéről. Természetesen nem postázás az egyetlen módja a jelentés fogadásának. Bármilyen megvalósítási módot választhat. Fontos azonban megjegyezni, hogy a felépítés befejezése után a virtuális gép fájljaihoz nem lehet hozzáférni.

Hibaösszegzés

Sikeresen teljesítettük a legnehezebb részt. Most pedig győződjünk meg arról, hogy minden erőfeszítésünk megéri. Nézzünk meg néhány érdekességet a postai úton hozzám érkezett statikus elemzési jelentésből (nem hiába jeleztem).

Veszélyes optimalizálás

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-Studio figyelmeztetés: V597 A fordító törölheti a 'memset' függvényhívást, amely a 'sum' puffer kiürítésére szolgál. A személyes adatok törléséhez az RtlSecureZeroMemory() függvényt kell használni. sha1.cpp 325

Ez a kódrészlet a biztonságos kivonatoló modulban található, azonban komoly biztonsági hibát tartalmaz (CWE-14). Nézzük meg a Debug verzió összeállításakor keletkező összeállítási listát:

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

Minden rendben és működik memeset végrehajtásra kerül, ezzel felülírva a fontos adatokat a RAM-ban, de még ne örüljünk. Nézzük meg az optimalizálással ellátott Release verzió összeállítási listáját:

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

Amint az a listából látható, a fordító figyelmen kívül hagyta a hívást memeset. Ez annak a ténynek köszönhető, hogy a függvényben sha1 a hívás után memeset nincs többé utalás a szerkezetre ctx. Ezért a fordító nem látja értelmét annak, hogy a processzoridőt a jövőben nem használt memória felülírására pazarolja. Ezt a funkció használatával javíthatja RtlSecureZeroMemory vagy hasonló neki.

korrigálni:

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

Felesleges összehasonlítás

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-Studio figyelmeztetés: V547 A 'leftvol >= 0' kifejezés mindig igaz. sceAudio.cpp 120

Először figyeljen az else ágra if. A kód csak akkor fut le, ha minden feltétel teljesül leftvol > 0xFFFF || rightvol > 0xFFFF || balvolt < 0 || jobb térfogat < 0 hamisnak fog bizonyulni. Ezért a következő állításokat kapjuk, amelyek igazak lesznek az else ágra: leftvol <= 0xFFFF, rightvol <= 0xFFFF, balvolt >= 0 и jobb térfogat >= 0. Figyeld meg az utolsó két állítást. Van értelme ellenőrizni, hogy mi a szükséges feltétele ennek a kódrészletnek a végrehajtásának?

Így nyugodtan eltávolíthatjuk ezeket a feltételes állításokat:

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

Egy másik forgatókönyv. E redundáns feltételek mögött valamilyen hiba rejtőzik. Talán nem ellenőrizték, hogy mire volt szükség.

Ctrl+C Ctrl+V visszaüt

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 A '||' bal és jobb oldalán azonos '!Memory::IsValidAddress(psmfData)' részkifejezések találhatók. operátor. scePsmf.cpp 703

Ügyeljen a belső csekkre if. Nem tartja furcsának, hogy ellenőrizzük a cím érvényességét? psmfData, kétszer annyi? Szóval ez nekem furcsának tűnik... Valójában ez természetesen elírás, és az ötlet az volt, hogy mindkét bemeneti paramétert ellenőrizzük.

Helyes lehetőség:

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

Elfelejtett változó

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-Studio figyelmeztetés: V547 A 'size == 8' kifejezés mindig hamis. syn-att.c 195

Ez a hiba a mappában található ext, tehát nem igazán releváns a projekt szempontjából, de a hibát még azelőtt megtalálták, hogy észrevettem volna, ezért úgy döntöttem, elhagyom. Végül is ez a cikk nem a hibák áttekintéséről szól, hanem a Travis CI-vel való integrációról, és az analizátor konfigurálása nem történt meg.

Változó méret konstans inicializálja, azonban a kódban egyáltalán nem használják, egészen az operátorig if, ami természetesen ad hamis a feltételek ellenőrzése közben, mert emlékszünk rá, méret egyenlő nullával. Az utólagos ellenőrzéseknek szintén nincs értelme.

Úgy tűnik, a kódrészlet szerzője elfelejtette felülírni a változót méret azelőtt.

megáll

Valószínűleg itt érünk véget a hibákkal. Ennek a cikknek az a célja, hogy bemutassa a PVS-Studio és a Travis CI munkáját, nem pedig a projekt lehető legapróbb elemzése. Ha nagyobb és szebb hibákat akarsz, mindig csodálhatod őket itt :).

Következtetés

A webszolgáltatások használata projektek felépítésére és az inkrementális elemzés gyakorlata lehetővé teszi számos probléma azonnali megtalálását a kód egyesítése után. Előfordulhat azonban, hogy egy build nem elég, így a tesztelés és a statikus elemzés együttes beállítása jelentősen javítja a kód minőségét.

Hasznos Linkek

A PVS-Studio konfigurálása Travis CI-ben a PSP játékkonzol emulátor példájával

Ha meg szeretné osztani ezt a cikket egy angolul beszélő közönséggel, kérjük, használja a fordítási linket: Maxim Zvyagintsev. A PVS-Studio beállítása Travis CI-ben a PSP játékkonzol emulátor példájával.

Forrás: will.com

Hozzászólás