Die .NET Core-Bibliotheken sind eines der beliebtesten C # -Projekte auf GitHub. Angesichts seiner großen Beliebtheit und Benutzerfreundlichkeit nicht überraschend. Umso interessanter ist es, herauszufinden, welche dunklen Ecken im Quellcode dieser Bibliotheken enthalten sind, was wir mit dem statischen Analysegerät PVS-Studio versuchen werden. Glaubst du, du hast am Ende etwas Interessantes entdeckt?
Ich habe diesen Artikel mehr als anderthalb Jahre lang gelesen. Irgendwann kam mir der Gedanke, dass die .NET Core-Bibliotheken ein Leckerbissen sind, und das Auschecken wird interessant sein. Mehrmals habe ich das Projekt überprüft, der Analysator hat immer interessantere Orte gefunden, aber es ging nicht über ein schnelles Scrollen durch die Liste der Warnungen hinaus. Und hier ist es - fertig! Das Projekt wird überprüft, der Artikel liegt vor Ihnen.
Mehr zum Projekt und zur Analyse
Wenn Sie gerne in die Analyse des Codes eintauchen möchten - Sie können diesen Abschnitt überspringen, aber ich möchte, dass Sie ihn lesen -, spreche ich hier ein wenig mehr über das Projekt und den Analysator sowie darüber, wie ich die Fehler analysiert und reproduziert habe.
Geprüftes Projekt
Wahrscheinlich ist es möglich, nicht zu sagen, was CoreFX (.NET Core-Bibliotheken) sind, aber wenn Sie es nicht gehört haben, ist die Beschreibung unten. Ich habe es nicht umformuliert und es
von der Projektseite auf GitHub genommen , wo Sie auch die Quellen herunterladen können.
Beschreibung:
Dieses Repo enthält die Bibliotheksimplementierung ("CoreFX" genannt) für .NET Core. Es enthält System.Collections, System.IO, System.Xml und viele andere Komponenten. Das entsprechende .NET Core Runtime-Repo ("CoreCLR" genannt) enthält die Laufzeitimplementierung für .NET Core. Es enthält RyuJIT, .NET GC und viele andere Komponenten. Laufzeitspezifischer Bibliothekscode (System.Private.CoreLib) befindet sich im CoreCLR-Repo. Es muss zusammen mit der Laufzeit erstellt und versioniert werden. Der Rest von CoreFX ist unabhängig von der Laufzeitimplementierung und kann auf jeder kompatiblen .NET-Laufzeit (z .
B. CoreRT) ausgeführt werden .
Verwendeter Analysator und Analysemethode
Ich habe den Quellcode mit dem
statischen Analysegerät PVS-Studio überprüft. Im Allgemeinen kann PVS-Studio nicht nur C # -Code, sondern auch C, C ++ und Java analysieren. Die Analyse von C # -Code funktioniert bisher nur unter Windows, während Code in C, C ++, Java unter Windows, Linux und MacOS analysiert werden kann.
Normalerweise verwende ich das PVS-Studio-Plugin für Visual Studio, um C # -Projekte zu testen (Versionen 2010-2019 werden unterstützt), da dies wahrscheinlich die einfachste und bequemste Methode zur Analyse ist: Öffnen Sie eine Lösung, starten Sie die Analyse, arbeiten Sie mit einer Liste von Warnungen. Mit CoreFX wurde es jedoch etwas komplizierter.
Tatsache ist, dass das Projekt keine einzige SLN-Datei enthält. Daher schlägt das Öffnen in Visual Studio und das Durchführen einer vollständigen Analyse mit dem PVS-Studio-Plug-In fehl. Wahrscheinlich ist es gut - ich weiß nicht wirklich, wie Visual Studio mit einer Lösung dieser Größe umgehen würde.
Es gab jedoch keine Probleme mit der Analyse, da das PVS-Studio-Verteilungskit eine Befehlszeilenversion des Analysators für MSBuild-Projekte (und tatsächlich .sln) enthält. Alles, was von mir verlangt wurde, war, ein kleines Skript zu schreiben, das "PVS-Studio_Cmd.exe" für jede .sln im CoreFX-Verzeichnis ausführt und die Analyseergebnisse in einem separaten Verzeichnis ablegt (angezeigt durch das Startflag des Analysators).
Voila! - Am Ausgang habe ich eine Reihe von Protokollen, die viele interessante Dinge enthalten. Falls gewünscht, können die Protokolle mit dem Dienstprogramm PlogConverter kombiniert werden, das mit dem Verteilungskit geliefert wird. Für mich war es jedoch bequemer, mit einzelnen Protokollen zu arbeiten, sodass ich nicht anfing, sie zu kombinieren.
Bei der Beschreibung einiger Fehler verweise ich auf die Dokumentation von docs.microsoft.com und auf die NuGet-Pakete, die von nuget.org heruntergeladen werden können. Ich gebe zu, dass der in der Dokumentation beschriebene / in Paketen enthaltene Code geringfügig vom analysierten Code abweichen kann. Es wird jedoch sehr seltsam sein, wenn beispielsweise die Dokumentation keine Beschreibung der generierten Ausnahmen für eine Reihe von Eingabedaten enthält und diese in der neuen Version des Pakets erscheinen - stimmen Sie zu, dass dies eine zweifelhafte Überraschung sein wird. Die Reproduktion von Fehlern in Paketen von NuGet mit denselben Eingabedaten, die zum Debuggen von Bibliotheken verwendet wurden, zeigt, dass das Problem nicht neu ist und, was noch wichtiger ist, dass es „berührt“ werden kann, ohne das Projekt aus dem Quellcode zu erstellen.
Unter der Annahme einer theoretischen Fehlersynchronisation des theoretischen Codes halte ich es daher für zulässig, auf die Beschreibung der entsprechenden Methoden auf docs.microsoft.com zu verweisen und Probleme auf Paketen von nuget.org zu reproduzieren.
Ich stelle auch fest, dass sich die Beschreibung der bereitgestellten Links sowie Informationen (Kommentare) in Paketen (in anderen Versionen) während des Schreibens des Artikels ändern können.
Andere bewährte Projekte
Übrigens ist dies kein einzigartiger Artikel, wir schreiben andere Artikel über das Überprüfen von Projekten, von denen eine Liste
hier zu finden ist . Darüber hinaus haben wir auf der Website nicht nur Artikel zur Analyse von Projekten gesammelt, sondern auch verschiedene technische Artikel zu C, C ++, C #, Java sowie nur interessante Hinweise. All dies finden Sie im
Blog .
Mein Kollege hat bereits 2015 .NET Core-Bibliotheken getestet. Die Ergebnisse der vorherigen Analyse finden Sie im entsprechenden Artikel: "
Neujahrsprüfung von .NET Core Libraries (CoreFX) ".
Entdeckte Fehler, verdächtige und interessante Orte
Wie immer empfehle ich aus Gründen des größeren Interesses, zuerst selbst nach Fehlern in den Fragmenten zu suchen und erst dann die Warnung und Beschreibung des Analysators des Problems zu lesen.
Der Einfachheit halber habe ich die fraglichen Fragmente mithilfe von Beschriftungen des Formulars
Ausgabe N explizit voneinander getrennt. Es ist einfacher zu verstehen, wo die Beschreibung eines Fehlers endet und die Analyse des anderen beginnt. Ja, und es ist auch einfacher, sich auf bestimmte Fragmente zu beziehen.
Problem 1abstract public class Principal : IDisposable { .... public void Save(PrincipalContext context) { .... if ( context.ContextType == ContextType.Machine || _ctx.ContextType == ContextType.Machine) { throw new InvalidOperationException( SR.SaveToNotSupportedAgainstMachineStore); } if (context == null) { Debug.Assert(this.unpersisted == true); throw new InvalidOperationException(SR.NullArguments); } .... } .... }
PVS-Studio Warnung :
V3095 Das '
Kontext' -Objekt wurde verwendet, bevor es gegen Null verifiziert wurde. Überprüfen Sie die Zeilen: 340, 346. Principal.cs 340
Die Entwickler geben ausdrücklich an, dass der
Nullwert für den
Kontextparameter ungültig ist, und möchten dies mit Ausnahme des Typs
InvalidOperationException hervorheben . Etwas höher, in der vorherigen Bedingung, gibt es jedoch eine bedingungslose Dereferenzierung des
Kontextlinks -
context.ContextType . Wenn der Wert des
Kontexts null ist , wird daher anstelle der erwarteten
InvalidOperationExcetion eine Ausnahme vom Typ
NullReferenceException ausgelöst .
Versuchen wir, das Problem zu reproduzieren. Verbinden Sie die entsprechende Bibliothek (
System.DirectoryServices.AccountManagement ) mit dem Projekt und führen Sie den folgenden Code aus:
GroupPrincipal groupPrincipal = new GroupPrincipal(new PrincipalContext(ContextType.Machine)); groupPrincipal.Save(null);
GroupPrincipal ist der Nachfolger der abstrakten Klasse
Principal , die die Implementierung der von uns benötigten
Save- Methode enthält. Wir führen den Code zur Ausführung aus und sehen, was zum Beweis erforderlich war.
Zum Spaß können Sie versuchen, das entsprechende Paket von NuGet herunterzuladen und das Problem auf die gleiche Weise zu wiederholen. Ich habe das Paket Version 4.5.0 installiert und das erwartete Ergebnis erhalten.
Problem 2 private SearchResultCollection FindAll(bool findMoreThanOne) { searchResult = null; DirectoryEntry clonedRoot = null; if (_assertDefaultNamingContext == null) { clonedRoot = SearchRoot.CloneBrowsable(); } else { clonedRoot = SearchRoot.CloneBrowsable(); } .... }
PVS-Studio Warnung :
V3004 Die Anweisung 'then' entspricht der Anweisung 'else'. DirectorySearcher.cs 629
Unabhängig von der Wahrheit der Bedingung
_assertDefaultNamingContext == null werden seitdem dieselben Aktionen ausgeführt, und
ansonsten haben die Zweige der
if-Anweisung dieselben Körper. Entweder sollte es in einem Zweig eine andere Aktion geben, oder Sie können die
if-Anweisung weglassen, um die Programmierer und den Analysator nicht zu verwirren.
Ausgabe 3 public class DirectoryEntry : Component { .... public void RefreshCache(string[] propertyNames) { .... object[] names = new object[propertyNames.Length]; for (int i = 0; i < propertyNames.Length; i++) names[i] = propertyNames[i]; .... if (_propertyCollection != null && propertyNames != null) .... .... } .... }
PVS-Studio Warnung :
V3095 Das Objekt 'propertyNames' wurde verwendet, bevor es gegen null verifiziert wurde. Überprüfen Sie die Zeilen: 990, 1004. DirectoryEntry.cs 990
Wieder sehen wir eine seltsame Prozedur. Die Methode hat eine
propertyNames! = Null- Prüfung, d. H. Entwickler versichern sich, dass die Methode
null zurückgibt. Hier oben können Sie mehrere Zugriffe auf diese möglicherweise null Referenz beobachten -
propertyNames.Length und
propertyNames [i] . Das Ergebnis ist ziemlich vorhersehbar - eine Ausnahme vom Typ
NullReferenceExcepption tritt auf, wenn eine
Nullreferenz an die Methode übergeben wird.
Was für ein Zufall, dass
RefreshCache eine öffentliche Methode in einer öffentlichen Klasse ist. Versuchen Sie das Problem zu wiederholen? Verbinden Sie dazu die gewünschte Bibliothek -
System.DirectoryServices - mit dem Projekt und schreiben Sie den Code wie
folgt :
DirectoryEntry de = new DirectoryEntry(); de.RefreshCache(null);
Führen Sie den Code zur Ausführung aus und sehen Sie das erwartete Bild.
Zum Spaß können Sie versuchen, das Problem in der Release-Version des NuGet-Pakets zu reproduzieren. Wir verbinden das
System.DirectoryServices- Paket mit dem NuGet-Projekt (ich habe Version 4.5.0 verwendet) und führen den bereits bekannten Code zur Ausführung aus. Das Ergebnis ist niedriger.
Ausgabe 4Jetzt gehen wir vom Gegenteil aus: Versuchen Sie zuerst, Code zu schreiben, der eine Instanz der Klasse verwendet, und schauen Sie dann hinein. Schauen wir uns die Struktur von
System.Drawing.CharacterRange aus der
System.Drawing.Common- Bibliothek und dem gleichnamigen NuGet-Paket an.
Der verwendete Code lautet wie folgt:
CharacterRange range = new CharacterRange(); bool eq = range.Equals(null); Console.WriteLine(eq);
Für den Fall, dass der Speicher
aktualisiert wird, wenden wir uns an
docs.microsoft.com , um
uns zu merken, welcher Rückgabewert vom Ausdruck
obj.Equals (null) erwartet wird:
Die folgenden Aussagen müssen für alle Implementierungen der Equals (Object) -Methode zutreffen. In der Liste stehen x, y und z für Objektreferenzen, die nicht null sind.....x.Equals (null) gibt false zurück.Denken Sie, dass der Text "Falsch" in der Konsole angezeigt wird? Natürlich nicht, das wäre zu einfach. :) Wir führen den Code aus und schauen uns das Ergebnis an.
Dies war die Schlussfolgerung bei der Ausführung des obigen Codes mit dem NuGet-Paket
System.Drawing.Common Version 4.5.1. Wir führen denselben Code mit der Debug-Version der Bibliothek aus und sehen Folgendes:
Schauen wir uns nun den Quellcode an - die Implementierung der
Equals- Methode in der
CharacterRange- Struktur und die Analyse-Warnung:
public override bool Equals(object obj) { if (obj.GetType() != typeof(CharacterRange)) return false; CharacterRange cr = (CharacterRange)obj; return ((_first == cr.First) && (_length == cr.Length)); }
PVS-Studio- Warnung :
V3115 Die Übergabe von 'null' an die Methode 'Equals' sollte nicht zu 'NullReferenceException' führen. CharacterRange.cs 56
Wir sehen, was wir beweisen mussten - der Parameter
obj wird ungenau verarbeitet,
weshalb beim Aufrufen der Instanzmethode
GetType im bedingten Ausdruck eine Ausnahme vom Typ
NullReferenceException auftritt.
Ausgabe 5Berücksichtigen Sie beim Erkunden dieser Bibliothek einen weiteren interessanten Ort - die
Icon.Save- Methode. Lesen Sie vor der Studie die Beschreibung der Methode.
Es gibt keine Beschreibung der Methode:
Wir wenden uns an docs.microsoft.com - "
Icon.Save (Stream) -Methode ". Es gibt jedoch auch keine Einschränkungen für die Eingabewerte und es gibt keine Informationen zu den generierten Ausnahmen.
Kommen wir nun zur Codeforschung.
public sealed partial class Icon : MarshalByRefObject, ICloneable, IDisposable, ISerializable { .... public void Save(Stream outputStream) { if (_iconData != null) { outputStream.Write(_iconData, 0, _iconData.Length); } else { .... if (outputStream == null) throw new ArgumentNullException("dataStream"); .... } } .... }
PVS-Studio Warnung :
V3095 Das Objekt 'outputStream' wurde verwendet, bevor es gegen null verifiziert wurde. Überprüfen Sie die Zeilen: 654, 672. Icon.Windows.cs 654
Wiederum ist die Geschichte, die wir bereits kennen, die mögliche Dereferenzierung einer Nullreferenz, da der Methodenparameter dereferenziert wird, ohne nach
Null zu
suchen . Wiederum ist eine gute Kombination von Umständen - sowohl die Klasse als auch die Methode - öffentlich, was bedeutet, dass Sie versuchen können, das Problem zu reproduzieren.
Die Aufgabe ist einfach: Die Codeausführung in den Ausdruck
outputStream.Write (_iconData, 0, _iconData.Length) zu bringen. unter Beibehaltung des Werts der Variablen
outputStream -
null . Dafür reicht es aus, dass die Bedingung
_iconData! = Null erfüllt ist.
Schauen wir uns den einfachsten öffentlichen Konstruktor an:
public Icon(string fileName) : this(fileName, 0, 0) { }
Er delegiert die Arbeit einfach an einen anderen Konstrukteur. Schauen Sie weiter - der hier verwendete Konstruktor.
public Icon(string fileName, int width, int height) : this() { using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { Debug.Assert(f != null, "File.OpenRead returned null instead of throwing an exception"); _iconData = new byte[(int)f.Length]; f.Read(_iconData, 0, _iconData.Length); } Initialize(width, height); }
Hier ist es, was Sie brauchen. Wenn wir nach dem Aufrufen dieses Konstruktors die Daten erfolgreich aus der Datei gelesen haben und keine Abstürze in der
Initialize- Methode auftreten, enthält das Feld
_iconData einen Link zu einem Objekt, das wir benötigen.
Es stellt sich heraus, dass Sie zur Reproduktion des Problems eine Instanz der
Icon- Klasse mit dem tatsächlichen Symbol erstellen und dann die
Save- Methode aufrufen müssen, wobei
null als Argument übergeben wird, was wir tun werden. Der Code kann beispielsweise wie folgt aussehen:
Icon icon = new Icon(@"D:\document.ico"); icon.Save(null);
Das Ergebnis der Ausführung wird erwartet.
Ausgabe 6Wir setzen die Überprüfung fort und gehen zur
System.Management- Bibliothek. Versuchen Sie, 3 Unterschiede zwischen den im
Fall CimType.UInt32 ausgeführten Aktionen und dem Rest des
Falls zu finden .
private static string ConvertToNumericValueAndAddToArray(....) { string retFunctionName = string.Empty; enumType = string.Empty; switch(cimType) { case CimType.UInt8: case CimType.SInt8: case CimType.SInt16: case CimType.UInt16: case CimType.SInt32: arrayToAdd.Add(System.Convert.ToInt32( numericValue, (IFormatProvider)CultureInfo.InvariantCulture .GetFormat(typeof(int)))); retFunctionName = "ToInt32"; enumType = "System.Int32"; break; case CimType.UInt32: arrayToAdd.Add(System.Convert.ToInt32( numericValue, (IFormatProvider)CultureInfo.InvariantCulture .GetFormat(typeof(int)))); retFunctionName = "ToInt32"; enumType = "System.Int32"; break; } return retFunctionName; }
Natürlich gibt es keine Unterschiede, vor denen der Analysator warnt.
PVS-Studio Warnung :
V3139 Zwei oder mehr
Fallzweige führen dieselben Aktionen aus. WMIGenerator.cs 5220
Dieser Codestil ist mir persönlich nicht sehr klar. Wenn hier kein Fehler vorliegt, hat es sich meiner Meinung nach nicht gelohnt, dieselbe Logik auf verschiedene Fälle zu verteilen.
Ausgabe 7Microsoft.CSharp- Bibliothek.
private static IList<KeyValuePair<string, object>> QueryDynamicObject(object obj) { .... List<string> names = new List<string>(mo.GetDynamicMemberNames()); names.Sort(); if (names != null) { .... } .... }
PVS-Studio- Warnung :
V3022 Ausdruck 'names! = Null' ist immer wahr. DynamicDebuggerProxy.cs 426
Ich könnte diese Warnung wahrscheinlich ignorieren, zusammen mit vielen ähnlichen, die von der
V3022- und
V3063-Diagnose ausgegeben wurden. Es gab viele (sehr viele) seltsame Schecks, aber das versank irgendwie in meiner Seele. Es ist möglich, dass vor dem Vergleich der lokalen Variablennamen mit
null mit dieser Variablen nicht nur ein Verweis auf das neu erstellte Objekt geschrieben wird, sondern auch die Instanzmethode
Sort aufgerufen wird . Dies ist natürlich kein Fehler, aber der Ort ist für mich interessant.
Ausgabe 8Hier ist ein weiterer interessanter Code.
private static void InsertChildNoGrow(Symbol child) { .... while (sym?.nextSameName != null) { sym = sym.nextSameName; } Debug.Assert(sym != null && sym.nextSameName == null); sym.nextSameName = child; .... }
PVS-Studio Warnung :
V3042 Mögliche NullReferenceException. Das '?.' und '.' Operatoren werden für den Zugriff auf Mitglieder des 'sym'-Objekts SymbolStore.cs 56 verwendet
Sehen Sie, was das Ding hier ist. Der Zyklus endet, wenn eine von zwei Bedingungen erfüllt ist:
- sym == null ;
- sym.nextSameName == null .
Es gibt kein Problem mit der zweiten Bedingung, die nicht über die erste gesagt werden kann, da unten ein bedingungsloser Aufruf des
Instanzfelds nextSameName erfolgt und, wenn
sym null ist ,
während des Aufrufs eine Ausnahme vom Typ
NullReferenceException ausgelöst wird.
„Bist du blind? Es gibt auch einen Aufruf von
Debug.Assert , wo überprüft wird, ob
sym! = Null "- jemand kann
Einwände erheben . Aber das ist alles Salz! Wenn wir in der Release-Version von
Debug.Assert arbeiten, hilft nichts, und mit dem oben beschriebenen
Status erhalten wir nur eine
NullReferenceException . Außerdem habe ich bereits einen ähnlichen Fehler in einem anderen Projekt von Microsoft gesehen -
Roslyn , wo es eine sehr ähnliche Situation mit
Debug.Assert gab . Ein wenig abgelenkt von Roslyn mit Ihrer Erlaubnis.
Das Problem kann entweder mithilfe von
Microsoft.CodeAnalysis- Bibliotheken oder direkt in Visual Studio mithilfe von Syntax Visualizer reproduziert werden. In Visual Studio Version 16.1.6 + Syntax Visualizer 1.0 wird dieses Problem weiterhin reproduziert.
Für die Reproduktion reicht der folgende Code aus:
class C1<T1, T2> { void foo() { T1 val = default; if (val is null) { } } }
Als Nächstes müssen Sie in Syntax Visualizer den Knoten des Syntaxbaums vom Typ
ConstantPatternSyntax finden , der
null im Code entspricht, und
TypeSymbol dafür
anfordern .
Danach wird Visual Studio neu gestartet. Wenn wir in die Ereignisanzeige gehen, finden wir Informationen zu Problemen in den Bibliotheken:
Application: devenv.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.Resources.MissingManifestResourceException at System.Resources.ManifestBasedResourceGroveler .HandleResourceStreamMissing(System.String) at System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet( System.Globalization.CultureInfo, System.Collections.Generic.Dictionary'2 <System.String,System.Resources.ResourceSet>, Boolean, Boolean, System.Threading.StackCrawlMark ByRef) at System.Resources.ResourceManager.InternalGetResourceSet( System.Globalization.CultureInfo, Boolean, Boolean, System.Threading.StackCrawlMark ByRef) at System.Resources.ResourceManager.InternalGetResourceSet( System.Globalization.CultureInfo, Boolean, Boolean) at System.Resources.ResourceManager.GetString(System.String, System.Globalization.CultureInfo) at Roslyn.SyntaxVisualizer.DgmlHelper.My. Resources.Resources.get_SyntaxNodeLabel() ....
Und zum Problem mit devenv.exe:
Faulting application name: devenv.exe, version: 16.1.29102.190, time stamp: 0x5d1c133b Faulting module name: KERNELBASE.dll, version: 10.0.18362.145, time stamp: 0xf5733ace Exception code: 0xe0434352 Fault offset: 0x001133d2 ....
Mit Debug-Versionen der Roslyn-Bibliotheken können Sie den Ort finden, an dem die Ausnahme aufgetreten ist:
private Conversion ClassifyImplicitBuiltInConversionSlow( TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { Debug.Assert((object)source != null); Debug.Assert((object)destination != null); if ( source.SpecialType == SpecialType.System_Void || destination.SpecialType == SpecialType.System_Void) { return Conversion.NoConversion; } .... }
Wie im obigen Code aus den .NET Core-Bibliotheken gibt es auch hier eine Überprüfung durch
Debug.Assert , die jedoch bei der Verwendung der Release-Versionen der Bibliotheken in keiner Weise hilfreich war.
Ausgabe 9Ein bisschen abgelenkt - und das reicht aus, zurück zu den .NET Core-Bibliotheken. Das
System.IO.IsolatedStorage- Paket enthält den folgenden interessanten Code.
private bool ContainsUnknownFiles(string directory) { .... return (files.Length > 2 || ( (!IsIdFile(files[0]) && !IsInfoFile(files[0]))) || (files.Length == 2 && !IsIdFile(files[1]) && !IsInfoFile(files[1])) ); }
Warnung PVS-Studio :
V3088 Der Ausdruck wurde zweimal in Klammern gesetzt: ((Ausdruck)). Ein Klammerpaar ist nicht erforderlich oder es liegt ein Druckfehler vor. IsolatedStorageFile.cs 839
Zu sagen, dass die Code-Formatierung verwirrend ist, bedeutet nichts zu sagen. Wenn ich kurz auf diesen Code schaue, würde ich sagen, dass der linke Operand des ersten Operators || -
files.Length> 2 , die richtige ist die in Klammern. Zumindest ist der Code so formatiert. Wenn Sie etwas genauer hinschauen, können Sie verstehen, dass dies nicht der Fall ist. Tatsächlich ist der richtige Operand
((! IsIdFile (files [0]) &&! IsInfoFile (files [0]))) . Meiner Meinung nach ist dieser Code ziemlich verwirrend.
Ausgabe 10In der Version von PVS-Studio 7.03 wurde die Diagnoseregel V3138 hinzugefügt, die nach Fehlern in interpolierten Zeilen sucht. Genauer gesagt, in Zeilen, die am wahrscheinlichsten interpoliert werden, aber aufgrund des fehlenden
$ -Zeichens nicht. Die
System.Net- Bibliotheken haben mehrere interessante Antworten auf diese Diagnoseregel gefunden.
internal static void CacheCredential(SafeFreeCredentials newHandle) { try { .... } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { NetEventSource.Fail(null, "Attempted to throw: {e}"); } } }
PVS-Studio Warnung :
V3138 String-Literal enthält potenziellen interpolierten Ausdruck. Betrachten Sie Folgendes: e. SSPIHandleCache.cs 42
Es ist sehr wahrscheinlich, dass das zweite Argument für die
Fail- Methode eine interpolierte Zeichenfolge ist, in die die Zeichenfolgendarstellung der
e- Ausnahme eingesetzt wird. Aufgrund des fehlenden
$ -Zeichens wird jedoch keine Zeichenfolgendarstellung der Ausnahme ausgelöst.
Ausgabe 11Ich habe einen anderen ähnlichen Fall getroffen.
public static async Task<string> GetDigestTokenForCredential(....) { .... if (NetEventSource.IsEnabled) NetEventSource.Error(digestResponse, "Algorithm not supported: {algorithm}"); .... }
PVS-Studio Warnung :
V3138 String-Literal enthält potenziellen interpolierten Ausdruck. Betrachten Sie Folgendes: Algorithmus. AuthenticationHelper.Digest.cs 58
Die Situation ist ähnlich wie oben beschrieben, das
$ -Symbol wird erneut übersprungen - die falsche Zeile geht zur
Fehlermethode .
Ausgabe 12Paket
System.Net.Mail . Die Methode ist klein, ich werde sie in ihrer Gesamtheit bringen, damit der Fehler etwas interessanter ist.
internal void SetContent(Stream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (_streamSet) { _stream.Close(); _stream = null; _streamSet = false; } _stream = stream; _streamSet = true; _streamUsedOnce = false; TransferEncoding = TransferEncoding.Base64; }
PVS-Studio Warnung :
V3008 Der Variablen '_streamSet' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 123, 119. MimePart.cs 123
Die doppelte Zuweisung des Wertes der Variablen
_streamSet sieht seltsam aus (zuerst - unter der Bedingung; dann - außerhalb). Die gleiche Geschichte mit dem Nullstellen der Variablen
_stream . Infolgedessen wird
_stream weiterhin auf
stream und
_streamSet auf
true gesetzt .
Ausgabe 13Ein interessanter Ort aus der
System.Linq.Expressions- Bibliothek, an den der Analysator sofort zwei Warnungen ausgegeben hat. In diesem Fall ist es eher eine Funktion als ein Fehler, aber dennoch ist die Methode sehr interessant ...
PVS-Studio-Warnungen :
- V3010 Der Rückgabewert der Funktion 'GetType' muss verwendet werden. Instruction.cs 36
- V3080 Mögliche Null-Dereferenzierung. Betrachten Sie die Inspektion von 'o'. Instruction.cs 36
Es gibt wahrscheinlich nichts zu kommentieren.
Ausgabe 14Schauen wir uns einen anderen Fall an, mit dem wir "von außen" arbeiten werden. Zuerst schreiben wir den Code, identifizieren die Probleme und schauen dann hinein. Nehmen Sie zum Studieren die
System.Configuration.ConfigurationManager- Bibliothek und das gleichnamige NuGet-Paket. Ich habe das Paket Version 4.5.0 verwendet. Wir werden mit der
System.Configuration.CommaDelimitedStringCollection- Klasse arbeiten.
Lassen Sie uns etwas tun, das nicht sehr schwierig ist. Erstellen Sie beispielsweise ein Objekt, extrahieren Sie seine Zeichenfolgendarstellung, ermitteln Sie die Länge dieser Zeichenfolge und drucken Sie sie aus. Relevanter Code:
CommaDelimitedStringCollection collection = new CommaDelimitedStringCollection(); Console.WriteLine(collection.ToString().Length);
Schauen Sie sich für alle Fälle die Beschreibung der
ToString- Methode an:
Nichts Außergewöhnliches - die Zeichenfolgendarstellung des Objekts wird einfach zurückgegeben. Für alle Fälle schaue ich auch auf docs.microsoft.com - "
CommaDelimitedStringCollection.ToString Method ". Es scheint auch nichts Besonderes zu sein.
Ok, führen Sie den Code zur Ausführung aus, ii ...
Hmm, unerwartet. Lassen Sie uns versuchen, der Sammlung ein Element hinzuzufügen und dann die Zeichenfolgendarstellung abzurufen. "Ganz zufällig" werden wir eine leere Zeichenfolge hinzufügen :). Der Code ändert sich und sieht folgendermaßen aus:
CommaDelimitedStringCollection collection = new CommaDelimitedStringCollection(); collection.Add(String.Empty); Console.WriteLine(collection.ToString().Length);
Wir starten es und sehen ...
Was nochmal ?! Schauen wir uns zum Schluss die Implementierung der
ToString- Methode der
CommaDelimitedStringCollection- Klasse an. Der Code wird unten dargestellt:
public override string ToString() { if (Count <= 0) return null; StringBuilder sb = new StringBuilder(); foreach (string str in this) { ThrowIfContainsDelimiter(str);
PVS-Studio-Warnungen :
- V3108 Es wird nicht empfohlen, 'null' von der 'ToSting ()' - Methode zurückzugeben. StringAttributeCollection.cs 57
- V3108 Es wird nicht empfohlen, 'null' von der 'ToSting ()' - Methode zurückzugeben. StringAttributeCollection.cs 71
Hier sehen wir zwei Stellen, an denen die aktuelle
ToString- Implementierung
null zurückgeben kann . Erinnern Sie sich daran, was Microsoft bei der Implementierung der
ToString- Methode
empfiehlt , für die wir uns erneut an docs.microsoft.com - "
Object.ToString-Methode "
wenden :
Hinweise für Vererbungen .... Überschreibungen der ToString () -Methode sollten den folgenden Richtlinien folgen:- ....
- Ihre ToString () - Überschreibung sollte weder leer noch eine Nullzeichenfolge zurückgeben .
- ....
Genau davor warnt PVS-Studio. Die beiden obigen Codeausschnitte, die wir geschrieben haben, um das Problem zu reproduzieren, erreichen unterschiedliche Austrittspunkte - die erste und die zweite Stelle, an der
null zurückgegeben wird. Etwas tiefer graben.
Der erste Fall.
Count - eine Eigenschaft der Basisklasse
StringCollection . Da keine Elemente hinzugefügt wurden,
Count == 0 , ist die Bedingung
Count <= 0 erfüllt,
null wird zurückgegeben.
Im zweiten Fall haben wir dazu ein Element mit der Instanzmethode
CommaDelimitedStringCollection.Add hinzugefügt.
public new void Add(string value) { ThrowIfReadOnly(); ThrowIfContainsDelimiter(value); _modified = true; base.Add(value.Trim()); }
Überprüft,
ob die
ThrowIf ... -Methode erfolgreich übergeben wurde, und das Element wird der
Basissammlung hinzugefügt. Dementsprechend wird der Wert von
Count gleich 1. Nun kehren wir zur
ToString- Methode zurück. Der Wert des Ausdrucks
Count <= 0 ist
false , daher gibt es keinen Ausweg aus der Methode und der Code wird weiterhin ausgeführt. Der Durchlauf der internen Auflistung beginnt und dem
StringBuilder werden zwei Elemente hinzugefügt - eine leere Zeichenfolge und ein Komma. Als Ergebnis stellt sich heraus, dass
sb nur ein Komma enthält, der Wert der
Length- Eigenschaft ist gleich eins. Der Wert des Ausdrucks
sb.Length> 0 ist
true , es wird subtrahiert und in
sb.Length geschrieben , jetzt ist der Wert von
sb.Length 0. Dies führt dazu, dass die Methode wieder
null zurückgibt.
Ausgabe 15Ganz unerwartet wollte ich die
System.Configuration.ConfigurationProperty- Klasse verwenden. Nehmen Sie den Konstruktor mit den meisten Parametern:
public ConfigurationProperty( string name, Type type, object defaultValue, TypeConverter typeConverter, ConfigurationValidatorBase validator, ConfigurationPropertyOptions options, string description);
Sehen wir uns die Beschreibung des letzten Parameters an:
Die Konstruktorbeschreibung auf docs.microsoft.com sagt dasselbe. Schauen wir uns an, wie dieser Parameter im Konstruktorkörper verwendet wird:
public ConfigurationProperty(...., string description) { ConstructorInit(name, type, options, validator, typeConverter); SetDefaultValue(defaultValue); }
Und der Parameter wird nicht verwendet.
PVS-Studio Warnung :
V3117 Der Konstruktorparameter 'description' wird nicht verwendet. ConfigurationProperty.cs 62
Sie verwenden es wahrscheinlich nicht absichtlich, aber die Beschreibung des entsprechenden Parameters ist verwirrend.
Ausgabe 16Ich habe einen anderen ähnlichen Ort getroffen. Versuchen Sie, den Fehler selbst zu finden. Der Code des Konstruktors ist unten angegeben.
internal SectionXmlInfo( string configKey, string definitionConfigPath, string targetConfigPath, string subPath, string filename, int lineNumber, object streamVersion, string rawXml, string configSource, string configSourceStreamName, object configSourceStreamVersion, string protectionProviderName, OverrideModeSetting overrideMode, bool skipInChildApps) { ConfigKey = configKey; DefinitionConfigPath = definitionConfigPath; TargetConfigPath = targetConfigPath; SubPath = subPath; Filename = filename; LineNumber = lineNumber; StreamVersion = streamVersion; RawXml = rawXml; ConfigSource = configSource; ConfigSourceStreamName = configSourceStreamName; ProtectionProviderName = protectionProviderName; OverrideModeSetting = overrideMode; SkipInChildApps = skipInChildApps; }
PVS-Studio :
V3117 Constructor parameter 'configSourceStreamVersion' is not used. SectionXmlInfo.cs 16
, :
internal object ConfigSourceStreamVersion { set { } }
, . , / , .
Issue 17,
System.Runtime.WindowsRuntime.UI.Xaml NuGet .
public struct RepeatBehavior : IFormattable { .... public override string ToString() { return InternalToString(null, null); } .... }
PVS-Studio :
V3108 It is not recommended to return 'null' from 'ToSting()' method. RepeatBehavior.cs 113
, —
ToString null . - , ,
RepeatBehavior.ToString , - . , Microsoft.
, ,
ToString null —
InternalToString .
internal string InternalToString(string format, IFormatProvider formatProvider) { switch (_Type) { case RepeatBehaviorType.Forever: return "Forever"; case RepeatBehaviorType.Count: StringBuilder sb = new StringBuilder(); sb.AppendFormat( formatProvider, "{0:" + format + "}x", _Count); return sb.ToString(); case RepeatBehaviorType.Duration: return _Duration.ToString(); default: return null; } }
, ,
switch default ,
InternalToString null , ,
null ToString .
RepeatBehavior — ,
ToString — , .
RepeatBehavior ,
ToString , ,
_Type RepeatBehaviorType.Forever ,
RepeatBehaviorType.Count RepeatBehaviorType.Duration .
_Type — , :
public struct RepeatBehavior : IFormattable { .... private RepeatBehaviorType _Type; .... public RepeatBehaviorType Type { get { return _Type; } set { _Type = value; } } .... }
. , ,
RepeatBehaviorType .
public enum RepeatBehaviorType { Count, Duration, Forever }
,
RepeatBehaviorType — , .
switch . , , ,
default .
System.Runtime.WindowsRuntime.UI.Xaml ( 4.3.0) .
RepeatBehavior behavior = new RepeatBehavior() { Type = (RepeatBehaviorType)666 }; Console.WriteLine(behavior.ToString() is null);
True ,
ToString null , ..
_Type case default . , , .
, ,
docs.microsoft.com , ,
null .
Issue 18System.Private.DataContractSerialization .
private static class CharType { public const byte None = 0x00; public const byte FirstName = 0x01; public const byte Name = 0x02; public const byte Whitespace = 0x04; public const byte Text = 0x08; public const byte AttributeText = 0x10; public const byte SpecialWhitespace = 0x20; public const byte Comment = 0x40; } private static byte[] s_charType = new byte[256] { .... CharType.None, CharType.None| CharType.Comment| CharType.Comment| CharType.Whitespace| CharType.Text| CharType.SpecialWhitespace, CharType.None| CharType.Comment| CharType.Comment| CharType.Whitespace| CharType.Text| CharType.SpecialWhitespace, CharType.None, CharType.None, CharType.None| CharType.Comment| CharType.Comment| CharType.Whitespace, CharType.None, .... };
PVS-Studio :
- V3001 There are identical sub-expressions 'CharType.Comment' to the left and to the right of the '|' Betreiber. XmlUTF8TextReader.cs 56
- V3001 There are identical sub-expressions 'CharType.Comment' to the left and to the right of the '|' Betreiber. XmlUTF8TextReader.cs 58
- V3001 There are identical sub-expressions 'CharType.Comment' to the left and to the right of the '|' Betreiber. XmlUTF8TextReader.cs 64
CharType.Comment| CharType.Comment . ,
(CharType.Comment | CharType.Comment) == CharType.Comment . ,
CharType.Comment , .
Issue 19Wir fahren fort.
XmlBinaryWriterSession.TryAdd docs.microsoft.com — "
XmlBinaryWriterSession.TryAdd(XmlDictionaryString, Int32) Method ":
Returns: true if the string could be added; otherwise, false.:
public virtual bool TryAdd(XmlDictionaryString value, out int key) { IntArray keys; if (value == null) throw System.Runtime .Serialization .DiagnosticUtility .ExceptionUtility .ThrowHelperArgumentNull(nameof(value)); if (_maps.TryGetValue(value.Dictionary, out keys)) { key = (keys[value.Key] - 1); if (key != -1) {
PVS-Studio :
V3009 It's odd that this method always returns one and the same value of 'true'. XmlBinaryWriterSession.cs 29
,
true , ,
false .
Issue 20, —
false :
internal virtual bool OnHandleReference(....) { if (xmlWriter.depth < depthToCheckCyclicReference) return false; if (canContainCyclicReference) { if (_byValObjectsInScope.Contains(obj)) throw ....; _byValObjectsInScope.Push(obj); } return false; }
PVS-Studio :
V3009 It's odd that this method always returns one and the same value of 'false'. XmlObjectSerializerWriteContext.cs 415
, ! , , — , , , …
, , . :) :)
Issue 21System.Security.Cryptography.Algorithms .
public override byte[] GenerateMask(byte[] rgbSeed, int cbReturn) { using (HashAlgorithm hasher = (HashAlgorithm)CryptoConfig.CreateFromName(_hashNameValue)) { byte[] rgbCounter = new byte[4]; byte[] rgbT = new byte[cbReturn]; uint counter = 0; for (int ib = 0; ib < rgbT.Length;) {
PVS-Studio :
V3080 Possible null dereference. Consider inspecting 'hasher'. PKCS1MaskGenerationMethod.cs 37
,
hasher.TransformBlock hasher null ,
NullReferenceException . .
, ,
hasher null ,
CreateFromName .
public static object CreateFromName(string name) { return CreateFromName(name, null); }
— .
CreateFromName , .
public static object CreateFromName(string name, params object[] args) { .... if (retvalType == null) { return null; } .... if (cons == null) { return null; } .... if (candidates.Count == 0) { return null; } .... if (rci == null || typeof(Delegate).IsAssignableFrom(rci.DeclaringType)) { return null; } .... return retval; }
, ,
null . , , , ,
NullReferenceException .
— , . . .
public class PKCS1MaskGenerationMethod : ....
:
1, 3 .
public . , — .
2 . — , — , . , .
4 .
CreateFromName null — , .
5, 6 .
cbReturn > 0 (, , ).
cbReturn > 0 ib < rgbT.Length .
7 .
Helpres.ConvertIntToByteArray .
, , , :
- rgbCeed — new byte[] { 0, 1, 2, 3 };
- cbReturn — 42.
, «»
CryptoConfig.CreateFromName ,
_hashNameValue . , , - :
public string HashName { get { return _hashNameValue; } set { _hashNameValue = value ?? DefaultHash; } }
''
HashName ( —
_hashNameValue ),
null CreateFromName . (, ), .
,
NullReferenceException , :
PKCS1MaskGenerationMethod tempObj = new PKCS1MaskGenerationMethod(); tempObj.HashName = "Dummy"; tempObj.GenerateMask(new byte[] { 1, 2, 3 }, 42);
, :
NuGet 4.3.1.
, , docs.microsoft.com — "
PKCS1MaskGenerationMethod.GenerateMask(Byte[], Int32) Method ".
, 2 «» :
OutOfMemoryException .
NullReferenceException rgbSeed.Length . ,
hasher ,
rgbSeed.Length .
Issue 22.
public class SignatureDescription { .... public string FormatterAlgorithm { get; set; } public string DeformatterAlgorithm { get; set; } public SignatureDescription() { } .... public virtual AsymmetricSignatureDeformatter CreateDeformatter( AsymmetricAlgorithm key) { AsymmetricSignatureDeformatter item = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm); item.SetKey(key);
PVS-Studio :
- V3080 Possible null dereference. Consider inspecting 'item'. SignatureDescription.cs 31
- V3080 Possible null dereference. Consider inspecting 'item'. SignatureDescription.cs 38
,
FormatterAlgorithm DeformatterAlgorithm ,
CryptoConfig.CreateFromName null CreateDeformatter CreateFormatter . ,
SetKey NullReferenceException . , , :
SignatureDescription signature = new SignatureDescription() { DeformatterAlgorithm = "Dummy", FormatterAlgorithm = "Dummy" }; signature.CreateDeformatter(null);
CreateDeformatter ,
CreateFormatter NullReferenceException .
Issue 23System.Private.Xml .
public override void WriteBase64(byte[] buffer, int index, int count) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteBase64(buffer, index, count); else _wrapped.WriteBase64(buffer, index, count); }
PVS-Studio :
V3004 The 'then' statement is equivalent to the 'else' statement. QueryOutputWriterV1.cs 242
,
then else if . , ,
if .
Issue 24 internal void Depends(XmlSchemaObject item, ArrayList refs) { .... if (content is XmlSchemaSimpleTypeRestriction) { baseType = ((XmlSchemaSimpleTypeRestriction)content).BaseType; baseName = ((XmlSchemaSimpleTypeRestriction)content).BaseTypeName; } else if (content is XmlSchemaSimpleTypeList) { .... } else if (content is XmlSchemaSimpleTypeRestriction) { baseName = ((XmlSchemaSimpleTypeRestriction)content).BaseTypeName; } else if (t == typeof(XmlSchemaSimpleTypeUnion)) { .... } .... }
PVS-Studio :
V3003 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 381, 396. ImportContext.cs 381
if-else-if —
content is XmlSchemaSimpleTypeRestriction . —
then - . ,
then - ( ), , , .
Issue 25, .
public bool MatchesXmlType(IList<XPathItem> seq, int indexType) { XmlQueryType typBase = GetXmlType(indexType); XmlQueryCardinality card; switch (seq.Count) { case 0: card = XmlQueryCardinality.Zero; break; case 1: card = XmlQueryCardinality.One; break; default: card = XmlQueryCardinality.More; break; } if (!(card <= typBase.Cardinality)) return false; typBase = typBase.Prime; for (int i = 0; i < seq.Count; i++) { if (!CreateXmlType(seq[0]).IsSubtypeOf(typBase)) return false; } return true; }
— !
— PVS-Studio :
V3102 Suspicious access to element of 'seq' object by a constant index inside a loop. XmlQueryRuntime.cs 738
for ,
i < seq.Count . ,
seq . (
seq[i] ), — (
seq[0] ).
Issue 26, .
public override void WriteValue(string value) { WriteValue(value); }
PVS-Studio :
V3110 Possible infinite recursion inside 'WriteValue' method. XmlAttributeCache.cs 166
, .
Issue 27 public IList<XPathNavigator> DocOrderDistinct(IList<XPathNavigator> seq) { if (seq.Count <= 1) return seq; XmlQueryNodeSequence nodeSeq = (XmlQueryNodeSequence)seq; if (nodeSeq == null) nodeSeq = new XmlQueryNodeSequence(seq); return nodeSeq.DocOrderDistinct(_docOrderCmp); }
PVS-Studio :
V3095 The 'seq' object was used before it was verified against null. Check lines: 880, 884. XmlQueryRuntime.cs 880
null , -
Count NullReferenceException .
nodeSeq ,
seq , — .
seq —
null , - .
seq —
null , :
- InvalidCastException , ;
- , nodeSeq , null .
Issue 284 , . , , .
PVS-Studio :
- V3117 Constructor parameter 'securityUrl' is not used. XmlSecureResolver.cs 15
- V3117 Constructor parameter 'strdata' is not used. XmlEntity.cs 18
- V3117 Constructor parameter 'location' is not used. Compilation.cs 58
- V3117 Constructor parameter 'access' is not used. XmlSerializationILGen.cs 38
( , ). Was? . , .
public XmlSecureResolver(XmlResolver resolver, string securityUrl) { _resolver = resolver; }
, docs.microsoft.com — "
XmlSecureResolver Constructors "
securityUrl :
The URL used to create the PermissionSet that will be applied to the underlying XmlResolver. The XmlSecureResolver calls PermitOnly() on the created PermissionSet before calling GetEntity(Uri, String, Type) on the underlying XmlResolver.Issue 29System.Private.Uri , Microsoft
ToString . "
Object.ToString Method ":
Your ToString() override should not throw an exception .:
public override string ToString() { if (_username.Length == 0 && _password.Length > 0) { throw new UriFormatException(SR.net_uri_BadUserPassword); } .... }
PVS-Studio :
V3108 It is not recommended to throw exceptions from 'ToSting()' method. UriBuilder.cs 406
,
UserName Password _username _password ,
ToString , . :
UriBuilder uriBuilder = new UriBuilder() { UserName = String.Empty, Password = "Dummy" }; String stringRepresentation = uriBuilder.ToString(); Console.WriteLine(stringRepresentation);
, — , docs.microsoft.com — "
UriBuilder.ToString Method ".
Issue 30,
System.Data.Common .
private ArrayList _tables; private DataTable GetTable(string tableName, string ns) { .... if (_tables.Count == 0) return (DataTable)_tables[0]; .... }
PVS-Studio :
V3106 Possibly index is out of bound. The '0' index is pointing beyond '_tables' bound. XMLDiffLoader.cs 277
? , ?
ArgumentOutOfRangeException ? , , . , .
Issue 31 internal XmlNodeOrder ComparePosition(XPathNodePointer other) { RealFoliate(); other.RealFoliate(); Debug.Assert(other != null); .... }
PVS-Studio :
V3095 The 'other' object was used before it was verified against null. Check lines: 1095, 1096. XPathNodePointer.cs 1095
other != null Debug.Assert ,
ComparePosition null . , .
other RealFoliate . ,
other null ,
NullReferenceException Assert .
Issue 32 private PropertyDescriptorCollection GetProperties(Attribute[] attributes) { .... foreach (Attribute attribute in attributes) { Attribute attr = property.Attributes[attribute.GetType()]; if ( (attr == null && !attribute.IsDefaultAttribute()) || !attr.Match(attribute)) { match = false; break; } } .... }
PVS-Studio :
V3080 Possible null dereference. Consider inspecting 'attr'. DbConnectionStringBuilder.cs 534
if .
Match — .
attr == null ,
null — () . , || ,
attr —
null ,
NullReferenceException .
, :
- attr — null . &&.
- !attribute.IsDefaultAttribute() — false . && — false .
- || false , .
- attr — null , Match .
Issue 33 private int ReadOldRowData( DataSet ds, ref DataTable table, ref int pos, XmlReader row) { .... if (table == null) { row.Skip();
PVS-Studio :
V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless XMLDiffLoader.cs 301
if , —
table == null . then- — -1, — .
table . , .
Issue 34System.ComponentModel.TypeConverter . , :
Removes the last character from the formatted string. (Remove last character in virtual string). On exit the out param contains the position where the operation was actually performed. This position is relative to the test string. The MaskedTextResultHint out param gives more information about the operation result. Returns true on success, false otherwise.: ,
true , —
false . , .
public bool Remove(out int testPosition, out MaskedTextResultHint resultHint) { .... if (lastAssignedPos == INVALID_INDEX) { .... return true;
PVS-Studio :
V3009 It's odd that this method always returns one and the same value of 'true'. MaskedTextProvider.cs 1529
, —
true .
Issue 35 public void Clear() { if (_table != null) { .... } if (_table.fInitInProgress && _delayLoadingConstraints != null) { .... } .... }
PVS-Studio :
V3125 The '_table' object was used after it was verified against null. Check lines: 437, 423. ConstraintCollection.cs 437
_table != null —
_table null . , .
_table null —
_table .fInitInProgress .
Issue 36,
System.Runtime.Serialization.Formatters .
private void Write(....) { .... if (memberNameInfo != null) { .... _serWriter.WriteObjectEnd(memberNameInfo, typeNameInfo); } else if ((objectInfo._objectId == _topId) && (_topName != null)) { _serWriter.WriteObjectEnd(topNameInfo, typeNameInfo); .... } else if (!ReferenceEquals(objectInfo._objectType, Converter.s_typeofString)) { _serWriter.WriteObjectEnd(typeNameInfo, typeNameInfo); } }
PVS-Studio :
V3038 The argument was passed to method several times. It is possible that other argument should be passed instead. BinaryObjectWriter.cs 262
_serWriter.WriteObjectEnd —
typeNameInfo . , . ,
WriteObjectEnd .
internal void WriteObjectEnd(NameInfo memberNameInfo, NameInfo typeNameInfo) { }
… . :) :)
Issue 37 internal void WriteSerializationHeader( int topId, int headerId, int minorVersion, int majorVersion) { var record = new SerializationHeaderRecord( BinaryHeaderEnum.SerializedStreamHeader, topId, headerId, minorVersion, majorVersion); record.Write(this); }
, , . , .
PVS-Studio :
V3066 Possible incorrect order of arguments passed to 'SerializationHeaderRecord' constructor: 'minorVersion' and 'majorVersion'. BinaryFormatterWriter.cs 111
SerializationHeaderRecord .
internal SerializationHeaderRecord( BinaryHeaderEnum binaryHeaderEnum, int topId, int headerId, int majorVersion, int minorVersion) { _binaryHeaderEnum = binaryHeaderEnum; _topId = topId; _headerId = headerId; _majorVersion = majorVersion; _minorVersion = minorVersion; }
,
majorVersion ,
minorVersion ;
minorVersion ,
majorVersion . . ( ?) — , .
Issue 38 internal ObjectManager( ISurrogateSelector selector, StreamingContext context, bool checkSecurity, bool isCrossAppDomain) { _objects = new ObjectHolder[DefaultInitialSize]; _selector = selector; _context = context; _isCrossAppDomain = isCrossAppDomain; }
PVS-Studio :
V3117 Constructor parameter 'checkSecurity' is not used. ObjectManager.cs 33
checkSecurity . . , , , .
Issue 39, . 1 1 . :
:
private void EnlargeArray() { int newLength = _values.Length * 2; if (newLength < 0) { if (newLength == int.MaxValue) { throw new SerializationException(SR.Serialization_TooManyElements); } newLength = int.MaxValue; } FixupHolder[] temp = new FixupHolder[newLength]; Array.Copy(_values, 0, temp, 0, _count); _values = temp; }
PVS-Studio :
- V3022 Expression 'newLength == int.MaxValue' is always false. ObjectManager.cs 1423
- V3022 Expression 'newLength == int.MaxValue' is always false. ObjectManager.cs 1511
- V3022 Expression 'newLength == int.MaxValue' is always false. ObjectManager.cs 1558
, —
temp (
FixupHolder ,
long object ). - copy-paste…
Issue 40System.Data.Odbc .
public string UnquoteIdentifier(....) { .... if (!string.IsNullOrEmpty(quotePrefix) || quotePrefix != " ") { .... } .... }
PVS-Studio :
V3022 Expression '!string.IsNullOrEmpty(quotePrefix) || quotePrefix != " "' is always true. OdbcCommandBuilder.cs 338
,
true . . ,
quotePrefix — . .
||, ,
true , ( )
true . . ,
false . , ,
true , —
false ,
true .
, ,
string.IsNullOrEmpty(quotePrefix) —
true , , :
- quotePrefix == null ;
- quotePrefix.Length == 0 .
quotePrefix != " " , . , —
true ,
quotePrefix .
Issue 41:
private sealed class PendingGetConnection { public PendingGetConnection( long dueTime, DbConnection owner, TaskCompletionSource<DbConnectionInternal> completion, DbConnectionOptions userOptions) { DueTime = dueTime; Owner = owner; Completion = completion; } public long DueTime { get; private set; } public DbConnection Owner { get; private set; } public TaskCompletionSource<DbConnectionInternal> Completion { get; private set; } public DbConnectionOptions UserOptions { get; private set; } }
PVS-Studio :
V3117 Constructor parameter 'userOptions' is not used. DbConnectionPool.cs 26
, —
userOptions , , . , .
Issue 42, 2 . .
private DataTable ExecuteCommand(....) { .... foreach (DataRow row in schemaTable.Rows) { resultTable.Columns .Add(row["ColumnName"] as string, (Type)row["DataType"] as Type); } .... }
PVS-Studio :
- V3051 An excessive type cast. The object is already of the 'Type' type. DbMetaDataFactory.cs 176
- V3051 An excessive type cast. The object is already of the 'Type' type. OdbcMetaDataFactory.cs 1109
(Type)row[«DataType»] as Type . , —
as .
row[«DataType»] —
null , ''
Add .
row[«DataType»] ,
Type ,
InvalidCastException . , ? Die Frage ist offen.
Issue 43System.Runtime.InteropServices.RuntimeInformation .
public static string FrameworkDescription { get { if (s_frameworkDescription == null) { string versionString = (string)AppContext.GetData("FX_PRODUCT_VERSION"); if (versionString == null) { .... versionString = typeof(object).Assembly .GetCustomAttribute< AssemblyInformationalVersionAttribute>() ?.InformationalVersion; .... int plusIndex = versionString.IndexOf('+'); .... } .... } .... } }
PVS-Studio :
V3105 The 'versionString' variable was used after it was assigned through null-conditional operator. NullReferenceException is possible. RuntimeInformation.cs 29
NullReferenceException IndexOf versionString . '?.',
NullReferenceException InfromationalVersion . ,
GetCustomAttribute<...> null , , —
IndexOf ,
versionString null .
Issue 44System.ComponentModel.Composition . 2 :
public static bool CanSpecialize(....) { .... object[] genericParameterConstraints = ....; GenericParameterAttributes[] genericParameterAttributes = ....;
PVS-Studio :
- V3125 The 'genericParameterConstraints' object was used after it was verified against null. Check lines: 603, 589. GenericSpecializationPartCreationInfo.cs 603
- V3125 The 'genericParameterAttributes' object was used after it was verified against null. Check lines: 604, 594. GenericSpecializationPartCreationInfo.cs 604
genericParameterAttributes != null genericParameterConstraints != null . ,
null — , .
null , — . , -
null , ? , ,
NullReferenceException .
Issue 45. , — , . NuGet prerelease ( 4.6.0-preview6.19303.8). , , :
LazyMemberInfo lazyMemberInfo = new LazyMemberInfo(); var eq = lazyMemberInfo.Equals(null); Console.WriteLine(eq);
Equals , docs.microsoft.com .NET Core, .NET Framework. ("
LazyMemberInfo.Equals(Object) Method ") — —
true false , .
:
, :
LazyMemberInfo lazyMemberInfo = new LazyMemberInfo(); var eq = lazyMemberInfo.Equals(typeof(String)); Console.WriteLine(eq);
.
, .
Equals .
public override bool Equals(object obj) { LazyMemberInfo that = (LazyMemberInfo)obj;
PVS-Studio :
V3115 Passing 'null' to 'Equals' method should not result in 'NullReferenceException'. LazyMemberInfo.cs 116
, ,
that._memberType . , , —
(LazyMemberInfo)obj . .
InvalidCastException , , .
NullReferenceException ? ,
LazyMemberInfo — , , .
null NullReferenceException . — . .
Issue 46- , ,
System.Drawing.Common ,
TriState .
public override bool Equals(object o) { TriState state = (TriState)o; return _value == state._value; }
PVS-Studio :
V3115 Passing 'null' to 'Equals' method should not result in 'NullReferenceException'. TriState.cs 53
, .
Issue 47System.Text.Json .
, ,
ToString null ? .
public override string ToString() { switch (TokenType) { case JsonTokenType.None: case JsonTokenType.Null: return string.Empty; case JsonTokenType.True: return bool.TrueString; case JsonTokenType.False: return bool.FalseString; case JsonTokenType.Number: case JsonTokenType.StartArray: case JsonTokenType.StartObject: {
null , .
PVS-Studio :
V3108 It is not recommended to return 'null' from 'ToSting()' method. JsonElement.cs 1460
GetString() . :
public string GetString() { CheckValidInstance(); return _parent.GetString(_idx, JsonTokenType.String); }
—
GetString :
internal string GetString(int index, JsonTokenType expectedType) { .... if (tokenType == JsonTokenType.Null) { return null; } .... }
,
null — ,
ToString .
Issue 48:
internal JsonPropertyInfo CreatePolymorphicProperty(....) { JsonPropertyInfo runtimeProperty = CreateProperty(property.DeclaredPropertyType, runtimePropertyType, property.ImplementedPropertyType, property?.PropertyInfo, Type, options); property.CopyRuntimeSettingsTo(runtimeProperty); return runtimeProperty; }
PVS-Studio :
V3042 Possible NullReferenceException. The '?.' and '.' operators are used for accessing members of the 'property' object JsonClassInfo.AddProperty.cs 179
CreateProperty property :
property.DeclaredPropertyType ,
property.ImplementedPropertyType ,
property?.PropertyInfo . , '?.'.
property null , ,
NullReferenceException .
Issue 49System.Security.Cryptography.Xml , . copy-paste, .
:
public void Write(StringBuilder strBuilder, DocPosition docPos, AncestralNamespaceContextManager anc) { docPos = DocPosition.BeforeRootElement; foreach (XmlNode childNode in ChildNodes) { if (childNode.NodeType == XmlNodeType.Element) { CanonicalizationDispatcher.Write( childNode, strBuilder, DocPosition.InRootElement, anc); docPos = DocPosition.AfterRootElement; } else { CanonicalizationDispatcher.Write(childNode, strBuilder, docPos, anc); } } }
:
public void WriteHash(HashAlgorithm hash, DocPosition docPos, AncestralNamespaceContextManager anc) { docPos = DocPosition.BeforeRootElement; foreach (XmlNode childNode in ChildNodes) { if (childNode.NodeType == XmlNodeType.Element) { CanonicalizationDispatcher.WriteHash( childNode, hash, DocPosition.InRootElement, anc); docPos = DocPosition.AfterRootElement; } else { CanonicalizationDispatcher.WriteHash(childNode, hash, docPos, anc); } } }
PVS-Studio :
- V3061 Parameter 'docPos' is always rewritten in method body before being used. CanonicalXmlDocument.cs 37
- V3061 Parameter 'docPos' is always rewritten in method body before being used. CanonicalXmlDocument.cs 54
docPos , , , , , .
Issue 50System.Data.SqlClient .
private bool IsBOMNeeded(MetaType type, object value) { if (type.NullableType == TdsEnums.SQLXMLTYPE) { Type currentType = value.GetType(); if (currentType == typeof(SqlString)) { if (!((SqlString)value).IsNull && ((((SqlString)value).Value).Length > 0)) { if ((((SqlString)value).Value[0] & 0xff) != 0xff) return true; } } else if ((currentType == typeof(string)) && (((String)value).Length > 0)) { if ((value != null) && (((string)value)[0] & 0xff) != 0xff) return true; } else if (currentType == typeof(SqlXml)) { if (!((SqlXml)value).IsNull) return true; } else if (currentType == typeof(XmlDataFeed)) { return true;
PVS-Studio :
V3095 The 'value' object was used before it was verified against null. Check lines: 8696, 8708. TdsParser.cs 8696
value != null . , ,
value .
value null — .
Issue 51, , .
protected virtual TDSMessageCollection CreateQueryResponse(....) { .... if (....) { .... } else if ( lowerBatchText.Contains("name") && lowerBatchText.Contains("state") && lowerBatchText.Contains("databases") && lowerBatchText.Contains("db_name"))
PVS-Studio :
V3053 An excessive expression. Examine the substrings 'name' and 'db_name'. QueryEngine.cs 151
,
lowerBatchText.Contains(«name») lowerBatchText.Contains(«db_name») . ,
«db_name» ,
«name» .
«name» ,
«db_name» . ,
lowerBatchText.Contains(«name») . ,
«name» .
Issue 52System.Net.Requests .
protected override PipelineInstruction PipelineCallback( PipelineEntry entry, ResponseDescription response, ....) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Command:{entry?.Command} Description:{response?.StatusDescription}");
PVS-Studio :
V3125 The 'entry' object was used after it was verified against null. Check lines: 270, 227. FtpControlStream.cs 270
entry?.Command response?.Description . '.' '?.',
NullReferenceException , -
null . . , ,
null response ( ,
response == null ),
entry . ,
entry —
null , ,
entry.Command ( '.', '?.') .
, — , , .
? . :) :)
Issue 53-
System.Collections.Immutable .
System.Collections.Immutable.ImmutableArray<T> .
IStructuralEquatable.Equals IStructuralComparable.CompareTo .
IStructuralEquatable.Equals . , , :
bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { var self = this; Array otherArray = other as Array; if (otherArray == null) { var theirs = other as IImmutableArray; if (theirs != null) { otherArray = theirs.Array; if (self.array == null && otherArray == null) { return true; } else if (self.array == null) { return false; } } } IStructuralEquatable ours = self.array; return ours.Equals(otherArray, comparer); }
? — , . :) :)
PVS-Studio :
V3125 The 'ours' object was used after it was verified against null. Check lines: 1212, 1204. ImmutableArray_1.cs 1212
Equals ours ,
return , ,
NullReferenceException . ? , .
bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { .... if (....) { .... if (....) { .... if (self.array == null && otherArray == null) { .... } else if (self.array == null) { .... } } } IStructuralEquatable ours = self.array; return ours.Equals(otherArray, comparer); }
,
ours self.array .
self.array == null . ,
self.array ,
ours ,
null . , . ? . .
bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { var self = this;
1 .
self.array == this.array (-
self = this ). ,
this.array == null .
2 .
if , , .
if , ,
other Array other null .
as otherArray ,
if .
3 . .
if (,
theirs != null ).
then -, 5
self.array == null 4. ,
if 3, :
- other null ;
- other IImmutableArray .
5 .
self.array == null , , ,
NullReferenceException .
, .
:
this.array — null .
— :
- other — null ;
- other Array ;
- other Array , IImmutableArray .
array — , :
internal T[] array;
ImmutableArray<T> — , ( ),
array , —
null . , .
, , , .
, . , , , .
1 .
var comparer = EqualityComparer<String>.Default; ImmutableArray<String> immutableArray = new ImmutableArray<string>(); ((IStructuralEquatable)immutableArray).Equals(null, comparer);
2 .
var comparer = EqualityComparer<String>.Default; ImmutableArray<String> immutableArray = new ImmutableArray<string>(); ((IStructuralEquatable)immutableArray).Equals(new string[] { }, comparer);
3 .
var comparer = EqualityComparer<String>.Default; ImmutableArray<String> immutableArray = new ImmutableArray<string>(); ((IStructuralEquatable)immutableArray).Equals(typeof(Object), comparer);
, .
Issue 54, , . :) . , .
int IStructuralComparable.CompareTo(object other, IComparer comparer) { var self = this; Array otherArray = other as Array; if (otherArray == null) { var theirs = other as IImmutableArray; if (theirs != null) { otherArray = theirs.Array; if (self.array == null && otherArray == null) { return 0; } else if (self.array == null ^ otherArray == null) { throw new ArgumentException( SR.ArrayInitializedStateNotEqual, nameof(other)); } } } if (otherArray != null) { IStructuralComparable ours = self.array; return ours.CompareTo(otherArray, comparer);
PVS-Studio :
V3125 The 'ours' object was used after it was verified against null. Check lines: 1265, 1251. ImmutableArray_1.cs 1265
, .
:
Object other = ....; var comparer = Comparer<String>.Default; ImmutableArray<String> immutableArray = new ImmutableArray<string>(); ((IStructuralComparable)immutableArray).CompareTo(other, comparer);
, ,
NullReferenceException .
:
other —
new String[]{ } ;
:
, , .
Issue 55System.Net.HttpListener , , , . copy-paste. , , :
public override IAsyncResult BeginRead(byte[] buffer, ....) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this); NetEventSource.Info(this, "buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset); } if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } .... }
PVS-Studio :
V3095 The 'buffer' object was used before it was verified against null. Check lines: 51, 53. HttpRequestStream.cs 51
ArgumentNullException buffer == null ,
null — . ,
NetEventSource.IsEnabled —
true ,
buffer —
null ,
NullReferenceException buffer.Length . ,
buffer == null .
PVS-Studio, :
- V3095 The 'buffer' object was used before it was verified against null. Check lines: 49, 51. HttpResponseStream.cs 49
- V3095 The 'buffer' object was used before it was verified against null. Check lines: 74, 75. HttpResponseStream.cs 74
Issue 56System.Transactions.Local .
internal override void EnterState(InternalTransaction tx) { if (tx._outcomeSource._isoLevel == IsolationLevel.Snapshot) { throw TransactionException.CreateInvalidOperationException( TraceSourceType.TraceSourceLtm, SR.CannotPromoteSnapshot, null, tx == null ? Guid.Empty : tx.DistributedTxId); } .... }
PVS-Studio :
V3095 The 'tx' object was used before it was verified against null. Check lines: 3282, 3285. TransactionState.cs 3282
InvalidOperationException .
tx ,
null ,
NullReferenceException tx.DistributedTxId . , ,
tx —
null ,
if tx —
tx._outcomeSource._isoLevel .
Issue 57System.Runtime.Caching .
internal void SetLimit(int cacheMemoryLimitMegabytes) { long cacheMemoryLimit = cacheMemoryLimitMegabytes; cacheMemoryLimit = cacheMemoryLimit << MEGABYTE_SHIFT; _memoryLimit = 0;
PVS-Studio :
V3022 Expression 'cacheMemoryLimit != 0 && _memoryLimit != 0' is always false. CacheMemoryMonitor.cs 250
, , —
cacheMemoryLimit != 0 && _memoryLimit != 0 —
false .
_memoryLimit 0 (
if ), &&
false , ,
false .
Issue 58System.Diagnostics.TraceSource .
public override object Pop() { StackNode n = _stack.Value; if (n == null) { base.Pop(); } _stack.Value = n.Prev; return n.Value; }
PVS-Studio :
V3125 The 'n' object was used after it was verified against null. Check lines: 115, 111. CorrelationManager.cs 115
. -
n == null ,
null — . —
NullReferenceException —
n.Prev .
n null ,
base.Pop() .
Issue 59System.Drawing.Primitives . . :
public static string ToHtml(Color c) { string colorString = string.Empty; if (c.IsEmpty) return colorString; if (ColorUtil.IsSystemColor(c)) { switch (c.ToKnownColor()) { case KnownColor.ActiveBorder: colorString = "activeborder"; break; case KnownColor.GradientActiveCaption: case KnownColor.ActiveCaption: colorString = "activecaption"; break; case KnownColor.AppWorkspace: colorString = "appworkspace"; break; case KnownColor.Desktop: colorString = "background"; break; case KnownColor.Control: colorString = "buttonface"; break; case KnownColor.ControlLight: colorString = "buttonface"; break; case KnownColor.ControlDark: colorString = "buttonshadow"; break; case KnownColor.ControlText: colorString = "buttontext"; break; case KnownColor.ActiveCaptionText: colorString = "captiontext"; break; case KnownColor.GrayText: colorString = "graytext"; break; case KnownColor.HotTrack: case KnownColor.Highlight: colorString = "highlight"; break; case KnownColor.MenuHighlight: case KnownColor.HighlightText: colorString = "highlighttext"; break; case KnownColor.InactiveBorder: colorString = "inactiveborder"; break; case KnownColor.GradientInactiveCaption: case KnownColor.InactiveCaption: colorString = "inactivecaption"; break; case KnownColor.InactiveCaptionText: colorString = "inactivecaptiontext"; break; case KnownColor.Info: colorString = "infobackground"; break; case KnownColor.InfoText: colorString = "infotext"; break; case KnownColor.MenuBar: case KnownColor.Menu: colorString = "menu"; break; case KnownColor.MenuText: colorString = "menutext"; break; case KnownColor.ScrollBar: colorString = "scrollbar"; break; case KnownColor.ControlDarkDark: colorString = "threeddarkshadow"; break; case KnownColor.ControlLightLight: colorString = "buttonhighlight"; break; case KnownColor.Window: colorString = "window"; break; case KnownColor.WindowFrame: colorString = "windowframe"; break; case KnownColor.WindowText: colorString = "windowtext"; break; } } else if (c.IsNamedColor) { if (c == Color.LightGray) {
-, … ? , , .
:
switch (c.ToKnownColor()) { .... case KnownColor.Control: colorString = "buttonface"; break; case KnownColor.ControlLight: colorString = "buttonface"; break; .... }
PVS-Studio :
V3139 Two or more case-branches perform the same actions. ColorTranslator.cs 302
, , - . , ,
case , . copy-paste , .
.
ToHtml «buttonface» , ():
- SystemColors.Control ;
- SystemColors.ControlLight .
ARGB, :
- SystemColors.Control — (255, 240, 240, 240) ;
- SystemColors.ControlLight — (255, 227, 227, 227) .
(
«buttonface» ) —
FromHtml ,
Control (255, 240, 240, 240) .
FromHtml ControlLight ? Ja , ( ) . :
s_htmlSysColorTable["threedhighlight"] = ColorUtil.FromKnownColor(KnownColor.ControlLight);
,
FromHtml ControlLight (255, 227, 227, 227) «threedhighlight» . ,
case KnownColor.ControlLight .
Issue 60System.Text.RegularExpressions .
internal virtual string TextposDescription() { var sb = new StringBuilder(); int remaining; sb.Append(runtextpos); if (sb.Length < 8) sb.Append(' ', 8 - sb.Length); if (runtextpos > runtextbeg) sb.Append(RegexCharClass.CharDescription(runtext[runtextpos - 1])); else sb.Append('^'); sb.Append('>'); remaining = runtextend - runtextpos; for (int i = runtextpos; i < runtextend; i++) { sb.Append(RegexCharClass.CharDescription(runtext[i])); } if (sb.Length >= 64) { sb.Length = 61; sb.Append("..."); } else { sb.Append('$'); } return sb.ToString(); }
PVS-Studio :
V3137 The 'remaining' variable is assigned but is not used by the end of the function. RegexRunner.cs 612
remaining - , . , - , , , . - .
Issue 61 public void AddRange(char first, char last) { _rangelist.Add(new SingleRange(first, last)); if (_canonical && _rangelist.Count > 0 && first <= _rangelist[_rangelist.Count - 1].Last) { _canonical = false; } }
PVS-Studio :
V3063 A part of conditional expression is always true if it is evaluated: _rangelist.Count > 0. RegexCharClass.cs 523
, —
_rangelist.Count > 0 —
true , . ,
_rangelist , , —
_rangelist.Add(....) — .
Issue 62V3128 System.Drawing.Common System.Transactions.Local .
private class ArrayEnumerator : IEnumerator { private object[] _array; private object _item; private int _index; private int _startIndex; private int _endIndex; public ArrayEnumerator(object[] array, int startIndex, int count) { _array = array; _startIndex = startIndex; _endIndex = _index + count; _index = _startIndex; } .... }
PVS-Studio :
V3128 The '_index' field is used before it is initialized in constructor. PrinterSettings.Windows.cs 1679
_endIndex —
_index , —
default(int) ,
0 .
_index . —
_index , .
Issue 63 internal class TransactionTable { .... private int _timerInterval; .... internal TransactionTable() {
PVS-Studio :
V3128 The '_timerInterval' field is used before it is initialized in constructor. TransactionTable.cs 151
.
_timerInterval (
default(int) )
_timer ,
_timerInterval .
Issue 64, . , .
copy-paste , .
private bool ProcessNotifyConnection(....) { .... WeakReference reference = (WeakReference)( LdapConnection.s_handleTable[referralFromConnection]); if ( reference != null && reference.IsAlive && null != ((LdapConnection)reference.Target)._ldapHandle) { .... } .... }
PVS-Studio () : VXXXX TODO_MESSAGE. LdapSessionOptions.cs 974
,
reference.IsAlive ,
WeakReference ,
reference.Target null . —
_ldapHandle NullReferenceException . , IsAlive Microsoft. docs.microsoft.com — "
WeakReference.IsAlive Property ":
Because an object could potentially be reclaimed for garbage collection immediately after the IsAlive property returns true, using this property is not recommended unless you are testing only for a false return value., ? Natürlich nicht! , . , , , , , . ( ), , , - . , , , .
,
V3022 V3063 . , :
String str = null; if (str == null) ....
, , .
lock statement this .. —
V3090 ; —
V3083 ; ,
IDisposable ,
Dispose /
Close —
V3072 ; .
( — , - ) , . , , . , - .
, , —
.
. — , . , , .
— , , , . , , .
, — . / , . , PVS-Studio.
Fazit
, — ! , . - , — .
, ,
PVS-Studio , . - —
support@viva64.com . :) :)
!
PS .NET Core
, ! — . , . , , — , , / (
).

, : Sergey Vasiliev.
Checking the .NET Core Libraries Source Code by the PVS-Studio Static Analyzer