PVS-Studio di Awan - Menjalankan Analisis pada Travis CI

Saat ini, sistem cloud CI adalah layanan yang sangat diminati. Pada artikel ini, kami akan memberi tahu Anda cara mengintegrasikan analisis kode sumber ke platform cloud CI dengan alat yang sudah tersedia di PVS-Studio. Sebagai contoh, kami akan menggunakan layanan Travis CI.

Gambar 1


Mengapa kita mempertimbangkan awan pihak ketiga dan tidak membuat awan kita sendiri? Ada beberapa alasan, yang utama adalah bahwa implementasi SaaS merupakan prosedur yang cukup mahal dan sulit. Sebenarnya, itu adalah tugas yang sederhana dan sepele untuk langsung mengintegrasikan analisis PVS-Studio ke dalam platform cloud pihak ketiga - apakah itu platform terbuka seperti CircleCI, Travis CI, GitLab, atau solusi perusahaan tertentu yang hanya digunakan di perusahaan tertentu. Oleh karena itu kita dapat mengatakan bahwa PVS-Studio sudah tersedia "di awan". Masalah lain adalah implementasi dan memastikan akses ke infrastruktur 24/7. Ini adalah tugas yang lebih rumit. PVS-Studio tidak akan menyediakan platform cloud sendiri secara langsung untuk menjalankan analisisnya.

Beberapa Informasi tentang Perangkat Lunak Bekas


Travis CI adalah layanan untuk membangun dan menguji perangkat lunak yang menggunakan GitHub sebagai penyimpanan. Travis CI tidak memerlukan perubahan kode pemrograman untuk menggunakan layanan ini. Semua pengaturan dibuat dalam file .travis.yml yang terletak di root repositori.

Kami akan menggunakan LXC (Linux Containers) sebagai proyek uji coba untuk PVS-Studio. Ini adalah sistem virtualisasi di tingkat sistem operasi untuk meluncurkan beberapa instance OS Linux pada satu node.

Proyek ini kecil, tetapi lebih dari cukup untuk demonstrasi. Output dari perintah cloc:
Bahasa
file
kosong
komentar
kode
C
124
11937
6758
50836
C / C ++ Header
65
1117
3676
3774
Catatan: Pengembang LXC sudah menggunakan Travis CI, jadi kami akan mengambil file konfigurasinya sebagai basis dan mengeditnya untuk tujuan kami.

Konfigurasi


Untuk mulai bekerja dengan Travis CI, kami mengikuti tautan dan masuk menggunakan akun GitHub.

Gambar 17

Di jendela yang terbuka, kita harus masuk ke Travis CI.

Gambar 16

Setelah otorisasi, pengalihan ke halaman pembuka "Pertama kali di sini? Mari kita mulai! " , di mana kami menemukan deskripsi singkat apa yang harus dilakukan setelah itu untuk memulai:

  • memungkinkan repositori;
  • tambahkan file .travis.yml di repositori;
  • mulai build pertama.

Gambar 18

Mari kita mulai melakukan tindakan ini.

Untuk menambahkan repositori kami di Travis CI, kami pergi ke pengaturan profil dengan tautan dan tekan "Aktifkan".

Gambar 19

Setelah diklik, sebuah jendela akan terbuka untuk memilih repositori tempat aplikasi Travis CI akan diberi akses.

Catatan: untuk memberikan akses ke repositori, akun Anda harus memiliki hak administrator untuk melakukannya.

Gambar 38

Setelah itu kami memilih repositori yang tepat, konfirmasikan pilihan dengan tombol "Setuju & Instal", dan kami akan diarahkan kembali ke halaman pengaturan profil.

Mari kita tambahkan beberapa variabel yang akan kita gunakan untuk membuat file lisensi penganalisa dan mengirimkan laporannya. Untuk melakukan ini, kita akan pergi ke halaman pengaturan - tombol "Pengaturan" di sebelah kanan repositori yang diperlukan.

Gambar 39

Jendela pengaturan akan terbuka.

Gambar 41

Deskripsi singkat tentang pengaturan;

  • Bagian "Umum" - mengonfigurasi pemicu tugas mulai otomatis;
  • Bagian "Pembatalan Otomatis" memungkinkan untuk mengonfigurasi pembatalan pembuatan otomatis;
  • Bagian “Variabel Lingkungan” memungkinkan untuk mendefinisikan variabel lingkungan yang berisi informasi terbuka dan rahasia, seperti informasi login, kunci ssh;
  • Bagian "Cron Jobs" adalah konfigurasi dari jadwal menjalankan tugas.

Di bagian "Variabel Lingkungan" kita akan membuat variabel PVS_USERNAME dan PVS_KEY yang masing - masing berisi nama pengguna dan kunci lisensi untuk penganalisa statis. Jika Anda tidak memiliki lisensi PVS-Studio permanen, Anda dapat meminta lisensi uji coba .

Gambar 5

Di sini kami akan membuat variabel MAIL_USER dan MAIL_PASSWORD , yang berisi nama pengguna dan kata sandi email, yang akan kami gunakan untuk mengirim laporan.

Gambar 4

Saat menjalankan tugas, Travis CI mengambil instruksi dari file .travis.yml, yang terletak di root repositori.

Dengan menggunakan Travis CI, kita dapat menjalankan analisis statis baik secara langsung pada mesin virtual dan menggunakan wadah yang telah dikonfigurasikan untuk melakukannya. Hasil dari pendekatan ini tidak berbeda satu sama lain. Namun, penggunaan wadah yang sudah dikonfigurasi sebelumnya dapat bermanfaat. Misalnya, jika kami sudah memiliki wadah dengan beberapa lingkungan spesifik, di dalamnya produk perangkat lunak mana yang dibangun dan diuji dan kami tidak ingin mengembalikan lingkungan ini di Travis CI.

Mari kita membuat konfigurasi untuk menjalankan analisa pada mesin virtual.

Untuk membuat dan menguji kami akan menggunakan mesin virtual di Ubuntu Trusty, deskripsinya tersedia di tautan .

Pertama-tama, kami menetapkan bahwa proyek ditulis dalam C dan daftar kompiler yang akan kami gunakan untuk membangun:

language: c compiler: - gcc - clang 

Catatan: jika Anda menentukan lebih dari satu kompiler, tugas akan berjalan secara bersamaan untuk masing-masing kompilator. Baca lebih lanjut di sini .

Sebelum membangun kita perlu menambahkan repositori analyzer, mengatur dependensi dan paket tambahan:

 before_install: - sudo add-apt-repository ppa:ubuntu-lxc/daily -y - 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 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev linux-libc-dev pvs-studio libio-socket-ssl-perl libnet-ssleay-perl sendemail ca-certificates 

Sebelum kami membangun sebuah proyek, kami perlu menyiapkan lingkungan Anda:

 script: - ./coccinelle/run-coccinelle.sh -i - git diff --exit-code - export CFLAGS="-Wall -Werror" - export LDFLAGS="-pthread -lpthread" - ./autogen.sh - rm -Rf build - mkdir build - cd build - ../configure --enable-tests --with-distro=unknown 

Selanjutnya, kita perlu membuat file lisensi dan mulai menganalisis proyek.

Kemudian kita membuat file lisensi untuk penganalisa dengan perintah pertama. Data untuk variabel $ PVS_USERNAME dan $ PVS_KEY diambil dari pengaturan proyek.

 - pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic 

Dengan perintah selanjutnya, kita mulai melacak pembangunan proyek.

 - pvs-studio-analyzer trace -- make -j4 

Setelah itu kami menjalankan analisis statis.
Catatan: saat menggunakan lisensi percobaan, Anda perlu menentukan parameter --disableLicenseExpirationCheck .
  - pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic -o PVS-Studio-${CC}.log --disableLicenseExpirationCheck 

File dengan hasil analisis dikonversi ke dalam laporan-html dengan perintah terakhir.

 - plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html 

Karena TravisCI tidak mengizinkan Anda mengubah format pemberitahuan email, pada langkah terakhir kami akan menggunakan paket sendemail untuk mengirim laporan:

 - 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 

Berikut ini adalah teks lengkap file konfigurasi untuk menjalankan alat analisa pada mesin virtual:

 language: c compiler: - gcc - clang before_install: - sudo add-apt-repository ppa:ubuntu-lxc/daily -y - 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 coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev linux-libc-dev pvs-studio libio-socket-ssl-perl libnet-ssleay-perl sendemail ca-certificates script: - ./coccinelle/run-coccinelle.sh -i - git diff --exit-code - export CFLAGS="-Wall -Werror" - export LDFLAGS="-pthread -lpthread" - ./autogen.sh - rm -Rf build - mkdir build - cd build - ../configure --enable-tests --with-distro=unknown - pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic - pvs-studio-analyzer trace -- make -j4 - 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 

Untuk menjalankan PVS-Studio dalam sebuah wadah, mari kita pra-membuatnya menggunakan Dockerfile berikut:

 FROM docker.io/ubuntu:trusty ENV CFLAGS="-Wall -Werror" ENV LDFLAGS="-pthread -lpthread" RUN apt-get update && apt-get install -y software-properties-common wget \ && wget -q -O - https://files.viva64.com/etc/pubkey.txt | sudo apt-key add - \ && wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list \ && apt-get update \ && apt-get install -yqq coccinelle parallel libapparmor-dev libcap-dev libseccomp-dev python3-dev python3-setuptools docbook2x libgnutls-dev libselinux1-dev linux-libc-dev pvs-studio git libtool autotools-dev automake pkg-config clang make libio-socket-ssl-perl libnet-ssleay-perl sendemail ca-certificates \ && rm -rf /var/lib/apt/lists/* 

Dalam hal ini, file konfigurasi mungkin terlihat seperti ini:

 before_install: - docker pull docker.io/oandreev/lxc env: - CC=gcc - CC=clang script: - docker run --rm --cap-add SYS_PTRACE -v $(pwd):/pvs -w /pvs docker.io/oandreev/lxc /bin/bash -c " ./coccinelle/run-coccinelle.sh -i && git diff --exit-code && ./autogen.sh && mkdir build && cd build && ../configure CC=$CC && pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic && pvs-studio-analyzer trace -- make -j4 && pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic -o PVS-Studio-$CC.log --disableLicenseExpirationCheck && plog-converter -t html -o PVS-Studio-$CC.html PVS-Studio-$CC.log && 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" 

Seperti yang Anda lihat, dalam hal ini kami tidak melakukan apa pun di dalam mesin virtual, dan semua tindakan untuk membangun dan menguji proyek berlangsung di dalam wadah.

Catatan : saat Anda memulai wadah, Anda perlu menentukan parameter --cap-add SYS_PTRACE atau --security-opt seccomp: unconfined , karena panggilan sistem ptrace digunakan untuk pelacakan kompiler.

Selanjutnya, kita memuat file konfigurasi di root repositori dan melihat bahwa Travis CI telah diberitahu tentang perubahan dalam proyek dan secara otomatis memulai pembangunan.

Detail kemajuan pembuatan dan penganalisa dapat dilihat di konsol.

Gambar 2

Setelah tes selesai, kami akan menerima dua email: yang pertama - dengan hasil analisis statis untuk membangun proyek menggunakan gcc, dan yang kedua - untuk dentang masing-masing.

Secara singkat tentang hasil pemeriksaan


Secara umum, proyek ini cukup bersih, analis hanya mengeluarkan 24 peringatan dengan kepastian tinggi dan 46 kepastian sedang. Mari kita lihat beberapa pemberitahuan menarik:

Kondisi redundan di if


V590 Pertimbangkan untuk memeriksa ekspresi 'ret! = (- 1) && ret == 1'. Ekspresi berlebihan atau mengandung kesalahan cetak. lampirkan.c 107

 #define EOF -1 static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) { .... while (getline(&line, &line_bufsz, proc_file) != -1) { ret = sscanf(line, "CapBnd: %llx", &info->capability_mask); if (ret != EOF && ret == 1) // <= { found = true; break; } } .... } 

Jika ret == 1 , jelas tidak sama dengan -1 (EOF). Cek berlebihan, ret! = EOF dapat dihapus.

Dua peringatan serupa telah dikeluarkan:

  • V590 Pertimbangkan untuk memeriksa ekspresi 'ret! = (- 1) && ret == 1'. Ekspresi berlebihan atau mengandung kesalahan cetak. attach.c 579
  • V590 Pertimbangkan untuk memeriksa ekspresi 'ret! = (- 1) && ret == 1'. Ekspresi berlebihan atau mengandung kesalahan cetak. attach.c 583

Hilangnya bit tinggi


V784 Ukuran bit mask kurang dari ukuran operan pertama. Ini akan menyebabkan hilangnya bit yang lebih tinggi. conf.c 1879

 struct mount_opt { char *name; int clear; int flag; }; static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t size) { struct mount_opt *mo; /* If opt is found in mount_opt, set or clear flags. * Otherwise append it to data. */ for (mo = &mount_opt[0]; mo->name != NULL; mo++) { if (strncmp(opt, mo->name, strlen(mo->name)) == 0) { if (mo->clear) { *flags &= ~mo->flag; // <= } else { *flags |= mo->flag; } return; } } .... } 

Di Linux, long adalah variabel integer 64-bit, flag-> adalah variabel integer 32-bit. Penggunaan flag> sebagai bit mask akan menyebabkan hilangnya 32 bit tinggi. Topeng bit secara implisit dilemparkan ke variabel integer 64-bit setelah inversi bitwise. Bit tinggi dari topeng ini bisa hilang.

Saya akan menunjukkannya menggunakan contoh:

 unsigned long long x; unsigned y; .... x &= ~y; 

Gambar 3


Ini versi kode yang benar:

 *flags &= ~(unsigned long)(mo->flag); 

Penganalisa mengeluarkan peringatan serupa lainnya:

  • V784 Ukuran bit mask kurang dari ukuran operan pertama. Ini akan menyebabkan hilangnya bit yang lebih tinggi. conf.c 1933

Loop mencurigakan


V612 Suatu 'pengembalian' tanpa syarat dalam satu lingkaran. conf.c 3477

 #define lxc_list_for_each(__iterator, __list) \ for (__iterator = (__list)->next; __iterator != __list; \ __iterator = __iterator->next) static bool verify_start_hooks(struct lxc_conf *conf) { char path[PATH_MAX]; struct lxc_list *it; lxc_list_for_each (it, &conf->hooks[LXCHOOK_START]) { int ret; char *hookname = it->elem; ret = snprintf(path, PATH_MAX, "%s%s", conf->rootfs.path ? conf->rootfs.mount : "", hookname); if (ret < 0 || ret >= PATH_MAX) return false; ret = access(path, X_OK); if (ret < 0) { SYSERROR("Start hook \"%s\" not found in container", hookname); return false; } return true; // <= } return true; } 

Loop dimulai dan terputus pada iterasi pertama. Ini mungkin dibuat secara sengaja, tetapi dalam kasus ini loop bisa dihilangkan.

Indeks Array di luar Batas


V557 Array underrun dimungkinkan. Nilai indeks 'bytes - 1' dapat mencapai -1. network.c 2570

 static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcname, struct lxc_netdev *netdev, pid_t pid, unsigned int hooks_version) { int bytes; char buffer[PATH_MAX] = {0}; .... bytes = lxc_read_nointr(pipefd[0], &buffer, PATH_MAX); if (bytes < 0) { SYSERROR("Failed to read from pipe file descriptor"); close(pipefd[0]); } else { buffer[bytes - 1] = '\0'; } .... } 

Bytes dibaca di buffer dari pipa. Jika terjadi kesalahan, fungsi lxc_read_nointr akan mengembalikan nilai negatif. Jika semua berjalan dengan sukses, terminal nol ditulis oleh elemen terakhir. Namun, jika 0 byte dibaca, indeks akan keluar dari batas buffer, yang mengarah ke perilaku yang tidak ditentukan.

Penganalisa mengeluarkan peringatan serupa lainnya:

  • V557 Array underrun dimungkinkan. Nilai indeks 'bytes - 1' dapat mencapai -1. network.c 2725

Buffer overflow


V576 Format salah. Pertimbangkan untuk memeriksa argumen aktual ketiga dari fungsi 'sscanf'. Berbahaya menggunakan penspesifikasi string tanpa spesifikasi lebar. Buffer overflow dimungkinkan. lxc_unshare.c 205

 static bool lookup_user(const char *oparg, uid_t *uid) { char name[PATH_MAX]; .... if (sscanf(oparg, "%u", uid) < 1) { /* not a uid -- perhaps a username */ if (sscanf(oparg, "%s", name) < 1) // <= { free(buf); return false; } .... } .... } 

Dalam hal ini, penggunaan sscanf bisa berbahaya, karena jika buffer oparq lebih besar dari buffer nama , indeks akan keluar batas ketika membentuk nama buffer.

Kesimpulan


Seperti yang kita lihat, ini adalah tugas yang cukup sederhana untuk mengonfigurasi pemeriksaan penganalisa kode statis di cloud. Untuk ini, kita hanya perlu menambahkan satu file dalam repositori dan menghabiskan sedikit waktu menyiapkan sistem CI. Akibatnya, kami akan mendapatkan alat untuk mendeteksi masalah pada tahap penulisan kode. Alat ini memungkinkan kami mencegah bug dari mencapai tahap pengujian berikutnya, di mana perbaikannya akan membutuhkan banyak waktu dan upaya.

Tentu saja, penggunaan PVS-Studio dengan platform cloud tidak hanya terbatas pada Travis CI. Mirip dengan metode yang dijelaskan dalam artikel, dengan perbedaan kecil, analisis PVS-Studio dapat diintegrasikan ke dalam solusi cloud CI populer lainnya, seperti CircleCI, GitLab, dll.

Tautan yang bermanfaat


  • Untuk informasi tambahan tentang menjalankan PVS-Studio di Linux dan MacOS, ikuti tautan .
  • Anda juga dapat membaca tentang membuat, mengatur dan menggunakan wadah dengan penganalisis kode statis PVS-Studio yang diinstal melalui tautan .
  • Dokumentasi TravisCI .

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


All Articles