Perpustakaan Seni Elektronik yang Kualitasnya Hampir Baik

Perhatian kami tertuju pada repositori Electronic Arts di GitHub. Ini sangat kecil dan dari dua puluh tiga proyek kami hanya tertarik pada beberapa perpustakaan C ++: EASTL, EAStdC, EABase, EAThread, EATest, EAMain dan EAAssert. Proyek juga sangat kecil (sekitar 10 file), jadi kami menemukan kesalahan hanya di "terbesar" dari 20 file: D Tapi kami menemukan yang menarik juga! Saat menulis catatan, saya dan kolega-kolega saya juga dengan bersemangat mendiskusikan permainan EA dan strateginya: D

Gambar 1


Pendahuluan


Electronic Arts (EA) adalah perusahaan Amerika yang mendistribusikan video game. Di situs web GitHub, ia memiliki repositori kecil dan beberapa proyek C ++. Ini adalah pustaka C ++: EASTL, EAStdC, EABase, EAThread, EATest, EAMain dan EAAssert. Mereka sangat kecil dan kami menemukan kesalahan menarik menggunakan penganalisis PVS-Studio hanya di "terbesar" dari mereka - EAStdC (20 file). Dengan volume seperti itu , sulit untuk berbicara tentang kualitas kode secara keseluruhan. Cukup beri peringkat 5 peringatan dan putuskan sendiri.

Peringatan 1


V524 Aneh bahwa tubuh fungsi '>>' sepenuhnya setara dengan tubuh fungsi '<<'. EAFixedPoint.h 287

template <class T, int upShiftInt, int downShiftInt, int upMulInt, int downDivInt> struct FPTemplate { .... FPTemplate operator<<(int numBits) const { return value << numBits; } FPTemplate operator>>(int numBits) const { return value << numBits; } FPTemplate& operator<<=(int numBits) { value <<= numBits; return *this;} FPTemplate& operator>>=(int numBits) { value >>= numBits; return *this;} .... } 

Ketika operator shift overloading, programmer membuat kesalahan ketik di salah satu dari mereka, membingungkan operator << dan >>. Kemungkinan besar, ini adalah hasil dari Copy-Paste-programming.

Peringatan 2


V557 Array overrun dimungkinkan. Nilai indeks 'nFormatLength' bisa mencapai 16. EASprintfOrdered.cpp 246

 static const int kSpanFormatCapacity = 16; struct Span8 { .... char mFormat[kSpanFormatCapacity]; .... }; static int OVprintfCore(....) { .... EA_ASSERT(nFormatLength < kSpanFormatCapacity); if(nFormatLength < kSpanFormatCapacity) spans[spanIndex].mFormat[nFormatLength++] = *p; // <= else return -1; switch(*p) { case 'b': case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': case 'a': case 'A': case 'p': case 'c': case 'C': case 's': case 'S': case 'n': { // Finalize the current span. spans[spanIndex].mpEnd = p + 1; spans[spanIndex].mFormat[nFormatLength] = 0; // <= spans[spanIndex].mFormatChar = *p; if(++spanIndex == kSpanCapacity) break; .... } 

Rentang [spanIndex] .mFormat array terdiri dari 16 elemen, mis. item terakhir yang valid memiliki indeks 15 . Sekarang kode fungsi OVprintfCore ditulis sehingga jika indeks nFormatLength memiliki indeks maksimum yang mungkin - 15 , maka peningkatan hingga 16 akan terjadi. Selanjutnya, dalam pernyataan switch, dimungkinkan untuk melampaui batas array.

Fragmen kode ini disalin ke 2 tempat lain:

  • V557 Array overrun dimungkinkan. Nilai indeks 'nFormatLength' bisa mencapai 16. EASprintfOrdered.cpp 614
  • V557 Array overrun dimungkinkan. Nilai indeks 'nFormatLength' bisa mencapai 16. EASprintfOrdered.cpp 977

Peringatan 3


V560 Bagian dari ekspresi kondisional selalu benar: (hasil> = 0). EASprintfOrdered.cpp 489

 static int OVprintfCore(....) { .... for(result = 1; (result >= 0) && (p < pEnd); ++p) { if(pWriteFunction8(p, 1, pWriteFunctionContext8, kWFSIntermediate) < 0) return -1; nWriteCountSum += result; } .... } 

Hasil kondisi > = 0 selalu benar, karena variabel hasil tidak berubah di loop. Kode ini terlihat sangat mencurigakan dan kemungkinan besar ada kesalahan dalam kode ini.

Fragmen kode ini disalin ke 2 tempat lain:

  • V560 Bagian dari ekspresi kondisional selalu benar: (hasil> = 0). EASprintfOrdered.cpp 852
  • V560 Bagian dari ekspresi kondisional selalu benar: (hasil> = 0). EASprintfOrdered.cpp 1215

Peringatan 4


V1009 Periksa inisialisasi array. Hanya elemen pertama yang diinisialisasi secara eksplisit. Elemen lainnya diinisialisasi dengan nol. EASprintfOrdered.cpp 151

 static int OVprintfCore(....) { .... int spanArgOrder[kArgCapacity] = { -1 }; .... } 

Ini mungkin bukan kesalahan, tetapi pengembang harus diingatkan bahwa hanya elemen pertama array spanArgOrder yang diinisialisasi dengan nilai -1 , dan semua yang lain akan memiliki nilai 0.

Fragmen kode ini disalin ke 2 tempat lain:

  • V1009 Periksa inisialisasi array. Hanya elemen pertama yang diinisialisasi secara eksplisit. Elemen lainnya diinisialisasi dengan nol. EASprintfOrdered.cpp 518
  • V1009 Periksa inisialisasi array. Hanya elemen pertama yang diinisialisasi secara eksplisit. Elemen lainnya diinisialisasi dengan nol. EASprintfOrdered.cpp 881

Peringatan 5


V728 Pemeriksaan berlebihan dapat disederhanakan. The '(A &&! B) || Ekspresi (! A && B) 'sama dengan ekspresi' bool (A)! = Bool (B) '. int128.h 1242

 inline void int128_t::Modulus(....) const { .... bool bDividendNegative = false; bool bDivisorNegative = false; .... if( (bDividendNegative && !bDivisorNegative) || (!bDividendNegative && bDivisorNegative)) { quotient.Negate(); } .... } 

Fragmen kode ini diformat untuk kenyamanan, tetapi dalam bahasa aslinya itu adalah kondisi yang sangat panjang yang sulit dibaca. Hal lain adalah jika kita menyederhanakan ekspresi kondisional, seperti yang disarankan oleh penganalisa:

 if( bDividendNegative != bDivisorNegative) { quotient.Negate(); } 

Kode menjadi lebih pendek, yang sangat menyederhanakan pemahaman logika ekspresi kondisional.

Kesimpulan


Seperti yang mungkin Anda perhatikan, sebagian besar peringatan mencurigakan digandakan di tiga tempat, dan di dalam file yang sama. Duplikasi kode adalah praktik pengembangan yang sangat buruk mempersulit dukungan kode. Dan jika kesalahan terjadi pada kode tersebut, maka stabilitas program menurun tajam karena penyebaran kesalahan di seluruh kode.

Mari berharap sesuatu yang menarik akan dipublikasikan dan kami akan kembali ke repositori ini lagi :). Sementara itu, saya menyarankan mereka yang ingin mengunduh PVS-Studio dan mencoba memeriksa proyek mereka sendiri.



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Svyatoslav Razmyslov. Perpustakaan Hampir Sempurna oleh Seni Elektronik .

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


All Articles