Ini adalah artikel kedua tentang menggunakan analisa statis PVS-Studio dalam sistem cloud CI, dan kali ini kita akan mempertimbangkan platform Azure DevOps - solusi cloud CI \ CD dari Microsoft. Sebagai proyek yang dianalisis kali ini, pertimbangkan ShareX.
Kami membutuhkan tiga komponen. Yang pertama adalah analisa statis PVS-Studio. Yang kedua adalah Azure DevOps, yang dengannya kami akan mengintegrasikan alat analisa. Yang ketiga adalah proyek yang akan kami periksa untuk menunjukkan kemampuan PVS-Studio saat bekerja di cloud. Jadi mari kita mulai.
PVS-Studio adalah penganalisa kode statis untuk mencari kesalahan dan cacat keamanan. Melakukan analisis kode dalam C, C ++, C # dan Java.
Azure DevOps . Platform Azure DevOps mencakup alat-alat seperti Azure Pipeline, Azure Board, Azure Artifacts, dan lainnya untuk mempercepat proses pembuatan perangkat lunak dan meningkatkan kualitasnya.
ShareX adalah aplikasi gratis yang memungkinkan Anda menangkap dan merekam bagian mana pun dari layar. Proyek ini ditulis dalam C # dan bagus untuk menunjukkan bagaimana menjalankan analisa statis. Kode sumber untuk proyek 
tersedia di GitHub .
Output dari perintah cloc untuk proyek ShareX:
Dengan kata lain, proyek ini kecil, tetapi cukup memadai untuk menunjukkan karya PVS-Studio dalam hubungannya dengan platform cloud.
Mari mengatur
Untuk memulai di Azure DevOps, klik 
tautan dan klik tombol "Mulai gratis dengan GitHub".
Memberikan akses aplikasi Microsoft ke data akun GitHub.
Untuk menyelesaikan pendaftaran harus membuat akun Microsoft.
Setelah mendaftar, buat proyek:
Selanjutnya, kita perlu pergi ke bagian "Pipeline" - "Builds" dan membuat pipeline Build baru
Untuk pertanyaan di mana kode kami berada, kami akan menjawab - GitHub.
Kami mengotorisasi aplikasi Azure Pipelines dan memilih repositori dengan proyek yang akan kami konfigurasikan peluncuran analisis statis.
Di jendela pemilihan template, pilih "Pipeline pemula".
Kami dapat menjalankan analisis statis kode proyek dalam dua cara: menggunakan agen yang dihosting oleh Microsoft atau di-hosting sendiri
Dalam versi pertama, kami akan menggunakan agen yang dihosting oleh Microsoft. Agen tersebut adalah mesin virtual biasa yang dimulai ketika kami memulai saluran pipa kami dan dihapus setelah tugas selesai. Menggunakan agen semacam itu memungkinkan Anda untuk tidak membuang waktu mendukung dan memperbarui mereka, tetapi memberlakukan beberapa pembatasan, misalnya, ketidakmungkinan menginstal perangkat lunak tambahan yang digunakan untuk membangun proyek.
Ganti konfigurasi default kami dengan yang berikut untuk menggunakan agen yang dihosting oleh Microsoft:
#    #      master- trigger: - master #         # ,   Docker-, #      Windows Server 1803 pool: vmImage: 'win1803' container: microsoft/dotnet-framework:4.7.2-sdk-windowsservercore-1803 steps: #    - task: PowerShell@2 inputs: targetType: 'inline' script: 'Invoke-WebRequest -Uri https://files.viva64.com/PVS-Studio_setup.exe -OutFile PVS-Studio_setup.exe' - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | #      nuget restore .\ShareX.sln #  ,        md .\PVSTestResults #   PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /COMPONENTS=Core #        "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" credentials -u $(PVS_USERNAME) -n $(PVS_KEY) #        html. "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\ShareX.sln -o .\PVSTestResults\ShareX.plog "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t html -o .\PVSTestResults\ .\PVSTestResults\ShareX.plog #    - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults 
Catatan: menurut 
dokumentasi , wadah yang digunakan harus di-cache dalam gambar mesin virtual, tetapi pada saat penulisan artikel ini tidak berfungsi dan wadah diunduh setiap kali tugas dimulai, yang secara negatif mempengaruhi waktu eksekusi.
Simpan pipeline dan buat variabel yang akan digunakan untuk membuat file lisensi. Untuk melakukan ini, buka jendela pengeditan pipa dan di sudut kanan atas klik tombol "Variabel".
Tambahkan dua variabel - 
PVS_USERNAME dan 
PVS_KEY , masing-masing berisi nama pengguna dan kunci lisensi. Saat membuat variabel 
PVS_KEY , 
jangan lupa untuk memeriksa item โRahasiakan nilai iniโ untuk mengenkripsi nilai variabel dengan kunci RSA 2048-bit, serta menekan output dari nilai variabel ke log eksekusi tugas.
Kami menyimpan variabel dan mulai pipa dengan tombol "Run".
Opsi kedua untuk menjalankan analisis adalah menggunakan agen yang di-host-sendiri. Agen yang diinangi sendiri adalah agen yang kami konfigurasikan dan kelola sendiri. Agen tersebut memberikan lebih banyak peluang untuk menginstal perangkat lunak, yang diperlukan untuk perakitan dan pengujian produk perangkat lunak kami.
Sebelum menggunakan agen tersebut, mereka harus dikonfigurasi sesuai dengan 
instruksi , dan penganalisa statis harus diinstal dan 
dikonfigurasi .
Untuk memulai tugas pada agen yang di-host-sendiri, kami mengganti konfigurasi default yang diusulkan dengan yang berikut:
 #    #    master- trigger: - master #    self-hosted    'MyPool' pool: 'MyPool' steps: - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | #      nuget restore .\ShareX.sln #  ,        md .\PVSTestResults #        html. "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\ShareX.sln -o .\PVSTestResults\ShareX.plog "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t html -o .\PVSTestResults\ .\PVSTestResults\ShareX.plog #    - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults 
Setelah menyelesaikan tugas, arsip dengan laporan analisis dapat diunduh pada tab Ringkasan, atau kita dapat menggunakan ekstensi 
Kirim Surat , yang memungkinkan Anda mengonfigurasi pengiriman email, atau mencari alat yang lebih nyaman bagi kami di 
Marketplace .
Tentang hasil analisis
Sekarang mari kita lihat beberapa kesalahan yang ditemukan dalam proyek yang diperiksa - ShareX.
Cek berlebihanUntuk melakukan pemanasan, mari kita mulai dengan kelemahan sederhana dalam kode, yaitu dengan pemeriksaan berlebihan:
 private void PbThumbnail_MouseMove(object sender, MouseEventArgs e) { .... IDataObject dataObject = new DataObject(DataFormats.FileDrop, new string[] { Task.Info.FilePath }); if (dataObject != null) { Program.MainForm.AllowDrop = false; dragBoxFromMouseDown = Rectangle.Empty; pbThumbnail.DoDragDrop(dataObject, DragDropEffects.Copy | DragDropEffects.Move); Program.MainForm.AllowDrop = true; } .... } 
Peringatan PVS-Studio : 
V3022 [CWE-571] Ekspresi 'dataObject! = Null' selalu benar. TaskThumbnailPanel.cs 415
Perhatikan memeriksa variabel 
dataObject untuk 
null . Untuk apa dia di sini? 
dataObject tidak bisa 
nol dalam hal ini, karena ini diinisialisasi dengan referensi ke objek yang dibuat. Akibatnya, kami memiliki verifikasi yang berlebihan. Apakah ini penting? Tidak. Tampak ringkas? Tidak. Pemeriksaan ini jelas lebih baik dihapus agar tidak mengacaukan kode.
Mari kita lihat bagian lain dari kode, di mana Anda dapat membuat komentar serupa:
 private static Image GetDIBImage(MemoryStream ms) { .... try { .... return new Bitmap(bmp); .... } finally { if (gcHandle != IntPtr.Zero) { GCHandle.FromIntPtr(gcHandle).Free(); } } .... } private static Image GetImageAlternative() { .... using (MemoryStream ms = dataObject.GetData(format) as MemoryStream) { if (ms != null) { try { Image img = GetDIBImage(ms); if (img != null) { return img; } } catch (Exception e) { DebugHelper.WriteException(e); } } } .... } 
Peringatan PVS-Studio : 
V3022 [CWE-571] Ekspresi 'img! = Null' selalu benar. ClipboardHelpers.cs 289
Metode 
GetImageAlternative lagi memeriksa bahwa variabel 
img tidak 
nol segera setelah membuat instance baru dari kelas 
Bitmap . Perbedaan dari contoh sebelumnya di sini adalah bahwa untuk menginisialisasi variabel 
img , kita tidak menggunakan konstruktor, tetapi metode 
GetDIBImage . Pembuat kode mengasumsikan bahwa pengecualian dapat terjadi dalam metode ini, tetapi menyatakan hanya 
mencoba dan 
akhirnya memblokir, menghilangkan 
tangkapan . Oleh karena itu, jika pengecualian terjadi, metode pemanggilan 
- GetImageAlternative - tidak akan menerima referensi ke objek bertipe 
Bitmap, tetapi akan dipaksa untuk menangani pengecualian dalam 
blok tangkapnya sendiri. Dalam kasus ini, variabel 
img tidak akan diinisialisasi, dan utas eksekusi bahkan tidak akan mencapai centang 
img! = Null , tetapi akan segera jatuh ke dalam 
blok tangkap . Oleh karena itu, penganalisa memang menunjukkan validasi berlebihan.
Pertimbangkan contoh peringatan berikut dengan kode 
V3022 :
 private void btnCopyLink_Click(object sender, EventArgs e) { .... if (lvClipboardFormats.SelectedItems.Count == 0) { url = lvClipboardFormats.Items[0].SubItems[1].Text; } else if (lvClipboardFormats.SelectedItems.Count > 0) { url = lvClipboardFormats.SelectedItems[0].SubItems[1].Text; } .... } 
Peringatan PVS-Studio : 
V3022 [CWE-571] Ekspresi 'lvClipboardFormats.SelectedItems.Count> 0' selalu benar. AfterUploadForm.cs 155
Mari kita lihat ekspresi kondisional kedua. Di sana kami memeriksa nilai properti 
Hitung baca-saja. Properti ini menunjukkan jumlah elemen dalam instance koleksi 
SelectedItems . Kondisi terpenuhi hanya jika properti 
Hitung lebih besar dari nol. Semuanya akan baik-baik saja, tetapi itu hanya di luar 
jika pernyataan bahwa 
Hitungan sudah diperiksa. Turunan dari koleksi 
SelectedItems tidak dapat memiliki jumlah elemen kurang dari nol, oleh karena itu, 
Count mengambil nilai yang sama dengan nol atau lebih besar dari nol. Karena kami telah melakukan pemeriksaan pada pernyataan pertama 
jika pernyataan bahwa 
Count adalah nol, dan ternyata salah, tidak masuk akal untuk menulis cek lain pada cabang lain bahwa 
Count lebih besar dari nol.
Contoh terakhir dari nomor kesalahan 
V3022 adalah fragmen kode berikut:
 private void DrawCursorGraphics(Graphics g) { .... int cursorOffsetX = 10, cursorOffsetY = 10, itemGap = 10, itemCount = 0; Size totalSize = Size.Empty; int magnifierPosition = 0; Bitmap magnifier = null; if (Options.ShowMagnifier) { if (itemCount > 0) totalSize.Height += itemGap; .... } .... } 
Peringatan PVS-Studio : Ekspresi V3022 'itemCount> 0' selalu salah. RegionCaptureForm.cs 1100.
Penganalisis memperhatikan bahwa 
itemCount kondisi 
> 0 akan selalu salah, karena sedikit deklarasi yang lebih tinggi dilakukan dan variabel 
itemCount diatur ke nol pada saat yang sama. Hingga kondisi tersebut, variabel ini tidak digunakan di mana pun dan tidak berubah, oleh karena itu, penganalisa membuat kesimpulan yang benar tentang ekspresi kondisional, yang nilainya selalu salah.
Baiklah, sekarang mari kita lihat sesuatu yang sangat menarik.
Cara terbaik untuk memahami bug adalah dengan memvisualisasikan bug.Sepertinya kami menemukan kesalahan yang agak menarik di tempat ini:
 public static void Pixelate(Bitmap bmp, int pixelSize) { .... float r = 0, g = 0, b = 0, a = 0; float weightedCount = 0; for (int y2 = y; y2 < yLimit; y2++) { for (int x2 = x; x2 < xLimit; x2++) { ColorBgra color = unsafeBitmap.GetPixel(x2, y2); float pixelWeight = color.Alpha / 255; r += color.Red * pixelWeight; g += color.Green * pixelWeight; b += color.Blue * pixelWeight; a += color.Alpha * pixelWeight; weightedCount += pixelWeight; } } .... ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount)); .... } 
Saya tidak ingin segera mengungkapkan semua kartu dan menunjukkan apa yang ditemukan oleh analis kami di sini, jadi mari kita tunda sejenak untuk saat ini.
Dengan nama metode, mudah untuk menebak apa yang dilakukannya - Anda mengirimkan gambar atau potongan gambar sebagai input, dan melakukan pixelasinya. Kode metode ini cukup panjang, jadi kami tidak akan memberikannya di sini secara keseluruhan, tetapi cukup mencoba menjelaskan algoritmanya dan menjelaskan bug apa yang ditemukan oleh PVS-Studio di sini.
Metode ini menerima dua parameter sebagai input: objek bertipe 
Bitmap dan nilai bertipe 
int , yang menunjukkan ukuran piksel. Algoritma operasi cukup sederhana:
1) Kami memecah fragmen gambar yang diterima pada input ke dalam kotak dengan sisi yang sama dengan ukuran pixelation. Sebagai contoh, jika kita memiliki ukuran pixelisasi 15, maka kita mendapatkan persegi yang berisi 15x15 = 225 piksel.
2) Selanjutnya, kita berkeliling setiap piksel dalam kuadrat ini dan mengakumulasikan nilai-nilai bidang 
Merah , 
Hijau , 
Biru dan 
Alpha menjadi variabel perantara, dan sebelumnya mengalikan nilai warna yang sesuai dan nilai kanal alfa dengan variabel 
pixelWeight , diperoleh dengan membagi nilai 
Alpha dengan 255 (variabel 
Alpha memiliki ketik 
byte ). Juga, ketika melintasi piksel, kami menjumlahkan nilai yang direkam dalam 
pixelWeight ke dalam variabel yang disebut 
weightedCount .
Cuplikan kode yang melakukan langkah-langkah di atas adalah sebagai berikut:
 ColorBgra color = unsafeBitmap.GetPixel(x2, y2); float pixelWeight = color.Alpha / 255; r += color.Red * pixelWeight; g += color.Green * pixelWeight; b += color.Blue * pixelWeight; a += color.Alpha * pixelWeight; weightedCount += pixelWeight; 
Omong-omong, perhatikan bahwa jika nilai variabel 
Alpha adalah nol, maka 
pixelWeight tidak akan menambahkan nilai apa pun ke variabel 
WeightedCount untuk piksel ini. Kami akan membutuhkan ini di masa depan.
3) Setelah kami melewati semua piksel dalam kuadrat saat ini, kami dapat membuat warna "rata-rata" umum untuk kuadrat ini. Kode yang melakukan tindakan ini adalah sebagai berikut:
 ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount)); 
4) Sekarang kita memiliki warna akhir dan 
menuliskannya ke variabel 
averageColor , kita dapat kembali berkeliling setiap pixel di dalam kotak dan memberikan nilai dari 
averageColor .
5) Kami kembali ke langkah 2 selama masih ada kotak mentah.
Sekali lagi, kami mencatat bahwa variabel 
weightedCount tidak sama dengan jumlah semua piksel yang dikuadratkan. Misalnya, jika piksel yang benar-benar transparan muncul di gambar (nilainya nol pada saluran alfa), maka variabel 
pixelWeight akan menjadi nol untuk piksel ini ( 
0/255 = 0), oleh karena itu, piksel ini tidak akan memberikan kontribusi apa pun pada pembentukan nilai variabel 
weightedCount . Ini logis - tidak masuk akal untuk memperhitungkan warna-warna piksel yang benar-benar transparan.
Segalanya tampak cukup masuk akal - pixelation harus bekerja dengan benar. Dan itu bekerja dengan baik. Itu tidak untuk gambar png yang memiliki piksel dengan nilai di saluran alpha kurang dari 255 dan tidak sama dengan nol. Perhatikan gambar pixelated di bawah ini:
Apakah Anda melihat pikselasi? Dan kita tidak. Nah, sekarang mari kita ungkapkan intrik kecil ini dan jelaskan di mana sebenarnya bug itu tersembunyi dalam metode ini. Kesalahan merayap ke baris untuk menghitung nilai variabel 
pixelWeight :
 float pixelWeight = color.Alpha / 255; 
Faktanya adalah bahwa pembuat kode, menyatakan variabel 
pixelWeight sebagai float , menyiratkan bahwa ketika membagi bidang 
Alpha dengan 255, selain nol dan satu, angka fraksional harus diperoleh. Di sinilah masalahnya, karena variabel 
Alpha adalah tipe 
byte , dan ketika kita membaginya dengan 255, kita mendapatkan nilai integer, dan hanya kemudian akan secara implisit dilemparkan ke 
float , oleh karena itu, bagian fraksional hilang.
Ketidakmampuan untuk pixelize gambar PNG yang memiliki tingkat transparansi mudah untuk dijelaskan. Karena nilai kanal alfa untuk piksel ini terletak pada rentang 0 <Alpha <255, saat membagi variabel 
Alpha dengan 255, kami akan selalu mendapatkan 0. Oleh karena itu, nilai 
pikselBerat , 
r , 
g , 
b , 
a , variabel Variabel 
berbobot juga selalu akan menjadi nol. Hasilnya, rata-rata warna rata-rata kami akan dengan nilai nol di semua saluran: merah - 0, biru - 0, hijau - 0, alfa - 0. Mengisi kotak dengan warna ini, kami tidak mengubah warna asli piksel, karena rata-rata 
Warna benar-benar transparan . Untuk memperbaiki kesalahan ini, Anda hanya perlu secara eksplisit melemparkan bidang 
Alpha ke tipe 
float . Baris kode yang diperbaiki mungkin terlihat seperti ini:
 float pixelWeight = (float)color.Alpha / 255; 
Dan inilah saatnya mengutip pesan yang diberikan PVS-Studio ke kode yang salah:
Peringatan PVS-Studio : 
V3041 [CWE-682] Ekspresi ini secara implisit dilemparkan dari tipe 'int' ke tipe 'float'. Pertimbangkan untuk menggunakan pemeran tipe eksplisit untuk menghindari hilangnya bagian fraksional. Contoh: double A = (double) (X) / Y; ImageHelpers.cs 1119.
Dan sebagai perbandingan, kami memberikan tangkapan layar gambar yang benar-benar pixelated yang diperoleh pada versi tetap aplikasi:
Potensi NullReferenceException public static bool AddMetadata(Image img, int id, string text) { .... pi.Value = bytesText; if (pi != null) { img.SetPropertyItem(pi); return true; } .... } 
Peringatan PVS-Studio: V3095 [CWE-476] Objek 'pi' digunakan sebelum diverifikasi terhadap null. Periksa baris: 801, 803. ImageHelpers.cs 801
Fragmen kode ini menunjukkan bahwa pembuatnya mengharapkan variabel 
pi menjadi 
nol , itulah sebabnya pemeriksaan 
pi! = Null dilakukan sebelum memanggil metode 
SetPropertyItem . Sungguh aneh bahwa sebelum pemeriksaan ini, array byte ditugaskan ke properti 
pi.Value , karena jika 
pi nol , pengecualian tipe 
NullReferenceException akan dibuang.
Situasi serupa terlihat di tempat lain:
 private static void Task_TaskCompleted(WorkerTask task) { .... task.KeepImage = false; if (task != null) { if (task.RequestSettingUpdate) { Program.MainForm.UpdateCheckStates(); } .... } .... } 
Peringatan PVS-Studio: V3095 [CWE-476] Objek 'tugas' digunakan sebelum diverifikasi terhadap nol. Periksa baris: 268, 270. TaskManager.cs 268
PVS-Studio menemukan kesalahan serupa lainnya. Artinya masih sama, jadi tidak ada kebutuhan besar untuk memberikan fragmen kode, kami membatasi diri pada pesan penganalisa.
Peringatan PVS-Studio: V3095 [CWE-476] Objek 'Config.PhotobucketAccountInfo' digunakan sebelum diverifikasi dengan null. Periksa baris: 216, 219. UploadersConfigForm.cs 216
Nilai pengembalian yang samaSepotong kode yang mencurigakan ditemukan dalam metode 
EvalWindows dari kelas 
WindowsList , yang mengembalikan 
true dalam keadaan apa pun:
 public class WindowsList { public List<IntPtr> IgnoreWindows { get; set; } .... public WindowsList() { IgnoreWindows = new List<IntPtr>(); } public WindowsList(IntPtr ignoreWindow) : this() { IgnoreWindows.Add(ignoreWindow); } .... private bool EvalWindows(IntPtr hWnd, IntPtr lParam) { if (IgnoreWindows.Any(window => hWnd == window)) { return true;  
Peringatan PVS-Studio: V3009 Aneh bahwa metode ini selalu mengembalikan nilai yang sama dan 'benar'. WindowsList.cs 82
Tampaknya logis bahwa jika sebuah pointer dengan nilai yang sama dengan 
hWnd ditemukan dalam daftar dengan nama 
IgnoreWindows , maka metode tersebut harus mengembalikan 
false .
Daftar 
IgnoreWindows dapat diisi baik dengan memanggil konstruktor 
WindowsList (IntPtr ignWindow) , atau langsung melalui akses ke properti, karena bersifat publik. Salah satu cara atau yang lain, menurut Visual Studio, pada saat ini dalam kode daftar ini tidak diisi dengan cara apa pun. Ini adalah tempat aneh lain dari metode ini.
Panggilan tidak aman ke penangan acara protected void OnNewsLoaded() { if (NewsLoaded != null) { NewsLoaded(this, EventArgs.Empty); } } 
Peringatan PVS-Studio: V3083 [CWE-367] Doa yang tidak aman dari acara 'NewsLoaded', NullReferenceException dimungkinkan. Pertimbangkan menugaskan acara ke variabel lokal sebelum menjalankannya. NewsListControl.cs 111
Dalam kasus ini, situasi tidak menyenangkan berikut ini dapat terjadi: setelah memeriksa variabel 
NewsLoaded untuk ketidaksetaraan 
nol , metode yang memproses acara tersebut dapat 
dibatalkan berlangganan, misalnya, di utas lain, dan ketika kita masuk ke tubuh 
pernyataan conditional 
if , variabel 
NewsLoaded sudah 
akan menjadi sama dengan 
nol . Mencoba memanggil pelanggan pada acara 
NewsLoaded yang 
nol akan melempar 
NullReferenceException . Jauh lebih aman menggunakan operator kondisional nol dan menulis ulang kode di atas sebagai berikut:
 protected void OnNewsLoaded() { NewsLoaded?.Invoke(this, EventArgs.Empty); } 
Alat analisis menunjukkan 
68 tempat lebih mirip. Kami tidak akan menjelaskannya di sini - pola panggilan acara di dalamnya serupa.
Kembalikan null dari ToStringBelum lama ini, dari 
artikel rekan yang 
menarik, saya menemukan bahwa Microsoft tidak merekomendasikan pengembalian 
nol dari metode 
ToString yang ditimpa. PVS-Studio sangat menyadari hal ini:
 public override string ToString() { lock (loggerLock) { if (sbMessages != null && sbMessages.Length > 0) { return sbMessages.ToString(); } return null; } } 
Peringatan PVS-Studio: V3108 Tidak disarankan untuk mengembalikan 'null' dari metode 'ToSting ()'. Logger.cs 167
Mengapa pantas jika tidak menggunakan? public SeafileCheckAccInfoResponse GetAccountInfo() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "account/info/?format=json"); .... } 
PVS-Studio Warning: V3008 Variabel 'url' diberi nilai dua kali berturut-turut. Mungkin ini sebuah kesalahan. Periksa baris: 197, 196. Seafile.cs 197
Seperti yang Anda lihat dari contoh, ketika mendeklarasikan variabel 
url , ia diberi nilai yang dikembalikan dari metode 
FixPrefix . Di baris berikutnya, kami "menggiling" nilai yang dihasilkan, bahkan tanpa menggunakannya di mana pun. Kami mendapatkan sesuatu yang mirip dengan "kode mati" - itu berfungsi, tidak mempengaruhi hasil akhir. Kesalahan ini kemungkinan besar merupakan hasil dari copy-paste, karena fragmen kode seperti itu ditemukan di 9 metode lainnya.
Sebagai contoh, kami memberikan dua metode dengan baris pertama yang serupa:
 public bool CheckAuthToken() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "auth/ping/?format=json"); .... } .... public bool CheckAPIURL() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "ping/?format=json"); .... } 
Total
Seperti yang dapat kita lihat, kerumitan pengaturan verifikasi otomatis oleh alat analisis tidak bergantung pada sistem CI yang dipilih - hanya dalam 15 menit dan beberapa klik mouse, kami mengatur verifikasi kode proyek kami dengan alat analisis statis.
Sebagai kesimpulan, kami sarankan Anda 
mengunduh dan mencoba penganalisa pada proyek Anda.

Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Oleg Andreev, Ilya Gainulin. 
PVS-Studio di Awan: Azure DevOps .