Tim kami memberikan dukungan pelanggan yang cepat dan efektif. Permintaan pengguna ditangani sepenuhnya oleh programmer karena klien kami adalah programmer itu sendiri dan mereka sering mengajukan pertanyaan rumit. Hari ini saya akan memberi tahu Anda tentang permintaan baru-baru ini tentang satu kesalahan positif yang bahkan memaksa saya untuk melakukan penyelidikan kecil untuk menyelesaikan masalah.
Kami bekerja keras untuk mengurangi jumlah kesalahan positif yang dihasilkan oleh PVS-Studio menjadi minimum. Sayangnya, penganalisa statis sering tidak dapat memberi tahu kode yang benar dari bug karena mereka tidak memiliki informasi yang cukup. Positif palsu, karenanya, tidak bisa dihindari. Namun, ini bukan masalah karena Anda dapat dengan mudah menyesuaikan penganalisa sehingga
9 dari 10 peringatan akan menunjukkan bug asli.
Meskipun kesalahan positif mungkin tidak tampak masalah besar, kami tidak pernah berhenti melawannya dengan meningkatkan diagnostik kami. Beberapa positif palsu yang mencolok ditangkap oleh tim kami; yang lain dilaporkan oleh klien kami dan pengguna versi gratis.
Salah satu klien kami baru-baru ini mengirimi kami email yang membaca sesuatu seperti ini:
Untuk beberapa alasan, penganalisa mengatakan bahwa pointer tertentu selalu nol, sedangkan tidak. Selain itu, perilakunya pada proyek uji aneh dan tidak stabil: kadang-kadang mengeluarkan peringatan, dan terkadang tidak. Berikut adalah contoh sintetis yang mereproduksi false positive:#include <windows.h> #include <aclapi.h> #include <tchar.h> int main() { PACL pDACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; ::GetNamedSecurityInfo(_T("ObjectName"), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, &pSD); auto test = pDACL == NULL; // V547 Expression 'pDACL == 0' is always true. return 0; }
Tidak sulit menebak bagaimana pengguna kami melihat positif palsu seperti itu. Fungsi
GetNamedSecurityInfo jelas mengubah nilai variabel
pDACL . Apa yang mencegah pengembang membuat handler untuk kasus-kasus sederhana seperti itu? Dan mengapa tidak ada peringatan yang dikeluarkan di setiap sesi? Mungkin itu adalah bug dalam penganalisa itu sendiri, katakanlah, variabel yang tidak diinisialisasi?
Sayangnya ... Mendukung pengguna penganalisa kode statis bukanlah pekerjaan yang mudah, tetapi itu adalah pilihan saya sendiri untuk melakukan itu. Jadi, saya menyingsingkan lengan baju saya dan turun untuk menyelidiki masalahnya.
Saya memulai dengan memeriksa deskripsi fungsi
GetNamedSecurityInfo dan memastikan bahwa panggilannya memang menyiratkan memodifikasi nilai variabel
pDACL . Berikut deskripsi argumen ke-6:
ppdacl
Pointer ke variabel yang menerima pointer ke DACL di deskriptor keamanan yang dikembalikan atau NULL jika deskriptor keamanan tidak memiliki DACL. Pointer yang dikembalikan hanya valid jika Anda menetapkan flag DACL_SECURITY_INFORMATION. Juga, parameter ini bisa NULL jika Anda tidak membutuhkan DACL.
|
Saya tahu bahwa PVS-Studio seharusnya dapat menangani kode sederhana seperti itu tanpa menghasilkan peringatan palsu. Pada saat itu, intuisi saya sudah memberi tahu saya bahwa kasus itu tidak sepele dan bahwa itu akan memakan waktu cukup lama untuk diselesaikan.
Kekhawatiran saya dikonfirmasi ketika saya gagal mereproduksi false positive baik dengan versi alpha kami dari penganalisis atau versi yang diinstal pada komputer pengguna. Apa pun yang saya lakukan, alat analisa tetap diam.
Saya meminta klien untuk mengirim saya
file-i preproses yang dihasilkan untuk program contoh. Dia melakukan itu, dan saya melanjutkan penyelidikan saya.
Penganalisa memang menghasilkan false positive pada file itu segera. Di satu sisi, itu bagus bahwa saya akhirnya berhasil mereproduksi. Di sisi lain, saya punya perasaan yang bisa digambarkan dengan gambar ini:
Kenapa perasaan ini? Anda tahu, saya tahu betul bagaimana alat analisa dan diagnostik
V547 bekerja. Tidak mungkin mereka bisa menghasilkan false positive seperti itu!
OK, mari kita membuat teh dan melanjutkan.
Panggilan ke fungsi
GetNamedSecurityInfo berkembang menjadi kode berikut:
::GetNamedSecurityInfoW(L"ObjectName", SE_FILE_OBJECT, (0x00000004L), 0, 0, &pDACL, 0, &pSD);
Kode ini terlihat sama baik di file-i yang diproses di komputer saya dan file yang dikirim oleh pengguna.
Hmm ... OKE, mari kita lihat deklarasi fungsi ini. Inilah yang saya miliki di file saya:
__declspec(dllimport) DWORD __stdcall GetNamedSecurityInfoW( LPCWSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID * ppsidOwner, PSID * ppsidGroup, PACL * ppDacl, PACL * ppSacl, PSECURITY_DESCRIPTOR * ppSecurityDescriptor );
Semuanya logis dan jelas. Tidak ada yang aneh.
Lalu aku mengintip ke file pengguna dan ...
Apa yang saya lihat di sana bukan milik realitas kita:
__declspec(dllimport) DWORD __stdcall GetNamedSecurityInfoW( LPCWSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, const PSID * ppsidOwner, const PSID * ppsidGroup, const PACL * ppDacl, const PACL * ppSacl, PSECURITY_DESCRIPTOR * ppSecurityDescriptor );
Perhatikan bahwa parameter formal
pp Dacl ditandai sebagai
const .
Wat? WTF? Wat? WTF?Apa itu
const !? Apa yang dilakukannya di sini !?
Yah, setidaknya saya tahu pasti bahwa penganalisa tidak bersalah dan saya dapat mempertahankan kehormatannya.
Argumennya adalah pointer ke objek konstan. Ternyata, dari sudut pandang
penganalisa, fungsi
GetNamedSecurityInfoW tidak dapat memodifikasi objek yang dirujuk oleh pointer. Oleh karena itu, dalam kode berikut:
PACL pDACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; ::GetNamedSecurityInfo(_T("ObjectName"), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, &pSD); auto test = pDACL == NULL;
variabel
pDACL tidak dapat berubah, yang secara tepat diperingatkan oleh penganalisis kami (Ekspresi 'pDACL == 0' selalu benar.).
Oke, sekarang kita tahu apa yang memicu peringatan itu. Yang masih belum kami ketahui adalah dari mana kata kunci
const itu berasal. Itu tidak mungkin ada di sana!
Yah, saya punya satu dugaan, dan itu dikonfirmasi oleh apa yang saya temukan di Internet. Ternyata ada versi lama dari file aclapi.h dengan deskripsi fungsi yang salah. Saya juga menemukan beberapa tautan menarik:
Jadi, pada suatu waktu, ada deskripsi fungsi dalam file aclapi.h (6.0.6002.18005-Windows 6.0):
WINADVAPI DWORD WINAPI GetNamedSecurityInfoW( __in LPWSTR pObjectName, __in SE_OBJECT_TYPE ObjectType, __in SECURITY_INFORMATION SecurityInfo, __out_opt PSID * ppsidOwner, __out_opt PSID * ppsidGroup, __out_opt PACL * ppDacl, __out_opt PACL * ppSacl, __out_opt PSECURITY_DESCRIPTOR * ppSecurityDescriptor );
Kemudian seseorang mengubah jenis parameter
pObjectName tetapi mengacaukan jenis pointer di sepanjang jalan dengan menambahkan kata kunci
const . Dan file aclapi.h (6.1.7601.23418-Windows 7.0) berakhir sebagai berikut:
WINADVAPI DWORD WINAPI GetNamedSecurityInfoW( __in LPCWSTR pObjectName, __in SE_OBJECT_TYPE ObjectType, __in SECURITY_INFORMATION SecurityInfo, __out_opt const PSID * ppsidOwner, __out_opt const PSID * ppsidGroup, __out_opt const PACL * ppDacl, __out_opt const PACL * ppSacl, __out PSECURITY_DESCRIPTOR * ppSecurityDescriptor );
Sekarang sudah jelas bahwa pengguna kami telah bekerja dengan versi aclapi.h yang sangat tidak benar, yang kemudian dia konfirmasikan dalam emailnya. Saya tidak dapat mereproduksi bug karena saya menggunakan versi yang lebih baru.
Ini adalah apa yang tampak seperti deskripsi fungsi tetap dalam file aclapi.h terbaru (6.3.9600.17415-Windows_8.1).
WINADVAPI DWORD WINAPI GetNamedSecurityInfoW( _In_ LPCWSTR pObjectName, _In_ SE_OBJECT_TYPE ObjectType, _In_ SECURITY_INFORMATION SecurityInfo, _Out_opt_ PSID * ppsidOwner, _Out_opt_ PSID * ppsidGroup, _Out_opt_ PACL * ppDacl, _Out_opt_ PACL * ppSacl, _Out_ PSECURITY_DESCRIPTOR * ppSecurityDescriptor );
Jenis argumen
pObjectName masih sama, tetapi
konstanta tambahan hilang. Semua baik lagi, tetapi masih ada header yang rusak digunakan di suatu tempat di luar sana.
Saya menjelaskan semua itu kepada pelanggan, dan dia senang melihat masalah terpecahkan. Selain itu, ia telah menemukan mengapa kesalahan positif tidak terjadi secara teratur:
Saya sekarang ingat bereksperimen dengan toolets pada proyek pengujian ini beberapa waktu lalu. Konfigurasi Debug diatur ke Platform Toolset secara default untuk Visual Studio 2017 - "Visual Studio 2017 (v141)", sedangkan konfigurasi Rilis diatur ke "Visual Studio 2015 - Windows XP (v140_xp)." Saya hanya beralih di antara konfigurasi kemarin, dan peringatan itu akan muncul dan menghilang sesuai.Itu saja. Investigasi telah berakhir. Kami membahas masalah dengan klien dan memutuskan untuk tidak menambahkan kludge ke penganalisa untuk membuatnya dapat menangani bug file header ini. Yang paling penting adalah kita sudah menemukan masalahnya. "Kasus diberhentikan", seperti kata mereka.
KesimpulanPVS-Studio adalah produk perangkat lunak yang kompleks, yang mengumpulkan sejumlah besar informasi dari kode program dan menggunakannya dalam berbagai
teknik analisis . Dalam kasus khusus ini, ternyata menjadi terlalu pintar, berakhir dengan false positive karena deskripsi fungsi yang salah.
Menjadi klien kami, dan Anda dijamin mendapatkan dukungan profesional yang cepat dari saya dan rekan tim saya.