Überprüfung des Quellcodes von .NET Core-Bibliotheken durch den statischen Analysator PVS-Studio

Bild 19

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 1

abstract 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.

Bild 1


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.

Bild 2


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.

Bild 3


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.

Bild 4


Ausgabe 4

Jetzt 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.

Bild 5

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:

Bild 6


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 5

Berü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:

Bild 7

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.

Bild 8

Ausgabe 6

Wir 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 7

Microsoft.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 8

Hier 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 .

Bild 9

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 9

Ein 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 10

In 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 11

Ich 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 12

Paket 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 13

Ein 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 ...

 // throws NRE when o is null protected static void NullCheck(object o) { if (o == null) { o.GetType(); } } 

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.

Bild 20

Ausgabe 14

Schauen 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:

Bild 11

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 ...

Bild 12

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 ...

Bild 13

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); // .... sb.Append(str.Trim()); sb.Append(','); } if (sb.Length > 0) sb.Length = sb.Length - 1; return sb.Length == 0 ? null : sb.ToString(); } 

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 15

Ganz 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:

 // description: // The description of the configuration entity. 

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 16

Ich 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 nullInternalToString .

 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 18

System.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, /* 9 (.) */ CharType.None| CharType.Comment| CharType.Comment| CharType.Whitespace| CharType.Text| CharType.SpecialWhitespace, /* A (.) */ CharType.None| CharType.Comment| CharType.Comment| CharType.Whitespace| CharType.Text| CharType.SpecialWhitespace, /* B (.) */ CharType.None, /* C (.) */ CharType.None, /* D (.) */ CharType.None| CharType.Comment| CharType.Comment| CharType.Whitespace, /* E (.) */ 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 19

Wir 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) { // If the key is already set, then something is wrong throw System.Runtime .Serialization .DiagnosticUtility .ExceptionUtility .ThrowHelperError( new InvalidOperationException( SR.XmlKeyAlreadyExists)); } key = Add(value.Value); keys[value.Key] = (key + 1); return true; } key = Add(value.Value); keys = AddKeys(value.Dictionary, value.Key + 1); keys[value.Key] = (key + 1); return true; } 

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

, ! , , — , , , …

Bild 21

, , . :) :)

Issue 21

System.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;) { // Increment counter -- up to 2^32 * sizeof(Hash) Helpers.ConvertIntToByteArray(counter++, rgbCounter); hasher.TransformBlock(rgbSeed, 0, rgbSeed.Length, rgbSeed, 0); hasher.TransformFinalBlock(rgbCounter, 0, 4); byte[] hash = hasher.Hash; hasher.Initialize(); Buffer.BlockCopy(hash, 0, rgbT, ib, Math.Min(rgbT.Length - ib, hash.Length)); ib += hasher.Hash.Length; } return rgbT; } } 

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 { .... public PKCS1MaskGenerationMethod() // <= 2 { _hashNameValue = DefaultHash; } .... public override byte[] GenerateMask(byte[] rgbSeed, int cbReturn) // <= 3 { using (HashAlgorithm hasher = (HashAlgorithm)CryptoConfig.CreateFromName(_hashNameValue)) // <= 4 { byte[] rgbCounter = new byte[4]; byte[] rgbT = new byte[cbReturn]; // <= 5 uint counter = 0; for (int ib = 0; ib < rgbT.Length;) // <= 6 { .... Helpers.ConvertIntToByteArray(counter++, rgbCounter); // <= 7 hasher.TransformBlock(rgbSeed, 0, rgbSeed.Length, rgbSeed, 0); .... } .... } } } 

:

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); 

, :

Bild 10


NuGet 4.3.1.

Bild 14


, , docs.microsoft.com — " PKCS1MaskGenerationMethod.GenerateMask(Byte[], Int32) Method ".

, 2 «» :

  • cbReturn ;
  • rgbSeed null .

OutOfMemoryException .

Bild 15

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); // <= return item; } public virtual AsymmetricSignatureFormatter CreateFormatter( AsymmetricAlgorithm key) { AsymmetricSignatureFormatter item = (AsymmetricSignatureFormatter) CryptoConfig.CreateFromName(FormatterAlgorithm); item.SetKey(key); // <= return item; } .... } 

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); // NRE signature.CreateFormatter(null); // NRE 

CreateDeformatter , CreateFormatter NullReferenceException .

Issue 23

System.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-ifcontent 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 , — . seqnull , - . seqnull , :

  • InvalidCastException , ;
  • , nodeSeq , null .

Issue 28

4 , . , , .

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 29

System.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 — () . , || , attrnull , NullReferenceException .

, :

  1. attrnull . &&.
  2. !attribute.IsDefaultAttribute()false . && — false .
  3. || false , .
  4. attrnull , Match .

Issue 33

 private int ReadOldRowData( DataSet ds, ref DataTable table, ref int pos, XmlReader row) { .... if (table == null) { row.Skip(); // need to skip this element if we dont know about it, // before returning -1 return -1; } .... if (table == null) throw ExceptionBuilder.DiffgramMissingTable( XmlConvert.DecodeName(row.LocalName)); .... } 

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 34

System.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; // nothing to remove. } .... 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.WriteObjectEndtypeNameInfo . , . , 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 . :

  • ;
  • copy-paste.

:

 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 40

System.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 43

System.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 44

System.ComponentModel.Composition . 2 :

 public static bool CanSpecialize(....) { .... object[] genericParameterConstraints = ....; GenericParameterAttributes[] genericParameterAttributes = ....; // if no constraints and attributes been specifed, anything can be created if ((genericParameterConstraints == null) && (genericParameterAttributes == null)) { return true; } if ((genericParameterConstraints != null) && (genericParameterConstraints.Length != partArity)) { return false; } if ((genericParameterAttributes != null) && (genericParameterAttributes.Length != partArity)) { return false; } for (int i = 0; i < partArity; i++) { if (!GenericServices.CanSpecialize( specialization[i], (genericParameterConstraints[i] as Type[]). CreateTypeSpecializations(specialization), genericParameterAttributes[i])) { return false; } } return true; } 

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 , .

:

Bild 16

, :

 LazyMemberInfo lazyMemberInfo = new LazyMemberInfo(); var eq = lazyMemberInfo.Equals(typeof(String)); Console.WriteLine(eq); 

.

Bild 17

, . Equals .

 public override bool Equals(object obj) { LazyMemberInfo that = (LazyMemberInfo)obj; // Difefrent member types mean different members if (_memberType != that._memberType) { return false; } // if any of the lazy memebers create accessors in a delay-loaded fashion, // we simply compare the creators if ((_accessorsCreator != null) || (that._accessorsCreator != null)) { return object.Equals(_accessorsCreator, that._accessorsCreator); } // we are dealing with explicitly passed accessors in both cases if(_accessors == null || that._accessors == null) { throw new Exception(SR.Diagnostic_InternalExceptionMessage); } return _accessors.SequenceEqual(that._accessors); } 

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 47

System.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 parent should have hit the None case Debug.Assert(_parent != null); return _parent.GetRawValueAsString(_idx); } case JsonTokenType.String: return GetString(); case JsonTokenType.Comment: case JsonTokenType.EndArray: case JsonTokenType.EndObject: default: Debug.Fail($"No handler for {nameof(JsonTokenType)}.{TokenType}"); return string.Empty; } } 

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 49

System.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 50

System.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; // Values will eventually converted to unicode string here } } return false; } 

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")) // SELECT [name], [state] FROM [sys].[databases] WHERE [name] = db_name() { // Delegate to current database response responseMessage = _PrepareDatabaseResponse(session); } .... } 

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 52

System.Net.Requests .

 protected override PipelineInstruction PipelineCallback( PipelineEntry entry, ResponseDescription response, ....) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Command:{entry?.Command} Description:{response?.StatusDescription}"); // null response is not expected if (response == null) return PipelineInstruction.Abort; .... if (entry.Command == "OPTS utf8 on\r\n") .... .... } 

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 . , entrynull , , entry.Command ( '.', '?.') .

, — , , .

Bild 23

? . :) :)

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 Array otherArray = other as Array; if (otherArray == null) // <= 2 { var theirs = other as IImmutableArray; if (theirs != null) // <= 3 { otherArray = theirs.Array; if (self.array == null && otherArray == null) { return true; } else if (self.array == null) // <= 4 { return false; } } IStructuralEquatable ours = self.array; // <= 5 return ours.Equals(otherArray, comparer); } 

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 .

— :

  • othernull ;
  • 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); 

, .

Bild 18

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); // <= } throw new ArgumentException(SR.ArrayLengthsNotEqual, nameof(other)); } 

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 .

: othernew String[]{ } ;

:

Bild 22

, , .

Issue 55

System.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.IsEnabledtrue , buffernull , 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 56

System.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 . , , txnull , if txtx._outcomeSource._isoLevel .

Issue 57

System.Runtime.Caching .

 internal void SetLimit(int cacheMemoryLimitMegabytes) { long cacheMemoryLimit = cacheMemoryLimitMegabytes; cacheMemoryLimit = cacheMemoryLimit << MEGABYTE_SHIFT; _memoryLimit = 0; // never override what the user specifies as the limit; // only call AutoPrivateBytesLimit when the user does not specify one. if (cacheMemoryLimit == 0 && _memoryLimit == 0) { // Zero means we impose a limit _memoryLimit = EffectiveProcessMemoryLimit; } else if (cacheMemoryLimit != 0 && _memoryLimit != 0) { // Take the min of "cache memory limit" and // the host's "process memory limit". _memoryLimit = Math.Min(_memoryLimit, cacheMemoryLimit); } else if (cacheMemoryLimit != 0) { // _memoryLimit is 0, but "cache memory limit" // is non-zero, so use it as the limit _memoryLimit = cacheMemoryLimit; } .... } 

PVS-Studio : V3022 Expression 'cacheMemoryLimit != 0 && _memoryLimit != 0' is always false. CacheMemoryMonitor.cs 250

, , — cacheMemoryLimit != 0 && _memoryLimit != 0false . _memoryLimit 0 ( if ), && false , , false .

Issue 58

System.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 — . — NullReferenceExceptionn.Prev . n null , base.Pop() .

Issue 59

System.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) { // special case due to mismatch between Html and enum spelling colorString = "LightGrey"; } else { colorString = c.Name; } } else { colorString = "#" + cRToString("X2", null) + cGToString("X2", null) + cBToString("X2", null); } return colorString; } 

-, … ? , , .

:

 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 60

System.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 > 0true , . , _rangelist , , — _rangelist.Add(....) — .

Issue 62

V3128 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() { // Create a timer that is initially disabled by specifing // an Infinite time to the first interval _timer = new Timer(new TimerCallback(ThreadTimer), null, Timeout.Infinite, _timerInterval); .... // Store the timer interval _timerInterval = 1 << TransactionTable.timerInternalExponent; .... } } 

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 / CloseV3072 ; .

( — , - ) , . , , . , - .

, , — .

. — , . , , .

— , , , . , , .

, — . / , . , PVS-Studio.

Fazit


, — ! , . - , — .

Bild 24

, , PVS-Studio , . - — support@viva64.com . :) :)

!

PS .NET Core


, ! — . , . , , — , , / ( ).



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

Source: https://habr.com/ru/post/de463537/


All Articles