Kaip sukonfigūruoti PVS-Studio Travis CI naudojant PSP žaidimų konsolės emuliatoriaus pavyzdį
„Travis CI“ yra paskirstyta žiniatinklio paslauga, skirta kurti ir išbandyti programinę įrangą, kuri naudoja „GitHub“ kaip šaltinio kodo prieglobą. Be aukščiau nurodytų veikimo scenarijų, galite pridėti ir savo, naudodamiesi plačiomis konfigūravimo parinktimis. Šiame straipsnyje mes sukonfigūruosime Travis CI dirbti su PVS-Studio, naudodami PPSSPP kodo pavyzdį.
įvedimas
Travisas CI yra žiniatinklio paslauga, skirta kurti ir išbandyti programinę įrangą. Paprastai jis naudojamas kartu su nuolatine integravimo praktika.
PPSSPP - PSP žaidimų konsolės emuliatorius. Programa gali imituoti bet kokių žaidimų paleidimą iš disko vaizdų, skirtų Sony PSP. Programa buvo išleista 1 m. lapkričio 2012 d. PPSSPP licencijuota pagal GPL v2. Kiekvienas gali padaryti patobulinimų projekto šaltinio kodas.
„PVS-Studio“ — statinis kodo analizatorius, skirtas klaidų ir galimų programos kodo spragų paieškai. Šiame straipsnyje, norėdami pakeisti, PVS-Studio paleisime ne lokaliai kūrėjo kompiuteryje, o debesyje ir ieškosime klaidų PPSSPP.
Eikime į svetainę Travisas CI. Suteikę prieigos teisę naudodami „GitHub“ paskyrą, pamatysime saugyklų sąrašą:
Bandymui aš sujungiau PPSSPP.
Suaktyviname saugyklą, kurią norime rinkti:
Šiuo metu Travis CI negali sukurti mūsų projekto, nes nėra statybos instrukcijų. Taigi laikas konfigūruoti.
Analizės metu mums bus naudingi kai kurie kintamieji, pavyzdžiui, PVS-Studio raktas, kurio būtų nepageidautina nurodyti konfigūracijos faile. Taigi, pridėkime aplinkos kintamuosius naudodami „Travis CI“ kūrimo nustatymus:
Mums reikės:
PVS_USERNAME – vartotojo vardas
PVS_KEY – raktas
MAIL_USER – el. paštas, kuris bus naudojamas ataskaitai siųsti
MAIL_PASSWORD – el. pašto slaptažodis
Paskutiniai du yra neprivalomi. Jie bus naudojami rezultatams siųsti paštu. Jei norite išplatinti ataskaitą kitu būdu, jų nurodyti nereikia.
Taigi, pridėjome mums reikalingus aplinkos kintamuosius:
Dabar sukurkime failą .travis.yml ir įdėkite jį į projekto šaknį. PPSSPP jau turėjo Travis CI konfigūracijos failą, tačiau jis buvo per didelis ir visiškai netinkamas pavyzdžiui, todėl teko jį gerokai supaprastinti ir palikti tik pagrindinius elementus.
Pirmiausia nurodykime kalbą, Ubuntu Linux versiją, kurią norime naudoti virtualioje mašinoje, ir būtinus kūrimo paketus:
matrix:
include:
- os: linux
compiler: "gcc"
env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
- os: linux
compiler: "clang"
env: PPSSPP_BUILD_TYPE=Linux
Šiek tiek daugiau apie skyrių matrica. „Travis CI“ yra du būdai sukurti kūrimo parinktis: pirmasis – nurodyti kompiliatorių sąrašą, operacinių sistemų tipus, aplinkos kintamuosius ir pan., po to sugeneruojama visų galimų kombinacijų matrica; antrasis yra aiškus matricos nurodymas. Žinoma, galite sujungti šiuos du metodus ir pridėti unikalų atvejį arba, priešingai, jo neįtraukti naudodami skyrių išskirti. Daugiau apie tai galite perskaityti Travis CI dokumentacija.
Belieka pateikti konkrečiam projektui skirtas surinkimo instrukcijas:
„Travis CI“ leidžia pridėti savo komandas įvairiems virtualios mašinos gyvavimo etapams. Skyrius prieš_įdiegimą vykdomas prieš diegiant paketus. Tada įrengti, kuris seka įdiegus paketus iš sąrašo addons.aptkurį nurodėme aukščiau. Pats surinkimas vyksta scenarijus. Jei viskas klostėsi gerai, mes atsiduriame po_sėkmės (šiame skyriuje vykdysime statinę analizę). Tai ne visi žingsniai, kuriuos galima pakeisti, jei reikia daugiau, turėtumėte pasidomėti Travis CI dokumentacija.
Kad būtų lengviau skaityti, komandos buvo įtrauktos į atskirą scenarijų .travis.sh, kuris yra projekto šaknyje.
Prieš diegdami paketus, atnaujinsime submodulius. To reikia norint sukurti PPSSPP. Pridėkime pirmąją funkciją .travis.sh (atkreipkite dėmesį į plėtinį):
Dabar mes pradedame tiesiogiai nustatyti automatinį PVS-Studio paleidimą Travis CI. Pirmiausia sistemoje turime įdiegti PVS-Studio paketą:
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
}
Funkcijos pradžioje travis_install mes įdiegiame reikalingus kompiliatorius naudodami aplinkos kintamuosius. Tada, jei kintamasis $PVS_ANALYZE saugo vertę taip (tai nurodėme skyriuje env kūrimo matricos konfigūravimo metu), įdiegiame paketą pvs studija. Be to, nurodomos pakuotės libio-socket-ssl-perl и libnet-ssleay-perl, tačiau jie būtini norint išsiųsti rezultatus, todėl jie nėra būtini, jei pasirinkote kitą ataskaitos pateikimo būdą.
Funkcija atsisiuntimo_ištrauka atsisiunčia ir išpakuoja nurodytą archyvą:
Atėjo laikas sujungti projektą. Tai atsitinka skyriuje scenarijus:
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
}
Tiesą sakant, tai yra supaprastinta pradinė konfigūracija, išskyrus šias eilutes:
if [ "$PVS_ANALYZE" = "Yes" ]; then
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi
Šiame kodo skyriuje mes nustatėme cmake kompiliavimo komandų eksportavimo vėliavėlė. Tai būtina statiniam kodo analizatoriui. Daugiau apie tai galite perskaityti straipsnyje "Kaip paleisti PVS-Studio „Linux“ ir „MacOS“."
Jei surinkimas buvo sėkmingas, mes turime po_sėkmės, kur atliekame statinę analizę:
Pirmoje eilutėje sugeneruojamas licencijos failas iš vartotojo vardo ir rakto, kuriuos nurodėme pačioje pradžioje nustatydami Travis CI aplinkos kintamuosius.
Antroji eilutė tiesiogiai pradeda analizę. Vėliava -j nustato analizei skirtų gijų skaičių, vėliavėlę -l nurodo licenciją, vėliavą -o apibrėžia žurnalų išvedimo failą ir vėliavėlę - DisableLicenseExpirationCheck reikalinga bandomajai versijai, nes pagal numatytuosius nustatymus pvs-studio-analizatorius įspės vartotoją, kad netrukus baigsis licencijos galiojimas. Kad taip nenutiktų, galite nurodyti šią vėliavėlę.
Žurnalo faile yra neapdorota išvestis, kurios negalima nuskaityti nekonvertavus, todėl pirmiausia turite padaryti failą skaitomą. Perleiskime rąstus plog-keitiklis, o išvestis yra html failas.
Šiame pavyzdyje aš nusprendžiau siųsti ataskaitas paštu naudodamas komandą Siųsti laišką.
Dėl to gavome tokį failą .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;
Dabar atėjo laikas perkelti pakeitimus į „git“ saugyklą, o po to „Travis CI“ automatiškai paleis kūrimą. Spustelėkite „ppsspp“, kad patektumėte į kūrimo ataskaitas:
Pamatysime dabartinės konstrukcijos apžvalgą:
Jei statyba bus sėkmingai baigta, gausime el. laišką su statinės analizės rezultatais. Žinoma, el. paštu nėra vienintelis būdas gauti ataskaitą. Galite pasirinkti bet kurį įgyvendinimo būdą. Tačiau svarbu atsiminti, kad užbaigus kūrimą nebus galima pasiekti virtualios mašinos failų.
Klaidų suvestinė
Sėkmingai įveikėme sunkiausią dalį. Dabar įsitikinkime, kad visos mūsų pastangos to vertos. Pažvelkime į keletą įdomių punktų iš statinės analizės ataskaitos, kuri man atėjo paštu (tai ne veltui nurodžiau).
PVS-Studio įspėjimas: V597 Kompiliatorius gali ištrinti funkcijos „memset“ iškvietimą, kuris naudojamas „sum“ buferiui išplauti. Funkcija RtlSecureZeroMemory() turėtų būti naudojama privatiems duomenims ištrinti. sha1.cpp 325
Ši kodo dalis yra saugios maišos modulyje, tačiau joje yra rimta saugos klaida (CWE-14). Pažvelkime į surinkimo sąrašą, kuris sugeneruojamas kuriant derinimo versiją:
; Line 355
mov r8d, 20
xor edx, edx
lea rcx, QWORD PTR sum$[rsp]
call memset
; Line 356
Viskas tvarkoje ir veikia memeset yra vykdomas, taip perrašant svarbius duomenis RAM, tačiau kol kas nesidžiaukite. Pažvelkime į leidimo versijos su optimizavimu surinkimo sąrašą:
Kaip matyti iš sąrašo, kompiliatorius ignoravo kvietimą memeset. Taip yra dėl to, kad funkcijoje sha1 po skambučio memeset nebėra nuorodų į struktūrą ctx. Todėl kompiliatorius nemato prasmės gaišti procesoriaus laiko perrašydamas nenaudojamą atmintį ateityje. Tai galite išspręsti naudodami funkciją RtlSecureZeroMemory arba panašus jai.
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);
}
}
Pirmiausia atkreipkite dėmesį į kitą šaką if. Kodas bus vykdomas tik esant visoms sąlygoms leftvol > 0xFFFF || dešinysis tūris > 0xFFFF || leftvol < 0 || dešinė < 0 pasirodys netikra. Todėl gauname tokius teiginius, kurie bus teisingi ir kitai šakai: leftvol <= 0xFFFF, rightvol <= 0xFFFF, kairysis tūris >= 0 и dešinysis tūris >= 0. Atkreipkite dėmesį į du paskutinius teiginius. Ar prasminga patikrinti, kokia yra būtina sąlyga, kad ši kodo dalis būtų vykdoma?
Taigi galime saugiai pašalinti šiuos sąlyginius teiginius:
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);
}
}
Kitas scenarijus. Už šių perteklinių sąlygų slypi kažkokia klaida. Galbūt jie nepatikrino, ko reikia.
V501 Kairėje ir dešinėje nuo '||' yra identiški antriniai posakiai '!Memory::IsValidAddress(psmfData)' operatorius. scePsmf.cpp 703
Atkreipkite dėmesį į čekį viduje if. Ar jums neatrodo keista, kad tikriname, ar adresas galioja? psmfData, dvigubai daugiau? Taigi man tai atrodo keista... Tiesą sakant, tai, žinoma, yra rašybos klaida, ir buvo mintis patikrinti abu įvesties parametrus.
Ši klaida yra aplanke ext, tad nelabai aktualu projektui, bet klaida buvo rasta anksčiau nei aš ją pastebėjau, todėl nusprendžiau ją palikti. Juk šiame straipsnyje kalbama ne apie klaidų peržiūrą, o apie integraciją su Travis CI, o jokia analizatoriaus konfigūracija nebuvo atlikta.
Kintamas Dydis inicijuojamas konstanta, tačiau kode ji visai nenaudojama iki pat operatoriaus if, kuris, žinoma, suteikia klaidingas tikrinant sąlygas, nes, kaip prisimename, Dydis lygus nuliui. Vėlesni patikrinimai taip pat neturi prasmės.
Matyt, kodo fragmento autorius pamiršo perrašyti kintamąjį Dydis prieš tai.
Stop
Čia tikriausiai ir baigsime klaidas. Šio straipsnio tikslas – pademonstruoti PVS-Studio darbą kartu su Travis CI, o ne kuo nuodugniau analizuoti projektą. Jei nori didesnių ir gražesnių klaidų, visada gali jomis žavėtis čia :).
išvada
Naudojant žiniatinklio paslaugas kuriant projektus kartu su laipsniškos analizės praktika, galima rasti daug problemų iškart po kodo sujungimo. Tačiau vienos versijos gali nepakakti, todėl testavimo nustatymas kartu su statine analize žymiai pagerins kodo kokybę.