Continuação: insultante para opiniões sobre analisadores de código estático

image1.png


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.

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 ...
Um para uma história. As pessoas olharam o código:



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









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 .



All Articles