Elektronische Kunstbibliotheken von fast guter Qualität

Unsere Aufmerksamkeit wurde auf das Electronic Arts Repository auf GitHub gelenkt. Es ist sehr klein und von 23 Projekten waren wir nur an einigen C ++ - Bibliotheken interessiert: EASTL, EAStdC, EABase, EAThread, EATest, EAMain und EAAssert. Die Projekte waren auch sehr klein (ungefähr 10 Dateien), so dass wir Fehler nur in der „größten“ von 20 Dateien fanden: D Aber wir fanden auch interessante! Während des Schreibens des Artikels diskutierten meine Kollegen und ich auch intensiv über die Spiele und die Strategie von EA: D.

Bild 1


Einführung


Electronic Arts (EA) ist ein amerikanisches Unternehmen, das Videospiele vertreibt. Auf der GitHub-Website hat sie ein kleines Repository und mehrere C ++ - Projekte. Dies sind C ++ - Bibliotheken: EASTL, EAStdC, EABase, EAThread, EATest, EAMain und EAAssert. Sie sind sehr klein und wir haben interessante Fehler bei der Verwendung des PVS-Studio- Analysators nur in der "größten" von ihnen gefunden - EAStdC (20 Dateien). Bei solchen Volumes ist es schwierig, über die Qualität des gesamten Codes zu sprechen. Bewerten Sie einfach 5 Warnungen und entscheiden Sie selbst.

Warnung 1


V524 Es ist seltsam, dass der Körper der Funktion '>>' dem Körper der Funktion '<<' vollständig entspricht. 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;} .... } 

Beim Überladen von Schichtoperatoren machte der Programmierer einen Tippfehler in einem von ihnen und verwirrte die Operatoren << und >>. Dies ist höchstwahrscheinlich das Ergebnis der Copy-Paste-Programmierung.

Warnung 2


V557 Array-Überlauf ist möglich. Der Wert des Index 'nFormatLength' könnte 16 erreichen. 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; .... } 

Das Array spans [spanIndex] .mFormat besteht aus 16 Elementen, d.h. Das letzte gültige Element hat einen Index von 15 . Jetzt wird der OVprintfCore- Funktionscode so geschrieben, dass, wenn der nFormatLength- Index den maximal möglichen Index - 15 hat , ein Inkrement von bis zu 16 auftritt. Weiter in der switch-Anweisung ist es möglich, über die Grenze des Arrays hinauszugehen.

Dieses Codefragment wurde an zwei weitere Stellen kopiert:

  • V557 Array-Überlauf ist möglich. Der Wert des Index 'nFormatLength' könnte 16 erreichen. EASprintfOrdered.cpp 614
  • V557 Array-Überlauf ist möglich. Der Wert des Index 'nFormatLength' könnte 16 erreichen. EASprintfOrdered.cpp 977

Warnung 3


V560 Ein Teil des bedingten Ausdrucks ist immer wahr: (Ergebnis> = 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; } .... } 

Das Bedingungsergebnis > = 0 ist immer wahr, da sich die Ergebnisvariable an keiner Stelle in der Schleife ändert. Der Code sieht sehr verdächtig aus und höchstwahrscheinlich liegt ein Fehler in diesem Code vor.

Dieses Codefragment wurde an zwei weitere Stellen kopiert:

  • V560 Ein Teil des bedingten Ausdrucks ist immer wahr: (Ergebnis> = 0). EASprintfOrdered.cpp 852
  • V560 Ein Teil des bedingten Ausdrucks ist immer wahr: (Ergebnis> = 0). EASprintfOrdered.cpp 1215

Warnung 4


V1009 Überprüfen Sie die Array-Initialisierung. Nur das erste Element wird explizit initialisiert. Die restlichen Elemente werden mit Nullen initialisiert. EASprintfOrdered.cpp 151

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

Dies ist möglicherweise kein Fehler, aber Entwickler sollten gewarnt werden, dass nur das erste Element des spanArgOrder- Arrays mit dem Wert -1 initialisiert wird und alle anderen den Wert 0 haben.

Dieses Codefragment wurde an zwei weitere Stellen kopiert:

  • V1009 Überprüfen Sie die Array-Initialisierung. Nur das erste Element wird explizit initialisiert. Die restlichen Elemente werden mit Nullen initialisiert. EASprintfOrdered.cpp 518
  • V1009 Überprüfen Sie die Array-Initialisierung. Nur das erste Element wird explizit initialisiert. Die restlichen Elemente werden mit Nullen initialisiert. EASprintfOrdered.cpp 881

Warnung 5


V728 Eine übermäßige Überprüfung kann vereinfacht werden. Das '(A &&! B) || (! A && B) 'Ausdruck entspricht dem Ausdruck' 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(); } .... } 

Dieses Codefragment wurde der Einfachheit halber formatiert, aber im Original ist es eine sehr lange Bedingung, die schwer zu lesen ist. Eine andere Sache ist, wenn wir den bedingten Ausdruck vereinfachen, wie der Analysator empfiehlt:

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

Der Code ist viel kürzer geworden, was das Verständnis der Logik des bedingten Ausdrucks erheblich vereinfacht hat.

Fazit


Wie Sie vielleicht bemerkt haben, werden die meisten verdächtigen Warnungen an drei Stellen und in derselben Datei dupliziert. Die Vervielfältigung von Code ist eine sehr schlechte Entwicklungspraxis erschwert die Codeunterstützung. Und wenn in einem solchen Code ein Fehler auftritt, nimmt die Stabilität des Programms aufgrund der Verteilung von Fehlern im gesamten Code stark ab.

Hoffen wir, dass noch etwas Interessantes veröffentlicht wird und wir wieder in dieses Repository zurückkehren :). In der Zwischenzeit schlage ich diejenigen vor, die PVS-Studio herunterladen und versuchen möchten, ihre eigenen Projekte zu überprüfen.



Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Svyatoslav Razmyslov. Fast perfekte Bibliotheken von Electronic Arts .

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


All Articles