PVS-Studio, comme d'autres analyseurs de code statique, produit souvent des faux positifs. Mais ne vous précipitez pas pour considérer les réponses étranges comme fausses. Il s'agit d'une courte histoire sur la façon dont PVS-Studio s'est à nouveau révélé plus attentif à plusieurs personnes.
L'utilisateur a écrit pour nous soutenir, affirmant que l'analyseur produit immédiatement quatre faux positifs par ligne de code. La lettre, écrite à l'appui, est d'abord parvenue à Eugène Ryzhkov, qui, l'ayant lu couramment et sans avoir remarqué de commentaires anormaux, l'a immédiatement envoyée au développeur principal Svyatoslav Razmyslov. Eugene n'a pas scruté le code, il serait donc juste de ne le compter que pour la moitié du programmeur :).
Sviatoslav a lu la lettre et a douté que l'analyseur puisse être si grossièrement faux. Par conséquent, il est venu me voir pour une consultation. Svyatoslav espérait que mon œil était fixé et je remarquerai quelque chose qui me dit pourquoi l'analyseur a émis tous ces étranges messages. Malheureusement, j'ai seulement confirmé que les messages sont vraiment très étranges et ne devraient pas l'être. Cependant, quelle était la raison de leur occurrence, je ne pouvais pas le remarquer. Il a été décidé d'ouvrir la tâche dans le bugtracker et de commencer à comprendre ce qui n'allait pas.
Et ce n'est que lorsque Svyatoslav a commencé à faire des exemples synthétiques afin de décrire en détail le problème dans le bugtracker, une idée lui est venue. Voyons maintenant si vous pouvez trouver rapidement la raison pour laquelle l'analyseur affiche 4 messages.
Voici le texte de la lettre, publiée avec la permission de l'auteur. Et une photo explicative jointe à la lettre.
Les avertissements du V560 sont tous faux. Fonctionne avec la version la plus récente de PVS-Studio pour un usage personnel. Fondamentalement, la déclaration «IF» est correcte. Un externe est fait pour la vitesse - les internes sont toujours nécessaires et les non sont toujours vrais ou faux.
Maintenant, cher lecteur, il est temps de vous tester! Tu vois l'erreur?
Votre temps pour être attentif. Et la licorne attendra un peu.
Après la partie introductive de l'article, beaucoup ont probablement trouvé une erreur. Lorsqu'il est configuré pour rechercher une erreur, il est localisé. Il est beaucoup plus difficile de remarquer une erreur après avoir lu la lettre, où elle est appelée "faux positifs" :).
Maintenant une explication pour ceux qui sont trop paresseux pour chercher un bug. Considérez à nouveau la condition:
if (!((ch >= 0x0FF10) && (ch <= 0x0FF19)) || ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) || ((ch >= 0x0FF41) && (ch <= 0x0FF5A)))
L'auteur du code a prévu de vérifier que le personnage ne tombe dans aucune des trois plages.
L'erreur est que l'opérateur NOT logique (!) Ne s'applique qu'à la première sous-expression.
Si la condition est remplie:
!((ch >= 0x0FF10) && (ch <= 0x0FF19))
puis l'évaluation de l'expression est interrompue en fonction de l'
évaluation de court-circuit . Si la condition n'est pas remplie, la valeur de la variable
ch se situe dans la plage [0xFF10..0xFF19]. Par conséquent, quatre autres comparaisons n'ont aucun sens. Tous seront faux ou vrais.
Encore une fois. Voir, si
ch se situe dans la plage
[0xFF10..0xFF19] et le calcul continue, alors:
- ch> = 0x0FF21 - toujours faux
- ch <= 0x0FF3A - toujours vrai
- ch> = 0x0FF41 - toujours faux
- ch <= 0x0FF5A - toujours vrai
C'est ce que l'analyseur PVS-Studio met en garde.
Ainsi, l'analyseur statique s'est avéré être plus attentif que l'utilisateur et deux programmeurs et demi de notre équipe.
Pour corriger la situation, vous devez ajouter des supports supplémentaires:
if (!(((ch >= 0x0FF10) && (ch <= 0x0FF19)) || ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) || ((ch >= 0x0FF41) && (ch <= 0x0FF5A))))
Ou réécrivez la condition:
if (((ch < 0x0FF10) || (ch > 0x0FF19)) && ((ch < 0x0FF21) || (ch > 0x0FF3A)) && ((ch < 0x0FF41) || (ch > 0x0FF5A)))
Cependant, je ne peux recommander d'utiliser aucune de ces options. J'écrirais ceci pour simplifier la lecture du code:
const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19)
Notez que j'ai supprimé certains des crochets. Comme nous venons de le voir, un grand nombre de crochets n'a pas du tout aidé à éviter une erreur. Les parenthèses devraient faciliter la lecture du code, pas plus compliquées. Les programmeurs se souviennent bien que la priorité des comparaisons = <, => est supérieure à celle de l'opérateur &&. Par conséquent, les crochets ne sont pas nécessaires ici. Mais si vous demandez quelle priorité est && ou ||, beaucoup seront confus. Par conséquent, pour spécifier la séquence des calculs &&, || les crochets sont mieux à mettre.
Pourquoi est-il préférable d'écrire || au début je décrivais dans l'article «
Le principal problème de programmation, de refactoring et tout ça » (voir chapitre: Aligner le même type de code avec un «tableau»).
Merci à tous pour votre attention. Téléchargez et commencez à utiliser
PVS-Studio . Cela aidera à identifier de nombreuses erreurs et vulnérabilités potentielles dès les premières étapes.

Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Andrey Karpov.
Comment PVS-Studio s'est avéré plus attentif que trois programmeurs et demi .