PVS-Studio pergi ke awan - meluncurkan analisis tentang Travis CI

Saat ini, sistem cloud CI adalah layanan yang sangat populer. Pada artikel ini kami akan memberitahu caranya, menggunakan alat yang ada yang tersedia di PVS-Studio, Anda dapat mengintegrasikan analisis kode sumber dengan platform cloud CI, menggunakan layanan Travis CI sebagai contoh.

Gambar 1


Mengapa kita melihat awan pihak ketiga dan tidak membuat awan kita sendiri? Ada beberapa alasan, dan yang utama adalah bahwa SaaS adalah prosedur yang agak mahal dan sulit. Bahkan, mengintegrasikan analisis PVS-Studio secara langsung dengan platform cloud pihak ketiga (apakah itu platform terbuka seperti CircleCI, Travis CI, GitLab, atau beberapa solusi perusahaan khusus yang digunakan hanya dalam satu perusahaan tertentu) adalah tugas yang cukup sederhana dan sepele. Artinya, kita dapat mengatakan bahwa PVS-Studio sudah tersedia "di awan" . Masalah yang sama sekali berbeda adalah organisasi dan penyediaan infrastruktur untuk pekerjaan tersebut 24/7. Ini adalah tugas yang sama sekali berbeda, dan PVS-Studio tidak memiliki rencana untuk menyediakan platform cloud sendiri secara langsung untuk menjalankan analisis di atasnya.

Informasi tentang perangkat lunak yang digunakan


Travis CI adalah layanan untuk membangun dan menguji perangkat lunak yang menggunakan GitHub sebagai penyimpanan. Travis CI tidak perlu mengubah kode program untuk menggunakan layanan ini, semua pengaturan terjadi dalam file .travis.yml yang terletak di root repositori.

Kami akan menggunakan LXC (Linux Containers) sebagai proyek uji untuk pengujian dengan PVS-Studio. Ini adalah sistem virtualisasi tingkat sistem operasi untuk menjalankan beberapa contoh sistem operasi Linux pada satu node.

Proyek ini kecil, tetapi lebih dari cukup untuk ditunjukkan. 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 konfigurasi mereka sebagai basis dan mengeditnya untuk tujuan kami.

Kustomisasi


Untuk memulai dengan Travis CI, ikuti tautan dan autentikasi menggunakan akun GitHub.

Gambar 17

Di jendela yang terbuka, Anda perlu mengesahkan Travis CI.

Gambar 16

Setelah otorisasi, pengalihan ke halaman pembuka “Pertama kali di sini? Mari kita mulai! " , yang menjelaskan secara singkat apa yang perlu dilakukan selanjutnya untuk memulai:

  • mengaktifkan repositori;
  • tambahkan file .travis.yml ke repositori;
  • jalankan build pertama.

Gambar 18

Kami akan mulai melaksanakan poin-poin ini.

Untuk menambahkan repositori kami ke Travis CI, buka pengaturan profil melalui tautan dan klik tombol "Activate".

Gambar 19

Setelah mengklik, sebuah jendela terbuka dengan pilihan repositori yang dapat diakses oleh aplikasi Travis CI.
Catatan: untuk memberikan akses ke repositori, akun harus memiliki hak administrator untuk itu.

Gambar 38

Kami memilih repositori yang diinginkan, mengonfirmasi pilihan dengan tombol "Setuju & Instal", dan kami akan diarahkan kembali ke halaman pengaturan profil.

Segera buat variabel yang akan kita gunakan untuk membuat file lisensi penganalisa dan mengirimkan laporannya. Untuk melakukan ini, buka halaman pengaturan - tombol "Pengaturan" di sebelah kanan repositori yang diinginkan.

Gambar 39

Jendela pengaturan akan terbuka.

Gambar 41

Deskripsi singkat pengaturan:

  • Bagian "Umum" - pengaturan pemicu untuk tugas autorun;
  • Bagian "Pembatalan Otomatis" - memungkinkan Anda untuk mengkonfigurasi rakitan membatalkan otomatis;
  • Bagian "Variabel Lingkungan" - memungkinkan Anda untuk menentukan variabel lingkungan yang berisi informasi publik dan rahasia, seperti kredensial, kunci ssh;
  • Bagian “Pekerjaan Cron” - mengatur jadwal peluncuran tugas.

Di bagian "Variabel Lingkungan" kami 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, maka Anda dapat meminta lisensi uji coba .

Gambar 5

Segera buat variabel MAIL_USER dan MAIL_PASSWORD yang berisi nama pengguna dan kata sandi kotak surat, yang akan kami gunakan untuk mengirim laporan.

Gambar 4

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

Menggunakan Travis CI, kita dapat menjalankan analisis statis secara langsung di mesin virtual, atau menggunakan wadah yang telah dikonfigurasi untuk ini. Hasil pendekatan ini tidak berbeda satu sama lain, tetapi menggunakan wadah pra-konfigurasi bisa berguna, misalnya, jika kita sudah memiliki wadah dengan beberapa lingkungan spesifik di mana produk perangkat lunak dibangun dan diuji, dan tidak ada keinginan untuk memulihkan lingkungan ini di Travis CI .

Mari kita membuat konfigurasi untuk menjalankan analisa di mesin virtual.

Untuk perakitan dan pengujian, kami akan menggunakan mesin virtual berbasis Ubuntu Trusty, deskripsinya dapat ditemukan di sini .

Pertama-tama, kami menunjukkan bahwa proyek ini ditulis dalam C dan kami daftar kompiler yang akan kami gunakan untuk perakitan:

language: c compiler: - gcc - clang 

Catatan : jika Anda menentukan lebih dari satu kompiler, tugas akan diluncurkan secara paralel untuk masing-masingnya. Baca lebih lanjut di dokumentasi .

Sebelum memulai pembuatan, kita perlu menambahkan repositori analyzer, menginstal 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 membangun proyek, Anda perlu menyiapkan lingkungan:

 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 dengan lisensi dan menjalankan analisis proyek.

Perintah pertama membuat file lisensi untuk penganalisa. Data untuk variabel $ PVS_USERNAME dan $ PVS_KEY diambil dari pengaturan proyek.

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

Perintah berikut memulai jejak perakitan proyek:

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

Setelah kami memulai analisis statis.
Catatan: saat menggunakan lisensi percobaan, Anda harus menentukan parameter --disableLicenseExpirationCheck .

  - pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic -o PVS-Studio-${CC}.log –-disableLicenseExpirationCheck 

Dengan perintah terakhir, file hasil analisis dikonversi ke laporan html.

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

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

 - 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 

Teks lengkap file konfigurasi untuk menjalankan alat analisa dalam 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 analisis statis dalam sebuah wadah, pertama-tama buatlah 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 tentu saja semua tindakan untuk merakit dan menguji proyek berlangsung di dalam wadah.

Catatan : saat memulai wadah, Anda harus menentukan --cap-add SYS_PTRACE atau --security-opt seccomp: parameter tidak dikonfigurasikan , karena panggilan sistem ptrace digunakan untuk mengkompilasi jejak.

Kami memuat file konfigurasi ke dalam root repositori dan melihat bahwa Travis CI menerima pemberitahuan tentang kehadiran perubahan dalam proyek dan secara otomatis memulai perakitan.

Informasi terperinci tentang kemajuan perakitan dan verifikasi penganalisa dapat dilihat di konsol.

Gambar 2

Setelah tes selesai, kami akan menerima 2 surat dalam surat: satu dengan hasil analisis statis untuk membangun proyek menggunakan gcc, dan yang kedua dengan dentang, masing-masing.

Secara singkat tentang hasil tes


Secara umum, proyek ini cukup bersih, analis hanya mengeluarkan 24 peringatan kritis dan 46 rata-rata. Untuk mendemonstrasikan pekerjaan, pertimbangkan 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 , maka jelas tidak sama dengan -1 (EOF). Validasi berlebihan, ret! = EOF dapat dihapus.

Dua peringatan lagi 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. Menggunakan flag mo-> sebagai bitmask akan menghasilkan hilangnya 32 bit paling signifikan. Casting implisit bitmask ke variabel integer 64-bit setelah inversi bitwise dilakukan. Bit tinggi topeng ini akan menjadi nol.

Tunjukkan dengan contoh:

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

Gambar 3


Kode yang benar adalah:

 *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

Siklus yang 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; } 

Siklus dimulai dan pada iterasi pertama ia terputus. Mungkin ini memang dimaksudkan, tapi kemudian siklusnya bisa dihilangkan.

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 dari pipa ke buffer. Jika terjadi kesalahan, fungsi lxc_read_nointr akan mengembalikan nilai negatif. Jika semuanya berjalan dengan baik, maka terminal nol ditulis sebagai elemen terakhir. Namun, jika 0 byte dibaca, maka buffer akan keluar dari batas, yang mengarah pada 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; } .... } .... } 

Menggunakan sscanf dalam hal ini bisa berbahaya, karena jika panjang buffer oparq lebih besar dari panjang buffer nama , maka ia akan pergi ke luar negeri ketika buffer nama terbentuk.

Kesimpulan


Seperti yang kita lihat, pengaturan pemeriksaan kode statis dari proyek kami di cloud adalah tugas yang cukup sederhana. Untuk melakukan ini, Anda hanya perlu menambahkan satu file ke repositori dan menghabiskan waktu minimum menyiapkan sistem CI. Sebagai hasilnya, kami mendapatkan alat yang memungkinkan Anda mengidentifikasi kode bermasalah pada tahap penulisan, dan tidak memungkinkan kesalahan untuk sampai ke tahap pengujian berikutnya, di mana koreksi mereka akan membutuhkan lebih banyak waktu dan sumber daya.

Tentu saja, menggunakan PVS-Studio dalam hubungannya dengan platform cloud tidak terbatas pada Travis CI. Dengan analogi dengan metode yang dijelaskan dalam artikel, dengan perbedaan minimal, analisis PVS-Studio dapat diintegrasikan dengan solusi CI berbasis cloud populer lainnya, seperti CircleCI, GitLab, dll.

Tautan yang bermanfaat


  • Informasi tambahan tentang peluncuran PVS-Studio di Linux dan MacOS dapat ditemukan di sini .
  • Anda dapat membaca tentang membuat, mengonfigurasi, dan menggunakan wadah dengan penganalisis statis PVS-Studio yang diinstal di sini .
  • Dokumentasi TravisCI .



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Oleg Andreev. PVS-Studio di Awan -Lari Analisis Travis CI

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


All Articles