
Foi planejado que, tendo escrito o artigo "É uma pena as opiniões sobre analisadores de código estático", falaremos e calmamente deixaremos o assunto de lado. Mas, inesperadamente, este artigo causou uma resposta tempestuosa. Infelizmente, a discussão deu errado e agora faremos uma segunda tentativa para explicar nossa visão da situação.
Anedota-analogia
Então, tudo começou com o artigo " É uma pena as opiniões sobre analisadores de código estático ". Começou a ser discutido ativamente em alguns recursos e essa discussão é muito semelhante à seguinte anedota antiga.
Compramos uma motosserra japonesa para alguns lenhadores siberianos rudes.Um para uma história. As pessoas olharam o código:
Os lenhadores se reuniram em um círculo e decidiram testá-lo.
Eles a trouxeram, deram-lhe uma árvore.
"Zíper", disse o serrote japonês.
"Que merda ..." - disseram os lenhadores.
Eles deslizaram para ela uma árvore mais grossa. "Vzh-zh-zhik!" - disse a serra.
"Uau, merda!" - disseram os lenhadores.
Eles colocaram um cedro espesso nela. "VZH-ZH-ZH-ZH-ZH-ZH-ZHIK !!!" - disse a serra.
"Uau, porra !!" - disseram os lenhadores.
Eles deslizaram para ela um pedaço de ferro. "CRACK!" - disse a serra.
"Sim, foda-se !!!" - Stern lenhadores siberianos disseram em repreensão! E saíram para cortar a mata com machados ...
if (A[0] == 0)
{
X = Y;
if (A[0] == 0)
....
}
E começaram a inventar situações quando isso poderia ser justificado, o que significa que o alerta do analisador PVS-Studio é falso-positivo. O raciocínio foi para o curso sobre a mudança na memória entre duas verificações, decorrente de:
- trabalho de fluxos paralelos;
- manipuladores de sinal / interrupção;
- a variável X é uma referência ao elemento A [0] ;
- hardware, como a execução de operações DMA;
- etc.
E tendo discutido que nem todas as situações que o analisador pode entender, eles partiram para cortar a floresta com machados. Ou seja, encontramos uma desculpa para que possamos continuar não utilizando o analisador de código estático em nosso trabalho.
Nossa visão da situação
Essa abordagem é contraproducente. Uma ferramenta imperfeita pode ser útil e seu uso é economicamente viável.
Sim, qualquer analisador estático gera falsos positivos. E nada pode ser feito sobre isso. No entanto, esse infortúnio é muito exagerado. Na prática, os analisadores estáticos podem ser configurados e usados de várias maneiras para suprimir e trabalhar com falsos positivos (ver 1 , 2 , 3 , 4 ). Além disso, aqui é oportuno relembrar o artigo "Os falsos positivos são nossos inimigos, mas ainda podem ser seus amigos ".
No entanto, mesmo isso não é o principal. Não faz sentido considerar casos especiais de código exótico!Você pode confundir o analisador com um código complexo? Sim você pode. No entanto, para um desses casos, haverá centenas de acionadores de analisador úteis. Muitos erros podem ser encontrados e corrigidos em um estágio muito inicial. E um ou dois alarmes falsos podem ser suprimidos com segurança e não prestar mais atenção a eles.
E mais uma vez o PVS-Studio está certo
Aqui o artigo pode ser terminado. No entanto, alguns podem considerar a seção anterior não considerações racionais, mas tentativas de esconder as fraquezas e deficiências da ferramenta PVS-Studio. Então você tem que continuar.
Considere o código compilado concreto que inclui declarações de variáveis:
void SetSynchronizeVar(int *);
int foo()
{
int flag = 0;
SetSynchronizeVar(&flag);
int X, Y = 1;
if (flag == 0)
{
X = Y;
if (flag == 0)
return 1;
}
return 2;
}
O analisador PVS-Studio emite razoavelmente um aviso: V547 Expression 'flag == 0' é sempre verdadeiro.
E o analisador está absolutamente certo. Se alguém começa a reclamar que uma variável pode mudar em outro encadeamento, em um manipulador de sinal e assim por diante, ele simplesmente não entende as linguagens C e C ++. Você não pode escrever assim.
Para fins de otimização, o compilador tem o direito de descartar a segunda verificação e estará absolutamente certo. Do ponto de vista da linguagem, uma variável não pode mudar. Sua mudança de fundo nada mais é do que um comportamento indefinido.
Para que a verificação permaneça no lugar, a variável deve ser declarada volátil :
void SetSynchronizeVar(volatile int *);
int foo()
{
volatile int flag = 0;
SetSynchronizeVar(&flag);
....
}
O analisador PVS-Studio sabe disso e não emite mais um aviso para tal código .
Aqui, voltamos ao que foi discutido no primeiro artigo . Não tem problema. Mas há críticas ou mal-entendidos por que o analisador tem o direito de emitir um aviso.
Nota para os leitores mais meticulosos
Alguns leitores podem retornar ao exemplo sintético do primeiro artigo:
char get();
int foo(char *p, bool arg)
{
if (p[1] == 1)
{
if (arg)
p[0] = get();
if (p[1] == 1) // Warning
return 1;
}
// ....
return 3;
}
E adicione volátil :
char get();
int foo(volatile char *p, bool arg)
{
if (p[1] == 1)
{
if (arg)
p[0] = get();
if (p[1] == 1) // Warning :-(
return 1;
}
// ....
return 3;
}
Depois disso, é justo dizer que o analisador ainda emite o aviso V547 A expressão 'p [1] == 1' é sempre verdadeira.
Viva, finalmente foi mostrado que o analisador ainda está errado :). Este é um falso positivo!
Como você pode ver, não estamos escondendo nenhuma falha. Ao analisar o fluxo de dados para os elementos do array, esse volátil malfadado se perdeu. A falha já foi encontrada e corrigida. A correção estará disponível na próxima versão do analisador. Não haverá falsos positivos.
Por que esse bug não foi identificado anteriormente? Porque, na verdade, este é novamente um código irreal, que não é encontrado em projetos reais. Na verdade, até agora, não encontramos esse código, embora tenhamos verificado muitos projetos de código aberto .
Por que o código não é realista? Primeiro, na prática, haverá algum tipo de função de temporização ou atraso entre as duas verificações. Em segundo lugar, ninguém em seu perfeito juízo, a menos que seja absolutamente necessário, cria matrizes que consistem em elementos voláteis. Trabalhar com tal matriz é uma queda colossal no desempenho.
Vamos resumir. É fácil criar exemplos em que o analisador falha. Mas do ponto de vista prático, as falhas identificadas praticamente não afetam a qualidade da análise do código e o número de erros reais detectados. Afinal, o código de aplicativos reais é apenas um código que é compreensível pelo analisador e pela pessoa ao mesmo tempo, e não um rebus ou quebra-cabeça. Se o código for um quebra-cabeça, não há tempo para analisadores :).
Obrigado pela atenção.

Links adicionais
- Como implementar um analisador de código estático em um projeto legado e não desmotivar a equipe .
- Configurações adicionais de diagnóstico .
- Características do analisador PVS-Studio pelo exemplo de EFL Core Libraries, 10-15% de falsos positivos .
- Introduza a análise estática em seu processo, em vez de procurar bugs com ela .

Se você deseja compartilhar este artigo com um público que fala inglês, por favor, use o link de tradução: Andrey Karpov. Parte 2: Opiniões Upsetting about Static Analyzers .