PVS-Studio beralih ke cloud: GitLab CI / CD

Gambar 2

Artikel ini merupakan kelanjutan dari serangkaian publikasi tentang penggunaan PVS-Studio dalam sistem cloud. Kali ini kita akan melihat penganalisa bersama dengan GitLab CI, sebuah produk dari GitLab Inc. Integrasi alat analisis statis dalam sistem CI memungkinkan Anda untuk mengidentifikasi bug segera setelah fase pembangunan proyek dan merupakan cara yang sangat efektif untuk mengurangi biaya mendeteksi kesalahan.

Daftar artikel kami yang lain tentang integrasi ke dalam sistem cloud CI:


Informasi tentang perangkat lunak yang digunakan


GitLab adalah layanan online untuk mengelola repositori. Ini dapat digunakan langsung di browser di situs web resmi dengan mendaftarkan akun, atau diinstal dan digunakan di server Anda sendiri.

PVS-Studio adalah alat analisis kode statis yang dirancang untuk mendeteksi kesalahan dan potensi kerentanan dalam program yang ditulis dalam C, C ++, C # dan Java. Ini bekerja pada sistem 64-bit pada Windows, Linux dan macOS dan dapat menganalisis kode yang dirancang untuk platform ARM 32-bit, 64-bit dan tertanam. Jika ini adalah pertama kalinya Anda mencoba analisis kode statis untuk menguji proyek Anda, kami sarankan Anda membaca artikel tentang cara cepat melihat peringatan PVS-Studio yang paling menarik dan mengevaluasi kemampuan alat ini.

Proyek OBS akan digunakan untuk menunjukkan operasi penganalisa statis di cloud. Open Broadcaster Software adalah perangkat lunak sumber terbuka dan gratis untuk perekaman dan streaming video. OBS menyediakan kemampuan untuk mencegat dari perangkat dan sumber secara real time, komposisi adegan, decoding, perekaman dan penyiaran. Transmisi data dilakukan terutama melalui Protokol Pesan Waktu Nyata, dan data dapat ditransfer ke sumber apa pun yang mendukung RTMP - program ini memiliki preset siap pakai untuk penyiaran langsung ke platform streaming paling populer.

Kustomisasi


Untuk memulai dengan GitLab, buka situs dan klik tombol Daftar :

Gambar 6

Anda dapat mendaftar dengan menautkan akun layanan seperti: GitHub, Twitter, Google, BitBucket, Saleforce atau hanya dengan mengisi formulir yang terbuka. Setelah otorisasi, GitLab menemui kami dengan proposal untuk membuat proyek:

Gambar 7

Daftar platform tempat Anda dapat mengimpor:

Gambar 33


Untuk kejelasan, buat proyek kosong:

Gambar 17


Selanjutnya, kita perlu mengunggah proyek kita ke repositori yang dibuat. Ini dilakukan menggunakan prompt yang muncul di jendela proyek yang dibuat.

Gambar 1


Ketika tugas dimulai, GitLab CI mengambil instruksi dari file .gitlab-ci.yml . Anda dapat menambahkannya dengan mengeklik tombol Atur CI / CD , atau cukup membuatnya di repositori lokal dan mengunggahnya ke situs. Kami akan menggunakan opsi pertama:

Gambar 21



Mari kita buat pembungkus minimal untuk skrip:

image: debian job: script: 

Unduh alat analisa dan sendemail, yang akan kita perlukan di masa depan:

 - apt-get update && apt-get -y install wget gnupg - wget -O - https://files.viva64.com/etc/pubkey.txt | apt-key add - - wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list - apt-get update && apt-get -y install pvs-studio sendemail 

Selanjutnya, instal dependensi dan utilitas untuk membangun OBS:

 - apt-get -y install build-essential cmake make pkg-config libx11-dev libgl1-mesa-dev libpulse-dev libxcomposite-dev libxinerama-dev libv4l-dev libudev-dev libfreetype6-dev libfontconfig-dev qtbase5-dev libqt5x11extras5-dev libx264-dev libxcb-xinerama0-dev libxcb-shm0-dev libjack-jackd2-dev libcurl4-openssl-dev libavcodec-dev libqt5svg5 libavfilter-dev libavdevice-dev libsdl2-dev ffmpeg qt5-default qtscript5-dev libssl-dev qttools5-dev qttools5-dev-tools qtmultimedia5-dev libqt5svg5-dev libqt5webkit5-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-jackd2-dev libxrandr-dev libqt5xmlpatterns5-dev libqt5xmlpatterns5 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls28-dev libselinux1-dev linux-libc-dev libtool autotools-dev libio-socket-ssl-perl libnet-ssleay-perl ca-certificates 

Sekarang kita perlu membuat file dengan lisensi analyzer. Secara default, file PVS-Studio.lic akan dibuat di direktori ../.config/PVS-Studio. Dalam hal ini, file lisensi dapat dihilangkan dari parameter peluncuran penganalisis, itu akan diambil secara otomatis:

 - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY 

Di sini, PVS_NAME dan PVS_KEY adalah nama-nama variabel yang nilainya kami tentukan dalam pengaturan. Mereka akan menyimpan login dan kunci lisensi PVS-Studio. Untuk mengatur nilainya, buka: Pengaturan> CI / CD> Variabel.

Gambar 23


Bangun proyek menggunakan cmake:

 - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On /builds/Stolyarrrov/obscheck/ - make -j4 

Kemudian jalankan alat analisa:

 - pvs-studio-analyzer analyze -o PVS-Studio.log 

PVS-Studio.log akan menyimpan hasil analisis. File laporan yang dihasilkan tidak dimaksudkan untuk dibaca, dan untuk membawanya ke tampilan yang dapat diakses oleh mata manusia, kita membutuhkan utilitas plog-converter. Program ini mengonversi log penganalisa ke berbagai format. Agar mudah dibaca, kami akan mengonversi ke format html:

 - plog-converter -t html PVS-Studio.log -o PVS-Studio.html 

Laporan dapat diunggah menggunakan artefak , tetapi kami akan menggunakan metode alternatif dan mengirim file dengan hasil analisa ke email menggunakan utilitas sendemail:

 - sendemail -t $MAIL_TO -u "PVS-Studio report, commit:GITLAB_COMMIT" -m "PVS-Studio report, commit:GITLAB_COMMIT" -s $GMAIL_PORT -o tls=auto -f $MAIL_FROM -xu $MAIL_FROM -xp $MAIL_FROM_PASS -a PVS-Studio.log PVS-Studio.html 

Lengkap .gitlab-ci.yml:

 image: debian job: script: - apt-get update && apt-get -y install wget gnupg - wget -O - https://files.viva64.com/etc/pubkey.txt | apt-key add - - wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list - apt-get update && apt-get -y install pvs-studio sendemail - apt-get -y install build-essential cmake pkg-config libx11-dev libgl1-mesa-dev libpulse-dev libxcomposite-dev libxinerama-dev libv4l-dev libudev-dev libfreetype6-dev libfontconfig-dev qtbase5-dev libqt5x11extras5-dev libx264-dev libxcb-xinerama0-dev libxcb-shm0-dev libjack-jackd2-dev libcurl4-openssl-dev libavcodec-dev libqt5svg5 libavfilter-dev libavdevice-dev libsdl2-dev ffmpeg qt5-default qtscript5-dev libssl-dev qttools5-dev qttools5-dev-tools qtmultimedia5-dev libqt5svg5-dev libqt5webkit5-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-jackd2-dev libxrandr-dev libqt5xmlpatterns5-dev libqt5xmlpatterns5 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls28-dev libselinux1-dev linux-libc-dev libtool autotools-dev make libio-socket-ssl-perl libnet-ssleay-perl ca-certificates - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On /builds/Stolyarrrov/obscheck/ - make -j4 - pvs-studio-analyzer analyze -o PVS-Studio.log - plog-converter -t html PVS-Studio.log -o PVS-Studio.html - sendemail -t $MAIL_TO -u "PVS-Studio report, commit:GITLAB_COMMIT" -m "PVS-Studio report, commit:GITLAB_COMMIT" -s $GMAIL_PORT -o tls=auto -f $MAIL_FROM -xu $MAIL_FROM -xp $MAIL_FROM_PASS -a PVS-Studio.log PVS-Studio.html 

Klik pada tombol komit perubahan . Jika kita melakukan semuanya dengan benar, kita akan melihat tulisan: Konfigurasi GitLab CI ini valid. Untuk melacak kemajuan, buka tab CI / CD> Pipeline.

Gambar 5


Klik menjalankan . Kita akan melihat jendela terminal mesin virtual tempat file konfigurasi kita berjalan. Setelah beberapa waktu, kami menerima pesan: pekerjaan berhasil.

Gambar 29


Jadi, saatnya pergi ke surat dan membuka file html dengan peringatan.

Hasil Validasi


Mari kita sekarang melihat beberapa peringatan dari laporan yang menunjukkan kesalahan dalam proyek Perangkat Lunak Penyiar Terbuka untuk menunjukkan esensi dari analisis kode statis. Tujuan artikel ini adalah untuk menjelaskan prinsip-prinsip interaksi antara PVS-Studio dan GitLab CI / CD, sehingga hanya beberapa fragmen kode menarik dengan kesalahan yang telah ditulis. Kami siap memberikan lisensi sementara kepada penulis proyek, dan jika mereka mau, mereka dapat melakukan analisis proyek yang lebih menyeluruh. Atau mereka dapat memanfaatkan salah satu opsi untuk lisensi PVS-Studio gratis.

Setiap orang juga dapat secara independen menerima kunci percobaan untuk mengeksplorasi kemampuan PVS-Studio dan memeriksa proyek mereka.

Jadi, mari kita lihat beberapa contoh kesalahan yang ditemukan di Open Broadcaster Software.

Peringatan N1

Ekspresi V547 'back_size' memang benar. circlebuf.h (138)

 struct circlebuf { .... size_t capacity; }; static inline void circlebuf_place(struct circlebuf *cb, size_t position,....,const void *data, size_t size) { .... size_t data_end_pos; data_end_pos = position + size; if (data_end_pos > cb->capacity) { size_t back_size = data_end_pos - cb->capacity; if (back_size) { memcpy((uint8_t *)cb->data + position, data, loop_size); } .... } 

Perhatikan baris: jika (data_end_pos> cb-> kapasitas) , pemenuhan kondisi akan berarti bahwa variabel back_size , yang didefinisikan dalam baris di bawah, akan selalu lebih besar dari nol, karena yang jelas lebih kecil dari yang jelas lebih besar dikurangi, yang berarti bahwa kondisinya adalah baris lain di bawah ini, akan selalu benar . Kondisi berlebih tidak begitu berbahaya ketika di bawahnya adalah kode yang mengubah data.

Peringatan N2, N3

V629 Pertimbangkan untuk memeriksa ekspresi '1 << indent'. Pergeseran bit dari nilai 32-bit dengan ekspansi selanjutnya ke tipe 64-bit. profiler.c (610)

 static void profile_print_entry(uint64_t active, unsigned indent, ....) { .... active &= (1 << indent) - 1; .... } 

Campuran operasi pada tipe 32-bit dan 64-bit terlihat mencurigakan di sini. Pertama, mask dihitung menggunakan tipe 32-bit (ekspresi (1 << indent) - 1 ), dan kemudian secara implisit diperluas ke tipe 64-bit dalam ekspresi active & = .... Kemungkinan besar, saat menghitung topeng, penggunaan tipe 64-bit juga diasumsikan.

Versi kode yang benar:

 active &= ((uint64_t)(1) << indent) - 1; 

Atau:

 active &= (1ull << indent) - 1; 

Juga, salin-tempel blok kode ini di bawah ini, yang juga dikeluarkan oleh penganalisis tentang: V629 Pertimbangkan untuk memeriksa ekspresi '1 << indent'. Pergeseran bit dari nilai 32-bit dengan ekspansi selanjutnya ke tipe 64-bit. profiler.c (719)

Peringatan N4

V761 Empat blok teks yang identik ditemukan. 'obs-audio-controls.c' (353)

 static float get_true_peak(....) { .... peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); .... } 

Empat blok identik. Hampir selalu, kode tersebut menunjukkan kesalahan salin-tempel . Kemungkinan besar, fungsi-fungsi ini seharusnya dipanggil dengan argumen yang berbeda. Kalaupun tidak, kode ini terlihat aneh. Solusi yang baik adalah menulis satu blok sekali dan membungkusnya dalam satu lingkaran:

 for(size_t i = 0; i < 3; i++) { peak = _mm_max_ps(peak, abs_ps(intrp_samples)); SHIFT_RIGHT_2PS(new_work, work); VECTOR_MATRIX_CROSS_PS(intrp_samples, work, m3, m1, p1, p3); } 

Peringatan N5

V560 Bagian dari ekspresi kondisional selalu salah: '! Pengubah'. obs-hotkey.c (662)

 typedef struct obs_key_combination obs_key_combination_t; struct obs_key_combination { uint32_t modifiers; obs_key_t key; }; static inline void load_binding(....) { obs_key_combination_t combo = {0}; uint32_t *modifiers = &combo.modifiers; load_modifier(modifiers, data, "shift", INTERACT_SHIFT_KEY); load_modifier(modifiers, data, "control", INTERACT_CONTROL_KEY); load_modifier(modifiers, data, "alt", INTERACT_ALT_KEY); load_modifier(modifiers, data, "command", INTERACT_COMMAND_KEY); if (!modifiers && (combo.key == OBS_KEY_NONE || combo.key >= OBS_KEY_LAST_VALUE)) { .... } .... } 

Definisi fungsi load_modifier :

 static inline void load_modifier(uint32_t *modifiers, obs_data_t *data, const char *name, uint32_t flag) { if (obs_data_get_bool(data, name)) *modifiers |= flag; } 

Seperti yang kita lihat, pengubah adalah penunjuk yang diinisialisasi dengan alamat bidang pengubah dari struktur kombo . Karena nilainya tidak berubah ke tempat verifikasi, nilainya akan tetap nol. Selain itu - antara tempat inisialisasi dan verifikasi, pointer digunakan ketika memanggil fungsi load_modifier , di mana ia dereferensi. Karenanya, memeriksa ! Pengubah tidak masuk akal, karena sebagai hasil dari operator && kami akan selalu salah ketika mengevaluasi ekspresi logis. Saya berpikir bahwa pemrogram ingin memeriksa nilai integer yang terletak di alamat yang disimpan dalam pengubah pointer, tetapi lupa untuk mengubah referensi pointer ini.

Yaitu Bagiku cek itu seharusnya seperti ini:

 if (!*modifiers && ....)  : if (!combo.modifiers && ....) 

Peringatan N6

V575 Potensi penunjuk nol dilewatkan ke fungsi 'strncpy'. Periksa argumen pertama. Periksa baris: 2904, 2903. rtmp.c (2904)

 static int PublisherAuth(....) { .... ptr = malloc(r->Link.app.av_len + pubToken.av_len); strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len); .... } 

Seringkali, kode ini tidak aman karena tidak memperhitungkan bahwa malloc dapat mengembalikan pointer nol. Jika malloc mengembalikan NULL , perilaku yang tidak terdefinisi akan muncul dalam kasus ini, karena argumen pertama ke strncpy adalah NULL .

Anda dapat membaca lebih lanjut tentang mengapa penting untuk memeriksa nilai pengembalian fungsi malloc di artikel terkait.

Peringatan N7, N8, N9

Mari kita coba tebak dalam kasus mana perhitungan yang salah dapat terjadi:

 class OBSProjector : public OBSQTDisplay { .... float sourceX, sourceY, ....; .... } .... void OBSProjector::OBSRenderMultiview(....) { OBSProjector *window = (OBSProjector *)data; .... auto calcBaseSource = [&](size_t i) { switch (multiviewLayout) { case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: window->sourceX = (i % 6) * window->scenesCX; window->sourceY = window->pvwprgCY + (i / 6) * window->scenesCY; break; case MultiviewLayout::VERTICAL_LEFT_8_SCENES: window->sourceX = window->pvwprgCX; window->sourceY = (i / 2) * window->scenesCY; if (i % 2 != 0) { window->sourceX += window->scenesCX; } break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: window->sourceX = 0; window->sourceY = (i / 2) * window->scenesCY; if (i % 2 != 0) { window->sourceX = window->scenesCX; } break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (i < 4) { window->sourceX = (float(i) * window->scenesCX); window->sourceY = 0; } else { window->sourceX = (float(i - 4) * window->scenesCX); window->sourceY = window->scenesCY; } break; default:// MultiviewLayout::HORIZONTAL_TOP_8_SCENES: if (i < 4) { window->sourceX = (float(i) * window->scenesCX); window->sourceY = window->pvwprgCY; } else { window->sourceX = (float(i - 4) * window->scenesCX); window->sourceY = window->pvwprgCY + window->scenesCY; } } } .... } 

Peringatan Analyzer:

  • V636 Ekspresi 'i / 6' secara implisit dilemparkan dari tipe 'size_t' ke tipe 'float'. Pertimbangkan untuk menggunakan pemeran tipe eksplisit untuk menghindari hilangnya bagian fraksional. Contoh: double A = (double) (X) / Y; window-projector.cpp (330)
  • V636 Ekspresi 'i / 2' secara implisit dilemparkan dari tipe 'size_t' ke tipe 'float'. Pertimbangkan untuk menggunakan pemeran tipe eksplisit untuk menghindari hilangnya bagian fraksional. Contoh: double A = (double) (X) / Y; window-projector.cpp (334)
  • V636 Ekspresi 'i / 2' secara implisit dilemparkan dari tipe 'size_t' ke tipe 'float'. Pertimbangkan untuk menggunakan pemeran tipe eksplisit untuk menghindari hilangnya bagian fraksional. Contoh: double A = (double) (X) / Y; window-projector.cpp (340)

Jawaban yang benar: di mana saya tidak dilemparkan ke mengambang . Dalam ekspresi yang ditunjukkan penganalisa kepada kami, pembagian bilangan bulat terjadi. Kode ini mungkin tidak berfungsi persis seperti yang diharapkan oleh programmer.

Kesimpulan


Seperti yang bisa kita lihat, mengintegrasikan analisa statis PVS-Studio ke proyek GitLab Anda cukup sederhana. Untuk melakukan ini, cukup tulis satu file konfigurasi dan masukkan ke dalam repositori cloud Anda. Karena GitLab memiliki mesin virtual terintegrasi sendiri, kita bahkan tidak perlu menghabiskan banyak waktu untuk mengkonfigurasi sistem CI. Memeriksa kode akan memungkinkan Anda untuk mengidentifikasi masalah segera setelah pembuatan, yang akan membantu untuk memperbaikinya ketika kompleksitas dan biaya pengeditan masih kecil.



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Vladislav Stolyarov. PVS-Studio di Awan: GitLab CI / CD .

Source: https://habr.com/ru/post/id476628/


All Articles