Normalmente, não escrevemos notas sobre o lançamento da nova versão do analisador PVS-Studio. No entanto, o novo lançamento inclui muitas mudanças interessantes relacionadas à análise dos códigos C e C ++, sobre as quais gostaríamos de informar nossos usuários.
Java em breve
Para ser sincero, as inovações mais recentes e interessantes do PVS-Studio ainda estão ocultas. Quero dizer suporte no analisador de linguagem Java. Ainda não existe uma versão beta pública do PVS-Studio for Java, mas ela estará disponível muito em breve. Se você deseja participar de seus testes, pode escrever para nós em
suporte (escolha: Quero um analisador para Java).
Novos diagnósticos para C e C ++
Na nova versão, ficamos um pouco empolgados e adicionamos imediatamente 15 diagnósticos de uso geral para C e C ++ (V1021-V1035). Em uma versão menor, muitos diagnósticos nunca foram adicionados de uma só vez. Mais detalhes sobre cada diagnóstico podem ser encontrados na
documentação . Na minha opinião, os mais interessantes entre os novos diagnósticos são:
- V1026. A variável é incrementada no loop. Um comportamento indefinido ocorrerá em caso de estouro de número inteiro assinado.
- V1033. A variável é declarada como automática em C. Seu tipo padrão é int.
Diagnóstico
V1026 criado com base na
discussão no fórum linux.org.ru. O programador reclamou de uma falha no compilador GCC 8, mas, como se viu depois, a falha foi no código incorreto, levando a um comportamento indefinido. Vamos olhar para este caso.
Nota Na discussão original, a variável
s é do tipo
const char * s . Além disso, na plataforma de destino, o tipo de
caractere não é assinado. Portanto, para maior clareza, escrevi imediatamente no exemplo que o tipo do ponteiro é
const unsigned char * .
int foo(const unsigned char *s) { int r = 0; while(*s) { r += ((r * 20891 + *s *200) | *s ^ 4 | *s ^ 3) ^ (r >> 1); s++; } return r & 0x7fffffff; }
O compilador não gera código para o operador AND bit a bit (&). Por esse motivo, a função retorna valores negativos, embora isso não deva acontecer com a intenção do programador.
O desenvolvedor acredita que isso é uma falha no compilador. Mas o programador que escreveu esse código está realmente errado. A função não funciona corretamente devido ao fato de que um comportamento indefinido ocorre nela.
O compilador vê que uma certa quantidade é considerada na variável
r . Estouro da variável
r não deve ocorrer. Caso contrário, esse é um comportamento indefinido que o compilador não deve considerar e levar em consideração. Portanto, o compilador acredita que, como o valor da variável
r após o final do ciclo não pode ser negativo, a operação
r & 0x7fffffff para redefinir o bit de sinal é supérflua e o compilador simplesmente retorna o valor da variável
r da função.
O Diagnostics V1026 foi desenvolvido apenas para detectar esses erros. Para corrigir o código, basta ler o hash usando uma variável não assinada. Versão corrigida do código:
int foo(const unsigned char *s) { unsigned r = 0; while(*s) { r += ((r * 20891 + *s *200) | *s ^ 4 | *s ^ 3) ^ (r >> 1); s++; } return (int)(r & 0x7fffffff); }
Agora, vejamos outro diagnóstico
V1033 . É interessante que a causa de possíveis erros foi a nova palavra
- chave
auto , que apareceu no C ++ 11. E não é a inovação da própria linguagem C ++ 11 que é culpada, mas as nuances do plano psicológico :). Eu vou explicar agora Dê uma olhada neste código:
float d = 3.14f; int i = 1; auto sum = d + i;
Vê isso como um erro? Pense nisso. Aqui está uma figura para não ler mais o texto.
Adivinha o que poderia estar errado? Caso contrário, aqui estão algumas informações mais interessantes. A variável
sum será 4, não 4,14. Porque
Agora o leitor dirá que foi um enigma desonesto! O problema é que isso não é C ++, mas C.
Acontece que um projeto usa C ++ e o bom e velho C. O programador se acostuma a usar
auto em C ++ e acidentalmente pode usar essa palavra em C. Mas isso significa algo mais:
autoDefine uma variável local como tendo uma vida útil local. A palavra-chave auto usa a seguinte sintaxe: [auto] data-definition;
Como o tempo de vida local é o padrão para variáveis locais, a palavra-chave automática é extremamente raramente usada.Acontece que a variável
sum é do tipo
int e é por isso que seu valor será 4.
Embora o erro possa parecer exótico, de fato, em um projeto que usa uma mistura de arquivos C e C ++, é muito fácil de executar. Consequentemente, ao analisar arquivos C, o PVS-Studio alerta para essas construções suspeitas.
Outras inovações
Foi adicionada a capacidade
de verificar projetos para o sistema de
compilação Waf .
Continuamos
a desenvolver o analisador para sistemas embarcados. Esta versão adiciona suporte à verificação do projeto para o compilador GNU Arm Embedded Toolchain, Arm Embedded GCC.
Ao analisar projetos para o compilador Visual C ++ (cl.exe, projetos vcxproj para Visual Studio / Standalone), o relatório do analisador agora armazena o registro nos caminhos dos arquivos verificados. O refinamento lateral parece mais fácil do que realmente é. Ao pré-processar arquivos, o compilador cl.exe estraga o caso em nomes de arquivos. E você precisa restaurá-los de volta ao analisador.
Foi adicionada a capacidade de usar arquivos pvsconfig do CLMonitor / Standalone no Windows.
Um modo de análise incremental foi adicionado ao módulo pvs-studio-analzyer / CMake. O módulo PVS-Studio CMake agora pode ser usado no Windows para projetos usando o compilador Visual C ++ (cl.exe).
Adicionado suporte para análise incremental para projetos do .NET Core / .NET Standard Visual Studio.
Sitelinks
- PVS-Studio. Histórico de versões .
- Andrey Karpov. O comportamento indefinido está mais próximo do que você pensa .
- Will Dietz, Peng Li, John Regehr e Vikram Adve. Noções básicas sobre estouro de número inteiro em C / C ++ .
- Egor Bredikhin. Desenvolvimento de um novo analisador estático: PVS-Studio Java .