Travis CI ialah perkhidmatan web teragih untuk membina dan menguji perisian yang menggunakan GitHub sebagai pengehosan kod sumber. Sebagai tambahan kepada senario operasi di atas, anda boleh menambah terima kasih anda sendiri kepada pilihan konfigurasi yang luas. Dalam artikel ini kami akan mengkonfigurasi Travis CI untuk bekerja dengan PVS-Studio menggunakan contoh kod PPSSPP.
Pengenalan
Menyediakan Travis CI
Kami memerlukan repositori di GitHub, di mana projek yang kami perlukan terletak, serta kunci untuk PVS-Studio (anda boleh mendapatkan
Mari pergi ke tapak
Untuk ujian, saya bercabang PPSSPP.
Kami mengaktifkan repositori yang ingin kami kumpulkan:
Pada masa ini, Travis CI tidak dapat membina projek kami kerana tiada arahan untuk membina. Jadi sudah tiba masanya untuk konfigurasi.
Semasa analisis, beberapa pembolehubah akan berguna kepada kami, sebagai contoh, kunci untuk PVS-Studio, yang tidak diingini untuk dinyatakan dalam fail konfigurasi. Jadi mari tambahkan pembolehubah persekitaran menggunakan tetapan binaan dalam Travis CI:
Kita perlukan:
- PVS_USERNAME - nama pengguna
- PVS_KEY - kunci
- MAIL_USER - e-mel yang akan digunakan untuk menghantar laporan
- MAIL_PASSWORD - kata laluan e-mel
Dua yang terakhir adalah pilihan. Ini akan digunakan untuk menghantar hasil melalui mel. Jika anda ingin mengedarkan laporan dengan cara lain, anda tidak perlu menunjukkannya.
Jadi, kami telah menambah pembolehubah persekitaran yang kami perlukan:
Sekarang mari buat fail .travis.yml dan letakkan di akar projek. PPSSPP telah pun mempunyai fail konfigurasi untuk Travis CI, walau bagaimanapun, ia terlalu besar dan tidak sesuai untuk contoh, jadi kami perlu memudahkannya dan meninggalkan elemen asas sahaja.
Mula-mula, mari kita nyatakan bahasa, versi Ubuntu Linux yang ingin kita gunakan dalam mesin maya, dan pakej yang diperlukan untuk binaan:
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'
Semua pakej yang disenaraikan diperlukan secara eksklusif untuk PPSSPP.
Sekarang kami menunjukkan matriks pemasangan:
matrix:
include:
- os: linux
compiler: "gcc"
env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
- os: linux
compiler: "clang"
env: PPSSPP_BUILD_TYPE=Linux
Sedikit lagi mengenai bahagian tersebut matriks. Dalam Travis CI, terdapat dua cara untuk mencipta pilihan binaan: yang pertama ialah menentukan senarai penyusun, jenis sistem pengendalian, pembolehubah persekitaran, dsb., selepas itu matriks semua kombinasi yang mungkin dijana; yang kedua ialah petunjuk eksplisit bagi matriks. Sudah tentu, anda boleh menggabungkan kedua-dua pendekatan ini dan menambah kes yang unik, atau, sebaliknya, mengecualikannya menggunakan bahagian tidak termasuk. Anda boleh membaca lebih lanjut mengenai ini dalam
Yang tinggal hanyalah menyediakan arahan pemasangan khusus projek:
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 membolehkan anda menambah arahan anda sendiri untuk pelbagai peringkat kehidupan mesin maya. Bahagian before_install dilaksanakan sebelum memasang pakej. Kemudian memasang, yang mengikuti pemasangan pakej daripada senarai addons.aptyang kami nyatakan di atas. Perhimpunan itu sendiri berlaku di skrip. Jika semuanya berjalan lancar, maka kita akan mendapati diri kita berada di dalamnya selepas_berjaya (dalam bahagian ini kita akan menjalankan analisis statik). Ini bukan semua langkah yang boleh diubah suai, jika anda memerlukan lebih banyak, maka anda harus melihatnya
Untuk memudahkan pembacaan, arahan diletakkan dalam skrip berasingan .travis.sh, yang diletakkan pada akar projek.
Jadi kami mempunyai fail berikut .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
Sebelum memasang pakej, kami akan mengemas kini submodul. Ini diperlukan untuk membina PPSSPP. Mari tambah fungsi pertama ke .travis.sh (perhatikan sambungan):
travis_before_install() {
git submodule update --init --recursive
}
Kini kami datang terus untuk menyediakan pelancaran automatik PVS-Studio di Travis CI. Mula-mula kita perlu memasang pakej PVS-Studio pada sistem:
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
}
Pada permulaan fungsi travis_install kami memasang penyusun yang kami perlukan menggunakan pembolehubah persekitaran. Kemudian jika pembolehubah $PVS_ANALYZE menyimpan nilai Ya (kami menunjukkannya dalam bahagian env semasa konfigurasi matriks binaan), kami memasang pakej pvs-studio. Di samping itu, pakej juga ditunjukkan libio-soket-ssl-perl ΠΈ libnet-ssleay-perl, walau bagaimanapun, ia diperlukan untuk mel hasil, jadi ia tidak diperlukan jika anda telah memilih kaedah lain untuk menyampaikan laporan anda.
Fungsi muat turun_ekstrak memuat turun dan membongkar arkib yang ditentukan:
download_extract() {
aria2c -x 16 $1 -o $2
tar -xf $2
}
Sudah tiba masanya untuk menyusun projek itu. Ini berlaku dalam bahagian skrip:
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
}
Sebenarnya, ini ialah konfigurasi asal yang dipermudahkan, kecuali untuk baris ini:
if [ "$PVS_ANALYZE" = "Yes" ]; then
CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi
Dalam bahagian kod ini yang kami tetapkan cicah bendera untuk mengeksport arahan kompilasi. Ini diperlukan untuk penganalisis kod statik. Anda boleh membaca lebih lanjut mengenai ini dalam artikel "
Jika perhimpunan itu berjaya, maka kita akan sampai selepas_berjaya, di mana kami melakukan analisis statik:
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
}
Mari kita lihat lebih dekat pada baris berikut:
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
Baris pertama menjana fail lesen daripada nama pengguna dan kunci yang kami nyatakan pada awal-awal lagi semasa menyediakan pembolehubah persekitaran Travis CI.
Baris kedua memulakan analisis secara langsung. Bendera -j menetapkan bilangan benang untuk analisis, bendera -l menunjukkan lesen, bendera -o mentakrifkan fail untuk mengeluarkan log, dan bendera -disableLicenseExpirationCheck diperlukan untuk versi percubaan, kerana secara lalai pvs-studio-analyzer akan memberi amaran kepada pengguna bahawa lesen akan tamat tempoh. Untuk mengelakkan perkara ini berlaku, anda boleh menentukan bendera ini.
Fail log mengandungi output mentah yang tidak boleh dibaca tanpa penukaran, jadi anda mesti membuat fail itu boleh dibaca terlebih dahulu. Mari lulus log melalui plog-converter, dan output ialah fail html.
Dalam contoh ini, saya memutuskan untuk menghantar laporan melalui mel menggunakan arahan menghantar e-mel.
Akibatnya, kami mendapat fail berikut .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;
Kini tiba masanya untuk menolak perubahan pada repositori git, selepas itu Travis CI akan menjalankan binaan secara automatik. Klik pada "ppsspp" untuk pergi ke laporan binaan:
Kami akan melihat gambaran keseluruhan binaan semasa:
Jika binaan berjaya disiapkan, kami akan menerima e-mel dengan hasil analisis statik. Sudah tentu, mel bukan satu-satunya cara untuk menerima laporan. Anda boleh memilih mana-mana kaedah pelaksanaan. Tetapi adalah penting untuk diingat bahawa selepas binaan selesai, ia tidak akan dapat mengakses fail mesin maya.
Ringkasan ralat
Kami telah berjaya menyelesaikan bahagian yang paling sukar. Sekarang mari kita pastikan bahawa semua usaha kita berbaloi. Mari lihat beberapa perkara menarik dari laporan analisis statik yang datang kepada saya melalui mel (bukan untuk apa-apa saya menunjukkannya).
Pengoptimuman berbahaya
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 ) );
}
Amaran PVS-Studio:
Sekeping kod ini terletak dalam modul pencincangan selamat, walau bagaimanapun, ia mengandungi kecacatan keselamatan yang serius (
; Line 355
mov r8d, 20
xor edx, edx
lea rcx, QWORD PTR sum$[rsp]
call memset
; Line 356
Semuanya teratur dan berfungsi memet dilaksanakan, dengan itu menimpa data penting dalam RAM, namun, jangan bergembira dahulu. Mari lihat penyenaraian pemasangan versi Keluaran dengan pengoptimuman:
; 354 :
; 355 : memset( sum, 0, sizeof( sum ) );
; 356 :}
Seperti yang dapat dilihat dari penyenaraian, pengkompil mengabaikan panggilan memet. Ini disebabkan oleh fakta bahawa dalam fungsi sha1 selepas panggilan memet tiada lagi rujukan kepada struktur ctx. Oleh itu, pengkompil tidak melihat gunanya membuang masa pemproses menggantikan memori yang tidak digunakan pada masa hadapan. Anda boleh membetulkannya dengan menggunakan fungsi RtlSecureZeroMemory atau
Betul:
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 ) );
}
Perbandingan yang tidak perlu
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);
}
}
Amaran PVS-Studio:
Beri perhatian kepada cawangan lain untuk yang pertama if. Kod akan dilaksanakan hanya jika semua syarat vol kiri > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || vol kanan < 0 akan menjadi palsu. Oleh itu, kami mendapat kenyataan berikut, yang akan menjadi benar untuk cawangan lain: vol kiri <= 0xFFFF, vol kanan <= 0xFFFF, vol kiri >= 0 ΠΈ vol kanan >= 0. Perhatikan dua kenyataan terakhir. Adakah masuk akal untuk menyemak apakah syarat yang diperlukan untuk pelaksanaan sekeping kod ini?
Jadi kami boleh mengalih keluar pernyataan bersyarat ini dengan selamat:
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);
}
}
Satu lagi senario. Terdapat beberapa jenis ralat tersembunyi di sebalik keadaan berlebihan ini. Mungkin mereka tidak menyemak apa yang diperlukan.
Ctrl+C Ctrl+V Memukul Balik
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
if (!Memory::IsValidAddress(psmfData) ||
!Memory::IsValidAddress(psmfData)) {
return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
}
....
}
Perhatikan cek di dalam if. Tidakkah anda rasa pelik kita menyemak sama ada alamat itu sah? psmfData, dua kali lebih? Jadi ini kelihatan pelik kepada saya... Sebenarnya, ini, sudah tentu, kesilapan menaip, dan ideanya adalah untuk menyemak kedua-dua parameter input.
Pilihan yang betul:
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
if (!Memory::IsValidAddress(psmfStruct) ||
!Memory::IsValidAddress(psmfData)) {
return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
}
....
}
Pembolehubah terlupa
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");
}
....
}
Amaran PVS-Studio:
Ralat ini terletak dalam folder ext, jadi tidak begitu relevan dengan projek itu, tetapi pepijat telah ditemui sebelum saya menyedarinya, jadi saya memutuskan untuk meninggalkannya. Lagipun, artikel ini bukan tentang menyemak ralat, tetapi mengenai penyepaduan dengan Travis CI, dan tiada konfigurasi penganalisis dijalankan.
Pembolehubah saiz dimulakan oleh pemalar, bagaimanapun, ia tidak digunakan sama sekali dalam kod, sehingga ke operator if, yang, sudah tentu, memberi palsu sambil menyemak syarat, kerana, seperti yang kita ingat, saiz sama dengan sifar. Pemeriksaan seterusnya juga tidak masuk akal.
Nampaknya, pengarang serpihan kod terlupa untuk menulis ganti pembolehubah saiz sebelum itu.
Berhenti
Di sinilah kita mungkin akan berakhir dengan kesilapan. Tujuan artikel ini adalah untuk menunjukkan kerja PVS-Studio bersama-sama dengan Travis CI, dan bukan untuk menganalisis projek itu seteliti mungkin. Jika anda mahukan kesilapan yang lebih besar dan lebih indah, anda sentiasa boleh mengaguminya
Kesimpulan
Menggunakan perkhidmatan web untuk membina projek bersama-sama dengan amalan analisis tambahan membolehkan anda menemui banyak masalah serta-merta selepas menggabungkan kod. Walau bagaimanapun, satu binaan mungkin tidak mencukupi, jadi menyediakan ujian bersama analisis statik akan meningkatkan kualiti kod dengan ketara.
Pautan berguna
Jika anda ingin berkongsi artikel ini dengan khalayak berbahasa Inggeris, sila gunakan pautan terjemahan: Maxim Zvyagintsev.
Sumber: www.habr.com