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 .