Como o PVS-Studio se mostrou mais atento do que três programadores e meio

Como o PVS-Studio mostrou mais de três programas e meio

O PVS-Studio, como outros analisadores de código estático, geralmente produz falsos positivos. Mas não se apresse em considerar respostas estranhas falsas. Esta é uma pequena história sobre como o PVS-Studio novamente se mostrou mais atento a várias pessoas.

O usuário escreveu para nos apoiar, alegando que o analisador produz imediatamente quatro falsos positivos por linha de código. Uma carta escrita em apoio chegou inicialmente a Yevgeny Ryzhkov, que, depois de ler com fluência e sem perceber comentários anômalos, enviou-a imediatamente ao desenvolvedor principal Svyatoslav Razmyslov. Eugene não examinou o código, portanto seria justo contá-lo apenas para metade do programador :).


Svyatoslav leu a carta e duvidou que o analisador pudesse estar tão errado. Portanto, ele veio a mim para uma consulta. Svyatoslav tinha a esperança de que meu olho estivesse fixo e notarei algo que me diz por que o analisador emitiu todas essas mensagens estranhas. Infelizmente, só confirmei que as mensagens são realmente muito estranhas e não deveriam ser. No entanto, qual foi o motivo da ocorrência deles, eu não percebi. Foi decidido abrir a tarefa no rastreador de bugs e começar a entender o que estava errado.

E somente quando Svyatoslav começou a fazer exemplos sintéticos para descrever em detalhes o problema no rastreador de bugs, o insight surgiu sobre ele. Vamos agora ver se você consegue encontrar rapidamente o motivo pelo qual o analisador exibe quatro mensagens.

Aqui está o texto da carta, publicado com permissão do autor. E uma figura explicativa anexada à carta.

Os avisos da V560 aqui são todos falsos. Executando com a versão mais recente do PVS-Studio para uso pessoal. Basicamente, a instrução "SE" está correta. O externo é feito para a velocidade - os internos ainda são necessários e nem sempre são verdadeiros ou falsos.

Uma carta


Agora, caro leitor, é hora de se testar! Vê o erro?

Sua hora de estar atento. E o unicórnio vai esperar um pouco.

Espera unicórnio


Após a parte introdutória do artigo, muitos provavelmente encontraram um erro. Quando configurado para encontrar um erro, ele está localizado. É muito mais difícil perceber um erro depois de ler a carta, onde é chamada de "falsos positivos" :).

Agora, uma explicação para quem tem preguiça de procurar um bug. Considere a condição novamente:

if (!((ch >= 0x0FF10) && (ch <= 0x0FF19)) || ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) || ((ch >= 0x0FF41) && (ch <= 0x0FF5A))) 

O autor do código planejava verificar se o caractere não se enquadra em nenhum dos três intervalos.

O erro é que o operador NOT lógico (!) Aplica-se apenas à primeira subexpressão.

Se a condição for atendida:

 !((ch >= 0x0FF10) && (ch <= 0x0FF19)) 

então a avaliação da expressão é interrompida de acordo com a avaliação de curto-circuito . Se a condição não for atendida, o valor da variável ch estará no intervalo [0xFF10..0xFF19]. Consequentemente, quatro comparações adicionais não fazem sentido. Todos eles serão falsos ou verdadeiros.

Mais uma vez Veja, se ch está no intervalo [0xFF10..0xFF19] e o cálculo continua, então:

  • ch> = 0x0FF21 - sempre falso
  • ch <= 0x0FF3A - sempre verdadeiro
  • ch> = 0x0FF41 - sempre falso
  • ch <= 0x0FF5A - sempre verdadeiro

É sobre isso que o analisador PVS-Studio alerta.

Portanto, o analisador estático mostrou-se mais atento do que o usuário e dois programadores e meio da nossa equipe.

Para corrigir a situação, você precisa adicionar colchetes adicionais:

 if (!(((ch >= 0x0FF10) && (ch <= 0x0FF19)) || ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) || ((ch >= 0x0FF41) && (ch <= 0x0FF5A)))) 

Ou reescreva a condição:

 if (((ch < 0x0FF10) || (ch > 0x0FF19)) && ((ch < 0x0FF21) || (ch > 0x0FF3A)) && ((ch < 0x0FF41) || (ch > 0x0FF5A))) 

No entanto, não posso recomendar o uso de nenhuma dessas opções. Eu escreveria isso para simplificar a leitura do código:

 const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19) // 0..9 || (ch >= 0x0FF21 && ch <= 0x0FF3A) // A..Z || (ch >= 0x0FF41 && ch <= 0x0FF5A); // a..z if (!isLetterOrDigit) 

Observe que eu removi alguns dos suportes. Como acabamos de ver, um grande número de colchetes não ajudou a evitar um erro. Os colchetes devem facilitar a leitura do código, não mais complicado. Os programadores lembram bem que a prioridade das comparações = <, => é maior que a do operador &&. Portanto, colchetes não são necessários aqui. Mas se você perguntar qual prioridade é && ou ||, muitos ficarão confusos. Portanto, para especificar a sequência de cálculos &&, || suportes são melhores para colocar.

Por que é melhor escrever || no começo, descrevi no artigo “ A questão principal da programação, refatoração e tudo isso ” (consulte o capítulo: Alinhe o mesmo tipo de código com uma “tabela”).

Obrigado a todos pela atenção. Faça o download e comece a usar o PVS-Studio . Isso ajudará a identificar muitos erros e vulnerabilidades em potencial nos estágios iniciais.



Se você deseja compartilhar este artigo com um público que fala inglês, use o link para a tradução: Andrey Karpov. Como o PVS-Studio se mostrou mais atento do que três programadores e meio .

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


All Articles