Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Travis CI se yon sèvis entènèt distribye pou bati ak teste lojisyèl ki sèvi ak GitHub kòm hosting kòd sous. Anplis senaryo fonksyònman ki anwo yo, ou ka ajoute pwòp ou a gras ak opsyon konfigirasyon vaste. Nan atik sa a nou pral konfigirasyon Travis CI pou travay ak PVS-Studio lè l sèvi avèk egzanp kòd PPSSPP la.

Entwodiksyon

Travis C.I. se yon sèvis entènèt pou bati ak tès lojisyèl. Li se anjeneral yo itilize ansanm ak pratik entegrasyon kontinyèl.

PPSSPP - Emulation konsole jwèt PSP. Pwogram nan kapab rivalize lansman nenpòt jwèt ki soti nan imaj ki gen kapasite pou Sony PSP. Pwogram nan te lage sou Novanm 1, 2012. PPSSPP gen lisans anba GPL v2. Nenpòt moun ka fè amelyorasyon nan kòd sous pwojè a.

PVS-estidyo — yon analizè kòd estatik pou chèche erè ak frajilite potansyèl nan kòd pwogram lan. Nan atik sa a, pou yon chanjman, nou pral lanse PVS-Studio pa lokalman sou machin pwomotè a, men nan nwaj la, epi gade pou erè nan PPSSPP.

Mete kanpe Travis CI

Nou pral bezwen yon depo sou GitHub, kote pwojè nou bezwen an ye, ansanm ak yon kle pou PVS-Studio (ou ka jwenn kle jijman oswa gratis pou pwojè Open Source).

Ann ale sou sit la Travis C.I.. Apre otorizasyon lè l sèvi avèk kont GitHub ou a, nou pral wè yon lis depo:

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Pou tès la, mwen fouchèt PPSSPP.

Nou aktive depo nou vle kolekte:

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Nan moman sa a, Travis CI pa ka konstwi pwojè nou an paske pa gen enstriksyon pou bati. Se konsa, li lè pou konfigirasyon.

Pandan analiz la, kèk varyab pral itil nou, pou egzanp, kle a pou PVS-Studio, ki ta endezirab presize nan dosye a konfigirasyon. Se konsa, ann ajoute varyab anviwònman lè l sèvi avèk anviwònman yo bati nan Travis CI:

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Nou pral bezwen:

  • PVS_USERNAME - non itilizatè
  • PVS_KEY - kle
  • MAIL_USER - imel ki pral itilize pou voye rapò a
  • MAIL_PASSWORD - imèl modpas

De dènye yo opsyonèl. Yo pral itilize sa yo pou voye rezilta pa lapòs. Si ou vle distribye rapò a yon lòt fason, ou pa bezwen endike yo.

Se konsa, nou te ajoute varyab anviwònman nou bezwen yo:

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Koulye a, kite a kreye yon dosye .travis.yml epi mete l nan rasin pwojè a. PPSSPP te deja gen yon dosye konfigirasyon pou Travis CI, sepandan, li te twò gwo ak konplètman inoporten pou egzanp lan, kidonk nou te oblije anpil senplifye li epi kite sèlman eleman debaz yo.

Premyèman, ann endike lang lan, vèsyon Ubuntu Linux ke nou vle itilize nan machin vityèl la, ak pakè ki nesesè pou bati a:

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'

Tout pakè ki nan lis yo nesesè sèlman pou PPSSPP.

Koulye a, nou endike matris la asanble:

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

Yon ti kras plis sou seksyon an matris. Nan Travis CI, gen de fason yo kreye opsyon bati: premye a se presize yon lis konpilateur, kalite sistèm opere, varyab anviwònman, elatriye, apre sa yo pwodwi yon matris nan tout konbinezon posib; dezyèm lan se yon endikasyon eksplisit nan matris la. Natirèlman, ou ka konbine de apwòch sa yo epi ajoute yon ka inik, oswa, okontrè, eskli li lè l sèvi avèk seksyon an. eskli. Ou ka li plis sou sa nan Dokiman Travis CI.

Tout sa ki rete se bay enstriksyon asanble espesifik pou pwojè a:

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 pèmèt ou ajoute pwòp kòmandman ou pou plizyè etap nan lavi yon machin vityèl. Seksyon anvan_enstale egzekite anvan enstale pakè yo. Lè sa a enstale, ki swiv enstalasyon pakè ki soti nan lis la addons.aptke nou te endike pi wo a. Asanble a li menm pran plas nan script. Si tout bagay ale byen, Lè sa a, nou jwenn tèt nou nan apre_siksè (se nan seksyon sa a ke nou pral kouri analiz estatik). Sa yo se pa tout etap sa yo ki ka modifye, si ou bezwen plis, Lè sa a, ou ta dwe gade nan Dokiman Travis CI.

Pou fasilite lekti, kòmandman yo te plase nan yon script separe .travis.sh, ki mete nan rasin pwojè a.

Se konsa, nou gen dosye sa a .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

Anvan enstale pakè yo, nou pral mete ajou submodul yo. Sa nesesè pou konstwi PPSSPP. Ann ajoute premye fonksyon an .travis.sh (note ekstansyon an):

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

Koulye a, nou vin dirèkteman nan mete kanpe lansman otomatik PVS-Studio nan Travis CI. Premye nou bezwen enstale pake PVS-Studio sou sistèm lan:

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
}

Nan kòmansman fonksyon an travis_install nou enstale konpilateur nou bezwen yo lè l sèvi avèk varyab anviwònman an. Lè sa a, si varyab la $PVS_ANALYZE magazen valè Wi (nou te endike li nan seksyon an apeprè pandan konfigirasyon matris bati), nou enstale pake a pvs-studio. Anplis de sa, pakè yo tou endike libio-socket-ssl-perl и libnet-ssleay-perl, sepandan, yo obligatwa pou rezilta poste, kidonk yo pa nesesè si ou te chwazi yon lòt metòd pou livrezon rapò ou a.

Fonksyon telechaje_extrait telechaje ak depake achiv espesifye a:

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

Li lè pou nou mete pwojè a ansanm. Sa rive nan seksyon an script:

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
}

An reyalite, sa a se yon konfigirasyon orijinal senplifye, eksepte pou liy sa yo:

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

Nan seksyon sa a nan kòd nou mete pou cmke drapo pou ekspòte kòmandman konpilasyon. Sa nesesè pou yon analizè kòd estatik. Ou ka li plis sou sa nan atik la "Ki jan yo kouri PVS-Studio sou Linux ak macOS".

Si asanble a te reyisi, lè sa a nou jwenn apre_siksè, kote nou fè analiz estatik:

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
}

Ann pran yon gade pi pre nan liy sa yo:

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

Premye liy lan jenere yon fichye lisans ki soti nan non itilizatè a ak kle ke nou te espesifye nan kòmansman an anpil lè w ap mete kanpe varyab anviwònman Travis CI yo.

Dezyèm liy lan kòmanse analiz la dirèkteman. Drapo -j fikse kantite fil pou analiz, drapo -l endike lisans, drapo -o defini dosye a pou pwodiksyon mòso bwa, ak drapo a -disableLicenseExpirationCheck obligatwa pou vèsyon esè, depi pa default pvs-studio-analyzer pral avèti itilizatè a ke lisans lan ap ekspire. Pou anpeche sa rive, ou ka presize drapo sa a.

Fichye boutèy la gen pwodiksyon anvan tout koreksyon ki pa ka li san konvèsyon, kidonk ou dwe premye fè dosye a lizib. Ann pase mòso bwa yo plog-konvètè, ak pwodiksyon an se yon dosye html.

Nan egzanp sa a, mwen deside voye rapò pa lapòs lè l sèvi avèk kòmandman an voye imèl.

Kòm yon rezilta, nou te resevwa dosye sa a .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;

Koulye a, li lè pou pouse chanjman yo nan repozitwa git la, apre sa Travis CI pral otomatikman kouri bati a. Klike sou "ppsspp" pou ale nan rapò konstriksyon yo:

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Nou pral wè yon apèsi sou konstriksyon aktyèl la:

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP
Si konstriksyon an fini avèk siksè, nou pral resevwa yon imèl ak rezilta analiz estatik la. Natirèlman, pa lapòs se pa sèl fason pou resevwa yon rapò. Ou ka chwazi nenpòt metòd aplikasyon. Men, li enpòtan sonje ke apre bati a fini, li pa pral posib jwenn aksè nan dosye yo machin vityèl.

Rezime erè

Nou te konplete avèk siksè pati ki pi difisil la. Koulye a, ann asire w ke tout efò nou yo vo li. Ann gade kèk pwen enteresan nan rapò analiz estatik ki te vin jwenn mwen pa lapòs (se pa pou anyen mwen te endike li).

Danjre optimize

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

Avètisman PVS-Studio: V597 Konpilateur a te kapab efase 'memset' apèl fonksyon, ki itilize pou vide tanpon 'som'. Fonksyon RtlSecureZeroMemory() ta dwe itilize pou efase done prive yo. sha1.cpp 325

Moso kòd sa a sitiye nan modil hachaj an sekirite, sepandan, li gen yon defo sekirite grav (CWE-14). Ann gade nan lis asanble ki pwodui lè w ap konpile vèsyon Debug la:

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

Tout se nan lòd ak fonksyon an memset se egzekite, kidonk ranplase done enpòtan nan RAM, sepandan, pa kontan jis ankò. Ann gade nan lis asanble vèsyon an Release ak optimize:

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

Kòm ka wè nan lis la, du a inyore apèl la memset. Sa a se akòz lefèt ke nan fonksyon an Sha1 apre apèl la memset pa gen plis referans a estrikti CTX. Se poutèt sa, du a wè pa gen okenn pwen nan gaspiye tan processeur ranplase memwa ki pa itilize nan tan kap vini an. Ou ka ranje sa lè w itilize fonksyon an RtlSecureZeroMemory oswa menm jan an pou li.

Kòrèkteman:

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

Konparezon pa nesesè

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

Avètisman PVS-Studio: V547 Ekspresyon 'leftvol >= 0' toujou vre. sceAudio.cpp 120

Peye atansyon sou lòt branch lan pou premye a if. Kòd la pral egzekite sèlman si tout kondisyon yo leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || dwavol <0 pral tounen fo. Se poutèt sa, nou jwenn deklarasyon sa yo, ki pral vre pou lòt branch lan: leftvol <= 0xFFFF, dwavol <= 0xFFFF, kitevol >= 0 и dwavol >= 0. Remake de dènye deklarasyon yo. Èske li fè sans pou tcheke sa ki yon kondisyon nesesè pou ekzekisyon moso kòd sa a?

Se konsa, nou ka san danje retire deklarasyon kondisyonèl sa yo:

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

Yon lòt senaryo. Gen kèk kalite erè kache dèyè kondisyon redondants sa yo. Petèt yo pa t tcheke sa ki te mande yo.

Ctrl+C Ctrl+V frape tounen

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 Gen sou-ekspresyon ki idantik '!Memory::IsValidAddress(psmfData)' sou bò gòch la ak sou bò dwat la nan '||' operatè. scePsmf.cpp 703

Peye atansyon sou chèk anndan an if. Ou pa panse sa dwòl pou nou tcheke si adrès la valab? psmfData, de fwa plis? Se konsa, sa a sanble etranj pou mwen... An reyalite, sa a se, nan kou, yon typo, ak lide a se te tcheke tou de paramèt opinyon.

Opsyon kòrèk:

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

Bliye varyab

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

Avètisman PVS-Studio: V547 Ekspresyon 'size == 8' toujou fo. syn-att.c 195

Erè sa a sitiye nan katab la ext, Se konsa, pa egzakteman ki gen rapò ak pwojè a, men yo te jwenn pinèz la anvan mwen remake li, se konsa mwen deside kite li. Apre yo tout, atik sa a se pa sou revize erè, men sou entegrasyon ak Travis CI, epi pa gen okenn konfigirasyon nan analizè a te pote soti.

Varyab gwosè se inisyalize pa yon konstan, sepandan, li pa itilize nan tout nan kòd la, dwa desann nan operatè a if, ki, nan kou, bay fo pandan y ap tcheke kondisyon yo, paske, jan nou sonje, gwosè egal a zewo. Chèk ki vin apre yo pa gen okenn sans tou.

Aparamman, otè fragman kòd la bliye ranplase varyab la gwosè anvan sa.

Sispann

Sa a se kote nou pral pwobableman fini ak erè yo. Objektif atik sa a se demontre travay PVS-Studio ansanm ak Travis CI, epi yo pa analize pwojè a kòm byen ke posib. Si ou vle pi gwo ak pi bèl erè, ou ka toujou admire yo isit la :).

Konklizyon

Sèvi ak sèvis entènèt pou konstwi pwojè ansanm ak pratik analiz incrémentielle pèmèt ou jwenn anpil pwoblèm imedyatman apre fusion kòd. Sepandan, yon sèl bati ka pa ase, kidonk mete kanpe tès ansanm ak analiz estatik pral siyifikativman amelyore kalite kòd la.

lyen itil

Ki jan yo konfigirasyon PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan yon Emulation konsole jwèt PSP

Si ou vle pataje atik sa a ak yon odyans ki pale angle, tanpri itilize lyen tradiksyon an: Maxim Zvyagintsev. Ki jan yo mete PVS-Studio nan Travis CI lè l sèvi avèk egzanp lan nan Emulation konsole jwèt PSP.

Sous: www.habr.com

Add nouvo kòmantè