Chamamos nossa atenção para o repositório de Artes Eletrônicas no GitHub. É muito pequeno e, dos vinte e três projetos, estávamos interessados apenas em algumas bibliotecas C ++: EASTL, EAStdC, EABase, EAThread, EATest, EAMain e EAAssert. Os projetos também eram muito pequenos (cerca de 10 arquivos); portanto, encontramos erros apenas no “maior” de 20 arquivos: D Mas também encontramos outros interessantes! Enquanto o artigo estava sendo escrito, meus colegas e eu também discutimos vigorosamente os jogos da EA e sua estratégia: D
1. Introdução
A Electronic Arts (EA) é uma empresa americana que distribui videogames. No site do GitHub, ela possui um pequeno
repositório e vários projetos em C ++. Estas são as bibliotecas C ++: EASTL, EAStdC, EABase, EAThread, EATest, EAMain e EAAssert. Eles são muito pequenos e encontramos erros interessantes usando o analisador
PVS-Studio apenas no "maior" deles -
EAStdC (20 arquivos). Com esses volumes,
é difícil falar sobre a qualidade do código como um todo. Avalie apenas 5 avisos e decida por si mesmo.
Aviso 1
V524 É estranho que o corpo da função '>>' seja totalmente equivalente ao corpo da função '<<'. 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;} .... }
Ao sobrecarregar os operadores de turno, o programador digitou um deles, confundindo os operadores << e >>. Muito provavelmente, este é o resultado da programação de copiar e colar.
Aviso 2
A saturação da matriz V557 é possível. O valor do índice 'nFormatLength' pode chegar a 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;
A
matriz spans [spanIndex] .mFormat consiste em
16 elementos, ou seja, o último item válido tem um índice de
15 . Agora, o
código da função
OVprintfCore é gravado para que, se o índice
nFormatLength tiver o índice máximo possível -
15 , ocorrerá um incremento de até
16 . Além disso, na
instrução switch, é possível ir além do limite da matriz.
Este fragmento de código foi copiado para mais 2 lugares:
- A saturação da matriz V557 é possível. O valor do índice 'nFormatLength' pode chegar a 16. EASprintfOrdered.cpp 614
- A saturação da matriz V557 é possível. O valor do índice 'nFormatLength' pode chegar a 16. EASprintfOrdered.cpp 977
Aviso 3
V560 Uma parte da expressão condicional é sempre verdadeira: (resultado> = 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; } .... }
O
resultado da condição
> = 0 é sempre verdadeiro, porque a variável
resultado não muda em nenhum lugar do loop. O código parece muito suspeito e provavelmente há um erro nesse código.
Este fragmento de código foi copiado para mais 2 lugares:
- V560 Uma parte da expressão condicional é sempre verdadeira: (resultado> = 0). EASprintfOrdered.cpp 852
- V560 Uma parte da expressão condicional é sempre verdadeira: (resultado> = 0). EASprintfOrdered.cpp 1215
Aviso 4
V1009 Verifique a inicialização do array. Somente o primeiro elemento é inicializado explicitamente. Os demais elementos são inicializados com zeros. EASprintfOrdered.cpp 151
static int OVprintfCore(....) { .... int spanArgOrder[kArgCapacity] = { -1 }; .... }
Isso pode não ser um erro, mas os desenvolvedores devem ser avisados de que apenas o primeiro elemento da matriz
spanArgOrder é inicializado com o valor
-1 , e todos os outros terão o valor 0.
Este fragmento de código foi copiado para mais 2 lugares:
- V1009 Verifique a inicialização do array. Somente o primeiro elemento é inicializado explicitamente. Os demais elementos são inicializados com zeros. EASprintfOrdered.cpp 518
- V1009 Verifique a inicialização do array. Somente o primeiro elemento é inicializado explicitamente. Os demais elementos são inicializados com zeros. EASprintfOrdered.cpp 881
Aviso 5
V728 Uma verificação excessiva pode ser simplificada. O '(A &&! B) || (! A && B) 'expressão é equivalente à expressão' 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(); } .... }
Esse fragmento de código foi formatado por conveniência, mas no original é uma condição muito longa e difícil de ler. Outra coisa é se simplificarmos a expressão condicional, como aconselha o analisador:
if( bDividendNegative != bDivisorNegative) { quotient.Negate(); }
O código ficou muito mais curto, o que simplificou bastante o entendimento da lógica da expressão condicional.
Conclusão
Como você deve ter notado, a maioria dos avisos suspeitos é duplicada em três locais e no mesmo arquivo. A duplicação de código é uma prática de desenvolvimento muito ruim, pois complica o suporte ao código. E se ocorrer um erro nesse código, a estabilidade do programa diminuirá acentuadamente devido à propagação de erros por todo o código.
Vamos esperar que outra coisa interessante seja publicada e retornaremos a este repositório novamente :). Enquanto isso, sugiro aqueles que desejam baixar o
PVS-Studio e tentar verificar seus próprios projetos.

Se você deseja compartilhar este artigo com um público que fala inglês, use o link para a tradução: Svyatoslav Razmyslov.
Bibliotecas quase perfeitas pela Electronic Arts .