Ini adalah cerita pendek tentang bagaimana PVS-Studio membantu kami menemukan kesalahan dalam kode sumber perpustakaan yang digunakan dalam PVS-Studio. Dan itu bukan kesalahan teoretis tetapi kesalahan aktual - kesalahan muncul dalam praktik saat menggunakan perpustakaan di penganalisa.
Dalam PVS-Studio_Cmd (serta beberapa utilitas lain) kami menggunakan perpustakaan khusus untuk parsing argumen baris perintah - CommandLine.
Hari ini saya mendukung mode baru dalam PVS-Studio_Cmd dan kebetulan saya harus menggunakan perpustakaan ini untuk parsing argumen baris perintah. Saat menulis kode, saya juga men-debug-nya karena saya harus bekerja dengan API yang tidak dikenal.
Jadi, kode tersebut ditulis, dikompilasi, dieksekusi dan ...
Eksekusi kode masuk ke dalam pustaka tempat pengecualian tipe
NullReferenceException terjadi. Tidak begitu jelas dari samping - Saya tidak memberikan referensi nol ke dalam metode ini.
Yang pasti, saya melihat komentar pada metode callee. Hampir tidak mungkin bahwa mereka menggambarkan kondisi terjadinya pengecualian dari tipe
NullReferenceException (seperti yang tampak bagi saya biasanya pengecualian dari tipe ini tidak disediakan untuk).
Tidak ada informasi tentang
NullReferenceException di komentar ke metode (yang, bagaimanapun, diharapkan).
Untuk melihat apa yang menyebabkan pengecualian (dan di mana itu terjadi), saya memutuskan untuk mengunduh kode sumber proyek, membangunnya dan menambahkan referensi ke versi debug perpustakaan ke penganalisis. Kode sumber proyek
tersedia di GitHub . Kami membutuhkan versi 1.9.71 perpustakaan. Ini adalah yang digunakan dalam analisa sekarang.
Saya mengunduh versi kode sumber yang sesuai, membangun perpustakaan, menambahkan referensi ke perpustakaan debug ke penganalisa, menjalankan kode dan melihat:
Jadi, tempat pengecualian terjadi jelas -
helpInfo memiliki nilai
nol , yang menyebabkan pengecualian tipe
NullReferenceException saat mengakses properti
Kiri .
Saya mulai memikirkannya. Baru-baru ini, PVS-Studio untuk C # telah ditingkatkan dengan baik dalam berbagai aspek, termasuk pencarian referensi referensi yang berpotensi nol. Secara khusus, analisis antar-prosedur ditingkatkan dalam beberapa cara. Itu sebabnya saya langsung tertarik untuk memeriksa kode sumber untuk memahami jika PVS-Studio dapat menemukan kesalahan yang sedang dibahas.
Saya memeriksa kode sumber dan di antara peringatan lain saya melihat persis apa yang saya harapkan.
Peringatan PVS-Studio :
V3080 Kemungkinan ada null dereference di dalam metode di 'helpInfo.Left'. Pertimbangkan untuk memeriksa argumen 2: helpInfo. Parser.cs 405
Ya, ini dia! Itulah yang kita butuhkan. Mari kita lihat lebih detail kode sumbernya.
private bool DoParseArgumentsVerbs( string[] args, object options, ref object verbInstance) { var verbs = ReflectionHelper.RetrievePropertyList<VerbOptionAttribute>(options); var helpInfo = ReflectionHelper.RetrieveMethod<HelpVerbOptionAttribute>(options); if (args.Length == 0) { if (helpInfo != null || _settings.HelpWriter != null) { DisplayHelpVerbText(options, helpInfo, null);
Penganalisis mengeluarkan peringatan untuk memanggil metode
DisplayHelpVerbText dan memperingatkan tentang argumen kedua -
helpInfo . Perhatikan bahwa metode ini terletak di cabang pernyataan
if . Ekspresi bersyarat tersusun sedemikian rupa sehingga cabang saat itu dapat dieksekusi pada nilai variabel berikutnya:
- helpInfo == null ;
- _settings.HelpWriter! = null ;
Mari kita lihat isi metode
DisplayHelpVerbText :
private void DisplayHelpVerbText( object options, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb) { string helpText; if (verb == null) { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, null, out helpText); } else { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, verb, out helpText); } if (_settings.HelpWriter != null) { _settings.HelpWriter.Write(helpText); } }
Karena
kata kerja == null (lihat pemanggilan metode), kami tertarik pada cabang selanjutnya dari pernyataan
if . Meskipun situasinya mirip dengan cabang
lain , mari kita pertimbangkan cabang
kemudian karena dalam kasus khusus kami eksekusi melewatinya. Ingat bahwa
helpInfo mungkin
nol .
Sekarang mari kita lihat isi
HelpVerbOptionAttribute . Metode
InvokeMethod . Sebenarnya, Anda sudah melihatnya pada tangkapan layar di atas:
internal static void InvokeMethod( object target, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb, out string text) { text = null; var method = helpInfo.Left; if (!CheckMethodSignature(method)) { throw new MemberAccessException( SR.MemberAccessException_BadSignatureForHelpVerbOptionAttribute .FormatInvariant(method.Name)); } text = (string)method.Invoke(target, new object[] { verb }); }
helpInfo.Left disebut tanpa syarat, sedangkan
helpInfo mungkin
nol . Penganalisa memperingatkan tentang hal itu, dan itulah yang terjadi.
KesimpulanSangat menyenangkan bahwa kami berhasil menemukan kesalahan dalam kode sumber perpustakaan yang digunakan dalam PVS-Studio dengan bantuan PVS-Studio. Saya pikir ini adalah semacam jawaban untuk pertanyaan "Apakah PVS-Studio menemukan kesalahan dalam kode sumber PVS-Studio?". :) Penganalisa dapat menemukan kesalahan tidak hanya dalam kode PVS-Studio tetapi juga dalam kode perpustakaan yang digunakan.
Akhirnya, saya sarankan Anda
mengunduh penganalisa dan mencoba memeriksa proyek Anda - bagaimana jika Anda dapat menemukan sesuatu yang menarik di sana juga?