Travis CI karûbarek webê ya belavkirî ye ji bo çêkirin û ceribandina nermalava ku GitHub wekî mêvandariya koda çavkaniyê bikar tîne. Digel senaryoyên xebitandinê yên li jor, hûn dikarin bi saya vebijarkên mîhengê yên berfireh re xwe zêde bikin. Di vê gotarê de em ê Travis CI mîheng bikin ku bi karanîna mînaka koda PPSSPP bi PVS-Studio re bixebite.
Pîrozbahiyê
Sazkirina Travis CI
Em ê hewceyê depoyek li ser GitHub, ku projeya ku em hewce ne lê ye, û her weha mifteyek ji bo PVS-Studio (hûn dikarin bistînin
Ka em biçin malperê
Ji bo ceribandinê, min PPSSPP kir.
Em depoya ku em dixwazin berhev bikin çalak dikin:
Heya nuha, Travis CI nikare projeya me ava bike ji ber ku rêwerzên avakirinê tune. Ji ber vê yekê dema veavakirinê ye.
Di dema analîzê de, hin guhêrbar dê ji me re bikêr bin, mînakî, mifteya PVS-Studio, ku nayê xwestin ku di pelê veavakirinê de were destnîşan kirin. Ji ber vê yekê em guhêrbarên jîngehê bi karanîna mîhengên çêkirinê li Travis CI zêde bikin:
Em ê hewce ne
- PVS_USERNAME - navê bikarhêner
- PVS_KEY - key
- MAIL_USER - e-nameya ku dê ji bo şandina raporê were bikar anîn
- MAIL_PASSWORD - şîfreya e-nameyê
Her du yên dawî vebijarkî ne. Ev ê ji bo şandina encaman bi nameyê werin bikar anîn. Ger hûn dixwazin raporê bi rengekî din belav bikin, ne hewce ye ku hûn wan nîşan bidin.
Ji ber vê yekê, me guhêrbarên jîngehê yên ku em hewce ne zêde kirine:
Niha em pelê çêbikin .travis.yml û wê di koka projeyê de bi cih bikin. PPSSPP jixwe ji bo Travis CI pelek vesazkirinê hebû, lêbelê, ew ji bo nimûne pir mezin û bi tevahî neguncav bû, ji ber vê yekê me neçar ma ku wê pir hêsan bikin û tenê hêmanên bingehîn bihêlin.
Pêşî, bila em ziman, guhertoya Ubuntu Linux ya ku em dixwazin di makîneya virtual de bikar bînin û pakêtên pêdivî yên ji bo çêkirinê destnîşan bikin:
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'
Hemî pakêtên ku têne navnîş kirin bi taybetî ji bo PPSSPP hewce ne.
Naha em matrixa civînê destnîşan dikin:
matrix:
include:
- os: linux
compiler: "gcc"
env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
- os: linux
compiler: "clang"
env: PPSSPP_BUILD_TYPE=Linux
Li ser beşê hinekî din matrix. Di Travis CI de, du awayên afirandina vebijarkên avakirinê hene: ya yekem ew e ku navnîşek berhevkeran, celebên pergala xebitandinê, guhêrbarên hawîrdorê, hwd. destnîşan bikin, piştî ku matrixek ji hemî berhevokên gengaz têne çêkirin; ya duyemîn nîşanek eşkere ya matrixê ye. Bê guman, hûn dikarin van her du nêzîkatiyan berhev bikin û dozek bêhempa lê zêde bikin, an, berevajî, wê bi karanîna beşê derxînin. jinavderxistin. Hûn dikarin li ser vê yekê bêtir bixwînin
Tiştê ku dimîne ev e ku meriv rêwerzên meclîsê yên taybetî yên projeyê peyda bike:
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 dihêle hûn ji bo qonaxên cihêreng ên jiyana makîneyek virtual fermanên xwe zêde bikin. Liq before_install berî sazkirina pakêtan hatine darvekirin. Paşan lêkirin, ku sazkirina pakêtan ji navnîşê dişopîne addons.aptku me li jor diyar kir. Civîn bi xwe tê de pêk tê nivîs. Ger her tişt baş bû, wê hingê em xwe tê de dibînin after_success (ew di vê beşê de ye ku em ê analîza statîk bimeşînin). Ev ne hemî gavên ku dikarin bêne guheztin ne, heke hûn bêtir hewce ne, wê hingê divê hûn lê bigerin
Ji bo hêsankirina xwendinê, ferman di skrîptek cûda de hatine danîn .travis.sh, ku li ser koka projeyê tê danîn.
Ji ber vê yekê me pelê jêrîn heye .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
Berî ku pakêtan saz bikin, em ê submodulan nûve bikin. Ev ji bo avakirina PPSSPP hewce ye. Ka em fonksiyona yekem lê zêde bikin .travis.sh (bala dirêjkirinê):
travis_before_install() {
git submodule update --init --recursive
}
Naha em rasterast têne sazkirina destpêkirina otomatîkî ya PVS-Studio li Travis CI. Pêşî divê em pakêta PVS-Studio li ser pergalê saz bikin:
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
}
Di destpêka fonksiyonê de travis_install em berhevkarên ku em hewce ne bi karanîna guhêrbarên hawîrdorê saz dikin. Hingê eger guherbar $PVS_ANALYZE dikanên nirxê Erê (me di beşê de destnîşan kir şandin di dema veavakirina matrixê de), em pakêtê saz dikin pvs-studio. Li gel vê, pakêt jî têne destnîşan kirin libio-socket-ssl-perl и libnet-ssleay-perl, lêbelê, ew ji bo encamên posteyê hewce ne, ji ber vê yekê heke we ji bo radestkirina rapora xwe rêbazek din hilbijartiye ew ne hewce ne.
function download_exttract arşîva diyarkirî dadixe û vedike:
download_extract() {
aria2c -x 16 $1 -o $2
tar -xf $2
}
Wext e ku proje li hev were. Ev di beşê de dibe nivîs:
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
}
Bi rastî, ev veavakirinek orjînal a hêsankirî ye, ji bilî van rêzan:
if [ "$PVS_ANALYZE" = "Yes" ]; then
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi
Di vê beşa kodê de em ji bo danîn cmake ala ji bo hinardekirina emrên berhevkirinê. Ev ji bo analîzkerek koda statîk hewce ye. Hûn dikarin li ser vê gotarê bêtir bixwînin "
Ger meclîs serketî bû, wê demê em bi ser bikevin after_success, ku em analîza statîk dikin:
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
}
Ka em bi hûrgulî li rêzikên jêrîn binêrin:
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
Rêza yekem pelê lîsansê ji nav û mifteya ku me di destpêkê de destnîşan kir dema ku guhêrbarên hawîrdorê yên Travis CI-ê saz kirin diafirîne.
Rêza duyemîn rasterast analîzê dest pê dike. Al -j ji bo analîzê hejmara têlan destnîşan dike, ala -l lîsans, ala nîşan dide -o pelê ji bo derxistina têketin, û ala diyar dike -LicenseExpirationCheck neçalak bike ji bo guhertoyên ceribandinê hewce ne, ji ber ku bi xwerû pvs-studio-analyzer dê bikarhêner hişyar bike ku destûrname li ber qedandinê ye. Ji bo pêşîgirtina vê yekê, hûn dikarin vê alayê diyar bikin.
Pelê têketinê hilberek xav heye ku bêyî veguheztinê nayê xwendin, ji ber vê yekê divê hûn pêşî pelê bixwînin. Werin em qeydan derbas bikin plog-converter, û encam pelek html e.
Di vê nimûneyê de, min biryar da ku bi karanîna fermanê raporên bi e-nameyê bişînim sendemail.
Di encamê de, me pelê jêrîn wergirt .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;
Naha ew dem e ku meriv guheztinên depoya git-ê bikişîne, piştî ku Travis CI dê bixweber çêkirinê bimeşîne. Li ser "ppsspp" bikirtînin da ku biçin raporên çêkirinê:
Em ê nêrînek li ser avakirina heyî bibînin:
Ger avakirin bi serfirazî qediya, em ê e-nameyek bi encamên analîza statîk bistînin. Bê guman, şandina posteyê ne tenê riya wergirtina raporê ye. Hûn dikarin her rêbazek pêkanînê hilbijêrin. Lê girîng e ku ji bîr mekin ku piştî çêkirinê qediya, dê nekare bigihîje pelên makîneya virtual.
Kurteya çewtiyê
Me beşa herî dijwar bi serkeftî qedand. Naha em piştrast bin ku hemî hewildanên me hêja ne. Ka em li hin xalên balkêş ên ji rapora analîza statîk a ku bi e-nameyê ji min re hat binihêrin (ne ji bo tiştek bû ku min ew destnîşan kir).
Optimîzasyona xeternak
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 ) );
}
Hişyariya PVS-Studio:
Ev perçeya kodê di modulê dehşikkirina ewledar de cih digire, lêbelê, ew xeletiyek ewlehiyê ya giran heye (
; Line 355
mov r8d, 20
xor edx, edx
lea rcx, QWORD PTR sum$[rsp]
call memset
; Line 356
Her tişt di rêz û fonksiyonê de ye memeset tê darvekirin, bi vî rengî daneyên girîng di RAM-ê de têne nivîsandin, lêbelê, hîna jî şa nebin. Ka em li navnîşa meclîsê ya guhertoya Release bi xweşbîniyê binêrin:
; 354 :
; 355 : memset( sum, 0, sizeof( sum ) );
; 356 :}
Wekî ku ji navnîşê tê dîtin, berhevkar bang paşguh kir memeset. Ev ji ber ku di fonksiyonê de ye sha1 piştî bangê memeset tu referansa zêdetir ji bo avahiya ctx. Ji ber vê yekê, berhevkar ti wateya windakirina dema pêvajoyê ya li ser nivîsandina bîranîna ku di pêşerojê de nayê bikar anîn, nabîne. Hûn dikarin vê yekê bi karanîna fonksiyonê rast bikin RtlSecureZeroMemory an
Rastîn
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 ) );
}
Berhevdana nehewce
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);
}
}
Hişyariya PVS-Studio:
Ji bo pêşî bala xwe bidin şaxê din if. Kod dê tenê heke hemî mercan were darve kirin leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rastvol < 0 dê derew derkeve. Ji ber vê yekê, em daxuyaniyên jêrîn digirin, ku dê ji bo şaxê din rast be: leftvol <= 0xFFFF, rastvol <= 0xFFFF, çepgir >= 0 и rastvol >= 0. Bala xwe bidin du daxuyaniyên dawî. Ma ew têgihîştî ye ku meriv kontrol bike ka şertek pêdivî ye ji bo pêkanîna vê perçeya kodê?
Ji ber vê yekê em dikarin bi ewlehî van daxuyaniyên şertî jêbirin:
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);
}
}
Senaryoyek din. Li pişt van şert û mercên zêde xeletiyek veşartî heye. Dibe ku wan tiştê ku hewce dike kontrol nekirine.
Ctrl+C Ctrl+V Vegere
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
if (!Memory::IsValidAddress(psmfData) ||
!Memory::IsValidAddress(psmfData)) {
return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
}
....
}
Bala xwe bidin kontrola hundir if. Ma hûn ne ecêb e ku em kontrol bikin ka navnîş derbasdar e? psmfData, du caran zêdetir? Ji ber vê yekê ev ji min re xerîb xuya dike... Bi rastî, ev, bê guman, xeletiyek tîpî ye, û fikir ew bû ku her du pîvanên têketinê kontrol bikin.
Vebijarka rast:
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
if (!Memory::IsValidAddress(psmfStruct) ||
!Memory::IsValidAddress(psmfData)) {
return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
}
....
}
Guherbarek jibîrkirî
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");
}
....
}
Hişyariya PVS-Studio:
Ev xeletî di peldankê de ye ext, ji ber vê yekê ne bi rastî bi projeyê re têkildar e, lê berî ku min bala xwe dayê, xeletî hate dîtin, ji ber vê yekê min biryar da ku wê bihêlim. Beriya her tiştî, ev gotar ne li ser nirxandina xeletiyan e, lê di derbarê entegrasyonê de bi Travis CI re ye, û tu veavakirina analîstê nehatiye kirin.
Têgûherr mezinayî ji hêla domdar ve tête destpêkirin, lêbelê, ew di kodê de, rastê operatorê, qet nayê bikar anîn if, ku, bê guman, dide şaş dema ku şert û mercan kontrol dikin, ji ber ku, wekî ku em bi bîr tînin, mezinayî wek sifir. Kontrolên paşerojê jî bê wate ne.
Xuya ye, nivîskarê perçeya kodê ji bîr kiriye ku guhêrbar binivîsîne mezinayî berî wê.
Rawestan
Li vir dibe ku em ê bi xeletiyan bi dawî bibin. Armanca vê gotarê ev e ku xebata PVS-Studio bi Travis CI re nîşan bide, û ne ku projeyê bi qasî ku gengaz analîz bike. Heke hûn xeletiyên mezintir û xweşiktir dixwazin, hûn dikarin her gav heyranê wan bikin
encamê
Bikaranîna karûbarên malperê ji bo avakirina projeyan bi hev re digel pratîka analîza zêdebûnê dihêle hûn tavilê piştî koda yekbûnê gelek pirsgirêkan bibînin. Lêbelê, dibe ku yek avahî ne bes be, ji ber vê yekê sazkirina ceribandinê digel analîzên statîk dê bi girîngî qalîteya kodê baştir bike.
Girêdanên bikarhêner
Heke hûn dixwazin vê gotarê bi temaşevanên ku bi Îngilîzî diaxivin re parve bikin, ji kerema xwe lînka wergerê bikar bînin: Maxim Zvyagintsev.
Source: www.habr.com