Dies ist eine kurze Geschichte darüber, wie PVS-Studio uns geholfen hat, einen Fehler im Quellcode der in PVS-Studio verwendeten Bibliothek zu finden. Und es war kein theoretischer, sondern ein tatsächlicher Fehler - der Fehler trat in der Praxis bei der Verwendung der Bibliothek im Analysegerät auf.
In PVS-Studio_Cmd (sowie einigen anderen Dienstprogrammen) verwenden wir eine spezielle Bibliothek zum Parsen von Befehlszeilenargumenten - CommandLine.
Heute habe ich den neuen Modus in PVS-Studio_Cmd unterstützt und es kam vor, dass ich diese Bibliothek zum Parsen von Befehlszeilenargumenten verwenden musste. Während ich den Code schreibe, debugge ich ihn auch, weil ich mit unbekannten APIs arbeiten muss.
Der Code wird also geschrieben, kompiliert, ausgeführt und ...
Die Codeausführung erfolgt in der Bibliothek, in der eine Ausnahme vom Typ
NullReferenceException auftritt. Von der Seite ist es nicht so klar - ich übergebe keine Nullreferenzen an die Methode.
Um sicher zu sein, schaue ich mir Kommentare zur Angerufenenmethode an. Es ist kaum wahrscheinlich, dass sie die Bedingungen für das Auftreten einer Ausnahme vom Typ
NullReferenceException beschreiben (wie mir scheint, sind Ausnahmen dieses Typs normalerweise nicht vorgesehen).
In den Kommentaren zur Methode (die jedoch erwartet wird) sind keine Informationen zu
NullReferenceException enthalten .
Um zu sehen, was genau die Ausnahme verursacht (und wo sie auftritt), habe ich beschlossen, den Quellcode des Projekts herunterzuladen, zu erstellen und dem Analysator einen Verweis auf die Debug-Version der Bibliothek hinzuzufügen. Der Quellcode des Projekts ist
bei GitHub verfügbar . Wir benötigen die Version 1.9.71 der Bibliothek. Es ist dasjenige, das jetzt im Analysator verwendet wird.
Ich lade die entsprechende Version des Quellcodes herunter, erstelle die Bibliothek, füge dem Analysator einen Verweis auf die Debug-Bibliothek hinzu, führe den Code aus und sehe:
Der Ort, an dem die Ausnahme auftritt, ist also klar -
helpInfo hat einen
Nullwert , der beim Zugriff auf die
Left- Eigenschaft eine Ausnahme vom Typ
NullReferenceException verursacht.
Ich fing an darüber nachzudenken. In letzter Zeit wurde PVS-Studio für C # in verschiedenen Aspekten gut verbessert, einschließlich der Suche nach der Dereferenzierung von potenziell Null-Referenzen. Insbesondere die interprozedurale Analyse wurde in mehrfacher Hinsicht verbessert. Aus diesem Grund war ich sofort daran interessiert, den Quellcode zu überprüfen, um zu verstehen, ob PVS-Studio den zur Diskussion stehenden Fehler finden konnte.
Ich habe den Quellcode überprüft und unter anderem genau das gesehen, was ich mir erhofft hatte.
PVS-Studio-Warnung :
V3080 Mögliche Null-Dereferenzierung innerhalb der Methode unter 'helpInfo.Left'. Überprüfen Sie das zweite Argument: helpInfo. Parser.cs 405
Ja, das ist es! Genau das brauchen wir. Schauen wir uns den Quellcode genauer an.
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);
Der Analysator gibt eine Warnung zum Aufrufen der
DisplayHelpVerbText- Methode aus und warnt vor dem zweiten Argument -
helpInfo . Beachten Sie, dass sich diese Methode im
then- Zweig der
if- Anweisung befindet. Der bedingte Ausdruck ist so zusammengesetzt, dass der
then- Zweig bei den nächsten Werten der Variablen ausgeführt werden kann:
- helpInfo == null ;
- _settings.HelpWriter! = null ;
Sehen wir uns den Hauptteil der
DisplayHelpVerbText- Methode an:
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); } }
Da
verb == null (siehe Methodenaufruf) interessiert uns der Verzweigung der
if- Anweisung. Obwohl die Situation beim
else- Zweig ähnlich ist, betrachten wir den
then- Zweig, da in unserem speziellen Fall die Ausführung ihn durchlaufen hat. Denken
Sie daran, dass
helpInfo möglicherweise
null ist .
Schauen wir uns nun den Hauptteil des
HelpVerbOptionAttribute an .
InvokeMethod- Methode. Eigentlich haben Sie es bereits auf dem Screenshot oben gesehen:
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 wird unbedingt aufgerufen, während
helpInfo null sein kann . Der Analysator warnte davor, und genau das ist passiert.
FazitEs ist schön, dass wir mit Hilfe von PVS-Studio einen Fehler im Quellcode der in PVS-Studio verwendeten Bibliothek gefunden haben. Ich denke, dies ist eine Art Antwort auf die Frage "Findet PVS-Studio Fehler im PVS-Studio-Quellcode?". :) Der Analysator kann Fehler nicht nur im PVS-Studio-Code, sondern auch im Code der verwendeten Bibliotheken finden.
Schließlich schlage ich vor, dass Sie
den Analysator herunterladen und versuchen, Ihr Projekt zu überprüfen - was ist, wenn Sie dort auch etwas Interessantes finden?