Travis CI adalah layanan web terdistribusi untuk membangun dan menguji perangkat lunak yang menggunakan GitHub sebagai layanan hosting kode sumber. Selain skrip di atas, Anda dapat menambahkan skrip Anda sendiri, berkat opsi konfigurasi yang luas. Pada artikel ini kita akan mengatur Travis CI untuk bekerja dengan PVS-Studio dengan contoh kode PPSSPP.
Pendahuluan
Travis CI adalah layanan web untuk membangun dan menguji perangkat lunak. Biasanya digunakan dalam kombinasi dengan praktik integrasi berkelanjutan.
PPSSPP adalah emulator konsol game PSP. Program ini mampu meniru peluncuran game apa pun dengan gambar cakram yang dirancang untuk Sony PSP. Program ini dirilis pada 1 November 2012. PPSSPP didistribusikan di bawah lisensi GPL v2. Siapa pun dapat melakukan perbaikan pada
kode sumber proyek.
PVS-Studio - penganalisa kode statis untuk mencari kesalahan dan potensi kerentanan dalam kode program. Pada artikel ini, kami akan meluncurkan PVS-Studio di cloud alih-alih secara lokal di komputer pengembang untuk berbagai tujuan dan akan mencari kesalahan di PPSSPP.
Travis ci mengatur
Kami akan membutuhkan repositori di GitHub di mana proyek yang kami butuhkan berada, serta kunci untuk PVS-Studio (Anda bisa mendapatkan
kunci percobaan atau yang
gratis untuk proyek-proyek Sumber Terbuka ).
Mari kita pergi ke situs
Travis CI . Setelah otorisasi dengan bantuan akun GitHub, kami akan memiliki daftar repositori:
Untuk pengujian, saya membuat garpu PPSSPP.
Kami mengaktifkan repositori yang ingin kami bangun:
Saat ini, Travis CI tidak dapat membangun proyek kami karena tidak ada instruksi untuk membangunnya. Itu sebabnya saatnya untuk konfigurasi.
Selama analisis kita akan memerlukan beberapa variabel, misalnya, kunci untuk PVS-Studio, yang tidak diinginkan untuk ditentukan dalam file konfigurasi. Jadi, mari kita tambahkan variabel lingkungan dengan mengkonfigurasi build di Travis CI:
Kami akan membutuhkan:
- PVS_USERNAME - nama pengguna
- PVS_KEY - kunci
- MAIL_USER - email yang akan digunakan untuk mengirim laporan
- MAIL_PASSWORD - kata sandi email
Dua yang terakhir adalah opsional. Mereka akan digunakan untuk mengirim hasilnya melalui surat. Jika Anda ingin mengirim laporan dengan cara lain, Anda tidak perlu menentukannya.
Jadi, kami telah menambahkan variabel lingkungan yang kami butuhkan:
Sekarang mari kita membuat file
.travis.yml dan meletakkannya di root proyek. PPSSPP sudah memiliki file konfigurasi untuk Travis CI, namun itu terlalu besar dan tidak cocok untuk contoh, jadi kami harus menyederhanakannya dan hanya menyisakan elemen dasar.
Pertama, mari kita tentukan bahasa pemrograman, versi Ubuntu Linux yang ingin kita gunakan pada mesin virtual, dan paket yang diperlukan untuk membangun:
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 paket tambahan hanya diperlukan untuk PPSSPP.
Sekarang tentukan matriks bangunan:
matrix: include: - os: linux compiler: "gcc" env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes - os: linux compiler: "clang" env: PPSSPP_BUILD_TYPE=Linux
Sedikit lebih banyak tentang bagian
matriks . Di Travis CI ada dua cara untuk membuat opsi membangun: yang pertama adalah menentukan kompiler, jenis sistem operasi, variabel lingkungan dll. dengan daftar, setelah itu matriks semua kombinasi yang mungkin akan dihasilkan; yang kedua adalah indikasi eksplisit dari matriks. Tentu saja, Anda dapat menggabungkan kedua pendekatan ini dan menambahkan kasus unik, atau, sebaliknya, mengecualikannya dengan menggunakan bagian
mengecualikan . Anda dapat membaca lebih lanjut tentang ini di
dokumentasi Travis CI .
Satu-satunya hal yang harus dilakukan adalah menentukan instruksi pembangunan spesifik proyek:
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 memungkinkan Anda untuk menambahkan perintah Anda sendiri untuk berbagai tahap kehidupan mesin virtual. Bagian
before_install berjalan sebelum menginstal paket. Kemudian
instal , yang mengikuti instalasi paket dari daftar
addons.apt yang telah kami tentukan di atas. Build itu sendiri terjadi dalam
skrip . Jika semuanya telah berhasil, kita masuk ke
after_success (di sinilah kita akan memulai analisis statis). Ini bukan semua langkah yang dapat Anda modifikasi, jika Anda membutuhkan lebih banyak, Anda harus melihat dalam
dokumentasi tentang Travis CI .
Untuk kenyamanan membaca perintah dimasukkan ke dalam
skrip terpisah
.travis.sh , yang ditempatkan di root proyek.
Jadi, kami memiliki file 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 menginstal paket, mari kita perbarui submodules. Ini diperlukan untuk membangun PPSSPP. Tambahkan fungsi pertama ke
.travis.sh (perhatikan ekstensi):
travis_before_install() { git submodule update --init --recursive }
Sekarang kami datang langsung untuk menyiapkan peluncuran otomatis PVS-Studio di Travis CI. Pertama, kita perlu menginstal paket PVS-Studio ke dalam 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 awal fungsi
travis_install kita menginstal kompiler yang kita perlukan menggunakan variabel lingkungan. Kemudian, jika variabel
$ PVS_ANALYZE menyimpan nilai
Ya (kami tentukan di bagian
env ketika mengkonfigurasi matriks build), kami menginstal paket
pvs-studio . Selain itu, ada juga paket
libio-socket-ssl-perl dan
libnet-ssleay-perl , tetapi mereka diperlukan untuk mengirim hasilnya melalui surat, jadi mereka tidak perlu jika Anda memilih cara lain untuk pengiriman laporan.
Fungsi download_extract mengunduh dan membongkar arsip yang ditentukan:
download_extract() { aria2c -x 16 $1 -o $2 tar -xf $2 }
Saatnya membangun proyek. Ini terjadi di bagian
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 adalah konfigurasi asli yang disederhanakan, kecuali untuk baris-baris ini:
if [ "$PVS_ANALYZE" = "Yes" ]; then CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}" fi
Di bagian kode ini, kita menetapkan flag ekspor perintah kompilasi untuk
cmake . Ini diperlukan untuk penganalisa kode statis. Anda dapat membaca lebih lanjut tentang hal ini di artikel "
Cara meluncurkan PVS-Studio di Linux dan macOS ".
Jika build berhasil, kita akan sampai ke
after_success tempat kita akan menjalankan analisis statis:
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 mail@domain.com \ -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 perhatikan baris berikut secara rinci:
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 menghasilkan file lisensi dari nama pengguna dan kunci yang kami tentukan di awal konfigurasi variabel lingkungan Travis CI.
Baris kedua memulai analisis secara langsung. Flag
-j <N> menetapkan jumlah utas analisis, flag
-l <file> menetapkan lisensi, flag
-o <file> mengatur file untuk menampilkan log, dan flag -
disableLicenseExpirationCheck diperlukan untuk versi percobaan , karena secara default
pvs-studio-analyzer akan memperingatkan pengguna tentang berakhirnya lisensi. Untuk mencegah hal ini terjadi, Anda dapat menentukan bendera ini.
File log berisi output yang tidak diproses yang tidak dapat dibaca tanpa konversi, jadi pertama-tama Anda harus membuat file tersebut dapat dibaca. Mari kita jalankan log melalui
plog-converter dan dapatkan file html di output.
Dalam contoh ini saya memutuskan untuk mengirim laporan melalui surat menggunakan perintah
sendemail .
Hasilnya adalah
file .travis.sh berikut:
#/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 mail@domain.com \ -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;
Saatnya untuk menambahkan perubahan ke repositori git, dan kemudian Travis CI akan secara otomatis memulai pembuatan. Klik "ppsspp" untuk membuat laporan:
Kami akan melihat gambaran umum bangunan saat ini:
Jika build berhasil diselesaikan, kami akan menerima email dengan hasil analisis statis. Tentu saja, mengirim melalui surat bukan satu-satunya cara untuk mendapatkan laporan. Anda dapat memilih metode implementasi apa pun. Tetapi penting untuk diingat bahwa tidak mungkin mendapatkan akses ke file mesin virtual setelah pembangunan selesai.
Tinjauan singkat kesalahan
Kami telah berhasil menyelesaikan bagian yang paling sulit. Mari kita sekarang memastikan bahwa semua upaya kita telah dibenarkan. Mari kita pertimbangkan beberapa poin menarik dari laporan analisis statis yang datang kepada saya melalui surat (bukan apa-apa yang saya tentukan).
Optimalisasi 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 ) ); }
Peringatan PVS-Studio:
V597 Kompiler dapat menghapus panggilan fungsi 'memset', yang digunakan untuk membersihkan buffer 'sum'. Fungsi RtlSecureZeroMemory () harus digunakan untuk menghapus data pribadi. sha1.cpp 325
Fragmen kode ini terletak di modul hashing aman, tetapi berisi cacat keamanan serius (
CWE-14 ). Mari kita pertimbangkan daftar assembler yang dihasilkan ketika versi Debug mengkompilasi:
; Line 355 mov r8d, 20 xor edx, edx lea rcx, QWORD PTR sum$[rsp] call memset ; Line 356
Semuanya baik-baik saja dan fungsi
memset dijalankan, sehingga menghapus data penting dalam RAM, tetapi Anda tidak harus senang lagi. Mari kita pertimbangkan daftar assembler dari versi Rilis dengan optimisasi:
; 354 : ; 355 : memset( sum, 0, sizeof( sum ) ); ; 356 :}
Seperti yang dapat Anda lihat dari daftar, kompiler mengabaikan panggilan
memset . Ini terkait dengan fakta bahwa fungsi
sha1 tidak lagi memanggil struktur
ctx setelah memanggil
memset . Itu sebabnya kompiler tidak melihat adanya arti membuang waktu prosesor pada menimpa memori yang tidak digunakan di masa depan. Anda dapat memperbaikinya dengan menggunakan fungsi
RtlSecureZeroMemory atau fungsi
serupa .
Benar:
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;
Peringatan PVS-Studio: Ekspresi
V547 'leftvol> = 0' selalu benar. sceAudio.cpp 120
Perhatikan cabang yang lain untuk yang pertama
jika . Kode akan dieksekusi hanya jika semua kondisi
tersisa> 0xFFFFF || rightvol> 0xFFFF || leftvol <0 || rightvol <0 salah. Oleh karena itu, kita mendapatkan pernyataan berikut yang akan benar untuk cabang lain:
leftvol <= 0xFFFFF, rightvol <= 0xFFFFF, leftvol> = 0 dan rightvol> = 0 . Perhatikan dua pernyataan terakhir. Apakah masuk akal untuk memeriksa kondisi apa yang diperlukan untuk mengeksekusi fragmen kode ini?
Jadi kami dapat dengan tenang menghapus operator bersyarat ini:
static u32 sceAudioOutputPannedBlocking (u32 chan, int leftvol, int rightvol, u32 samplePtr) { int result = 0;
Skenario lain. Di belakang kondisi yang berlebihan ini ada beberapa kesalahan. Mungkin kita sudah memeriksa apa yang tidak kita butuhkan ...
Ctrl + C Ctrl + V menyerang 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"); } .... }
V501 Ada sub-ekspresi identik '! Memori :: IsValidAddress (psmfData)' di kiri dan di kanan '||' operator. scePsmf.cpp 703
Catat cek di dalam
jika . Bukankah aneh bagi Anda bahwa kami memeriksa apakah alamat
psmfData valid dua kali lipat? Jadi saya merasa aneh ... Sebenarnya, kami memiliki kesalahan cetak sebelum kami, tentu saja, dan idenya adalah untuk memeriksa kedua parameter input.
Varian yang benar adalah:
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) { if (!Memory::IsValidAddress(psmfStruct) || !Memory::IsValidAddress(psmfData)) { return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address"); } .... }
Variabel yang terlupakan
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"); } .... }
Peringatan PVS-Studio: Ekspresi
V547 'size == 8' selalu salah. syn-att.c 195
Kesalahan ini terletak di folder
ext , jadi itu tidak benar-benar berlaku untuk proyek, tetapi kesalahan itu ditemukan sebelum saya menyadarinya, jadi saya memutuskan untuk menyimpannya. Namun, artikel ini bukan tentang tinjauan kesalahan tetapi tentang integrasi dengan Travis CI dan tidak ada konfigurasi penganalisa yang dilakukan.
Variabel
ukuran diinisialisasi dengan konstanta, tetapi tidak digunakan sama sekali dalam kode hingga
jika operator yang, tentu saja, menghasilkan informasi
palsu sambil memeriksa kondisi karena, seperti yang kita ingat,
ukurannya sama dengan nol. Pemeriksaan selanjutnya juga tidak masuk akal.
Rupanya, pembuat fragmen kode lupa untuk menimpa variabel
ukuran sebelum itu.
Berhenti
Di situlah kita akan berhenti dengan kesalahan. Tujuan artikel ini adalah untuk menunjukkan bagaimana PVS-Studio bekerja dengan Travis CI dan tidak menganalisis proyek selengkap mungkin. Jika Anda ingin kesalahan yang lebih besar dan lebih indah, Anda selalu dapat melihatnya di
sini :).
Kesimpulan
Menggunakan layanan web untuk membangun proyek bersama dengan praktik analisis tambahan memungkinkan Anda mendeteksi banyak masalah setelah penggabungan kode. Namun, satu build mungkin tidak cukup, sehingga pengaturan pengujian bersama dengan analisis statis akan secara signifikan meningkatkan kualitas kode.
Tautan yang bermanfaat