Ceci est une courte histoire sur la façon dont PVS-Studio nous a aidés à trouver une erreur dans le code source de la bibliothèque utilisée dans PVS-Studio. Et ce n'était pas une erreur théorique mais une erreur réelle - l'erreur est apparue en pratique lors de l'utilisation de la bibliothèque dans l'analyseur.
Dans PVS-Studio_Cmd (ainsi que certains autres utilitaires), nous utilisons une bibliothèque spéciale pour analyser les arguments de ligne de commande - CommandLine.
Aujourd'hui, j'ai pris en charge le nouveau mode dans PVS-Studio_Cmd et il se trouve que j'ai dû utiliser cette bibliothèque pour analyser les arguments de la ligne de commande. Lors de l'écriture du code, je le débogue également car je dois travailler avec des API inconnues.
Ainsi, le code est écrit, compilé, exécuté et ...
L'exécution du code va à l'intérieur de la bibliothèque où une exception du type
NullReferenceException se produit. Ce n'est pas si clair de côté - je ne passe aucune référence nulle dans la méthode.
Pour être sûr, je regarde les commentaires sur la méthode appelée. Il est peu probable qu'ils décrivent les conditions d'occurrence d'une exception du type
NullReferenceException (comme il me semble généralement que les exceptions de ce type ne sont pas prévues).
Il n'y a aucune information sur
NullReferenceException dans les commentaires sur la méthode (qui, cependant, est attendue).
Pour voir ce qui cause exactement l'exception (et où elle se produit), j'ai décidé de télécharger le code source du projet, de le construire et d'ajouter une référence à la version de débogage de la bibliothèque à l'analyseur. Le code source du projet est
disponible sur GitHub . Nous avons besoin de la version 1.9.71 de la bibliothèque. C'est celui utilisé dans l'analyseur maintenant.
Je télécharge la version correspondante du code source, crée la bibliothèque, ajoute une référence à la bibliothèque de débogage à l'analyseur, exécute le code et vois:
Ainsi, l'endroit où l'exception se produit est clair -
helpInfo a une valeur
nulle , ce qui provoque une exception du type
NullReferenceException lors de l'accès à la propriété
Left .
J'ai commencé à y penser. Récemment, PVS-Studio pour C # a été bien amélioré sous divers aspects, y compris la recherche de déréférencement de références potentiellement nulles. En particulier, l'analyse interprocédurale a été améliorée de plusieurs manières. C'est pourquoi je me suis immédiatement intéressé à vérifier le code source pour comprendre si PVS-Studio pouvait trouver l'erreur en cours de discussion.
J'ai vérifié le code source et entre autres avertissements, j'ai vu exactement ce que j'espérais.
Avertissement PVS-Studio :
V3080 Déréférence nulle possible à l'intérieur de la méthode sur 'helpInfo.Left'. Pensez à inspecter le deuxième argument: helpInfo. Parser.cs 405
Ouais, c'est ça! C'est exactement ce dont nous avons besoin. Jetons un regard plus détaillé sur le code source.
private bool DoParseArgumentsVerbs( string[] args, object options, ref object verbInstance) { var verbs = ReflectionHelper.RetrievePropertyList<VerbOptionAttribute>(options); var helpInfo = ReflectionHelper.RetrieveMethod<HelpVerbOptionAttribute>(options); if (args.Length == 0) { if (helpInfo != null || _settings.HelpWriter != null) { DisplayHelpVerbText(options, helpInfo, null);
L'analyseur émet un avertissement pour appeler la méthode
DisplayHelpVerbText et met en garde contre le deuxième argument -
helpInfo . Faites attention à ce que cette méthode se trouve dans la branche
then de l'instruction
if . L'expression conditionnelle est composée de telle manière que la branche
then- peut être exécutée aux valeurs suivantes des variables:
- helpInfo == null ;
- _settings.HelpWriter! = null ;
Voyons le corps de la méthode
DisplayHelpVerbText :
private void DisplayHelpVerbText( object options, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb) { string helpText; if (verb == null) { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, null, out helpText); } else { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, verb, out helpText); } if (_settings.HelpWriter != null) { _settings.HelpWriter.Write(helpText); } }
Depuis le
verbe == null (voir appel de méthode), nous nous intéressons à la branche
then- de l'instruction
if . Bien que la situation soit similaire avec la branche
else , considérons
alors la branche car dans notre cas particulier, l'exécution est passée par là. N'oubliez pas que
helpInfo peut être
nul .
Examinons maintenant le corps de
HelpVerbOptionAttribute . Méthode
InvokeMethod . En fait, vous l'avez déjà vu sur la capture d'écran ci-dessus:
internal static void InvokeMethod( object target, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb, out string text) { text = null; var method = helpInfo.Left; if (!CheckMethodSignature(method)) { throw new MemberAccessException( SR.MemberAccessException_BadSignatureForHelpVerbOptionAttribute .FormatInvariant(method.Name)); } text = (string)method.Invoke(target, new object[] { verb }); }
helpInfo.Left est appelé sans condition, tandis que
helpInfo peut être
null . L'analyseur en a averti, et c'est ce qui s'est produit.
ConclusionC'est bien que nous ayons réussi à trouver une erreur dans le code source de la bibliothèque utilisée dans PVS-Studio avec l'aide de PVS-Studio. Je pense que c'est une sorte de réponse à la question "PVS-Studio trouve-t-il des erreurs dans le code source de PVS-Studio?". :) L'analyseur peut trouver des erreurs non seulement dans le code PVS-Studio mais aussi dans le code des bibliothèques utilisées.
Enfin, je vous suggère de
télécharger l'analyseur et d'essayer de vérifier votre projet - que faire si vous pouvez également trouver quelque chose d'intéressant?