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.
Agora, caro leitor, é hora de se testar! Vê o erro?
Sua hora de estar atento. E o unicórnio vai esperar um pouco.
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)
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 .