PVS-Studio in den Clouds: Azure DevOps

Bild 9

Dies ist ein zweiter Artikel, der sich auf die Verwendung des PVS-Studio-Analysators in Cloud-CI-Systemen konzentriert. Dieses Mal betrachten wir die Plattform Azure DevOps - eine Cloud-CI \ CD-Lösung von Microsoft. Wir werden das ShareX-Projekt analysieren.

Wir brauchen drei Komponenten. Der erste ist der PVS-Studio-Analysator. Das zweite ist Azure DevOps, in das wir den Analysator integrieren werden. Das dritte ist das Projekt, das wir überprüfen werden, um die Fähigkeiten von PVS-Studio bei der Arbeit in einer Cloud zu demonstrieren. Also lass uns loslegen.

PVS-Studio ist ein statischer Code-Analysator zum Auffinden von Fehlern und Sicherheitsmängeln. Das Tool unterstützt die Analyse von C-, C ++ - und C # -Code.

Azure DevOps . Die Azure DevOps-Plattform enthält Tools wie Azure Pipeline, Azure Board, Azure Artifacts und andere, die das Erstellen von Software beschleunigen und deren Qualität verbessern.

ShareX ist eine kostenlose App, mit der Sie jeden Teil des Bildschirms erfassen und aufzeichnen können. Das Projekt ist in C # geschrieben und eignet sich hervorragend zur Darstellung der Konfiguration des Starts des statischen Analysators. Der Projektquellcode ist auf GitHub verfügbar .

Die Ausgabe des Befehls cloc für das ShareX-Projekt:
Sprache
Dateien
leer
Kommentar
Code
C #
696
20658
24423
102565
MSBuild-Skript
11
1
77
5859
Mit anderen Worten, das Projekt ist klein, aber völlig ausreichend, um die Arbeit von PVS-Studio zusammen mit der Cloud-Plattform zu demonstrieren.

Beginnen wir mit der Konfiguration


Um mit der Arbeit in Azure DevOps zu beginnen, folgen Sie dem Link und klicken Sie auf "Kostenlos mit GitHub starten".

Bild 2

Gewähren Sie der Microsoft-Anwendung Zugriff auf die GitHub-Kontodaten.

Bild 1

Sie müssen ein Microsoft-Konto erstellen, um Ihre Registrierung abzuschließen.

Bild 12

Erstellen Sie nach der Registrierung ein Projekt:

Bild 5

Als nächstes müssen wir zu "Pipelines" - "Builds" wechseln und eine neue Build-Pipeline erstellen.

Bild 8

Auf die Frage, wo sich unser Code befindet, antworten wir - GitHub.

Bild 13

Autorisieren Sie Azure Pipelines und wählen Sie das Repository mit dem Projekt aus, für das wir den Lauf des statischen Analysators konfigurieren.

Bild 7

Wählen Sie im Vorlagenauswahlfenster "Starter-Pipeline".

Bild 17

Wir können die statische Code-Analyse des Projekts auf zwei Arten ausführen: mithilfe von Microsoft-gehosteten oder selbst gehosteten Agenten.

Zunächst verwenden wir von Microsoft gehostete Agenten. Solche Agenten sind normale virtuelle Maschinen, die beim Ausführen unserer Pipeline gestartet werden. Sie werden entfernt, wenn die Aufgabe erledigt ist. Durch die Verwendung solcher Agenten können wir keine Zeit für deren Support und Aktualisierung verschwenden, sondern bestimmte Einschränkungen auferlegen, z. B. die Unfähigkeit, zusätzliche Software zu installieren, die zum Erstellen eines Projekts verwendet wird.

Ersetzen wir die vorgeschlagene Standardkonfiguration durch die folgende für die Verwendung von von Microsoft gehosteten Agenten:

# Setting up run triggers # Run only for changes in the master branch trigger: - master # Since the installation of random software in virtual machines # is prohibited, we'll use a Docker container, # launched on a virtual machine with Windows Server 1803 pool: vmImage: 'win1803' container: microsoft/dotnet-framework:4.7.2-sdk-windowsservercore-1803 steps: # Download the analyzer distribution - task: PowerShell@2 inputs: targetType: 'inline' script: 'Invoke-WebRequest -Uri https://files.viva64.com/PVS-Studio_setup.exe -OutFile PVS-Studio_setup.exe' - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | # Restore the project and download dependencies nuget restore .\ShareX.sln # Create the directory, where files with analyzer reports will be saved md .\PVSTestResults # Install the analyzer PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /COMPONENTS=Core # Create the file with configuration and license information "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" credentials -u $(PVS_USERNAME) -n $(PVS_KEY) # Run the static analyzer and convert the report in html. "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\ShareX.sln -o .\PVSTestResults\ShareX.plog "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t html -o .\PVSTestResults\ .\PVSTestResults\ShareX.plog # Save analyzer reports - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults 

Hinweis: Gemäß der Dokumentation muss der verwendete Container im Image der virtuellen Maschine zwischengespeichert werden. Zum Zeitpunkt des Schreibens des Artikels funktioniert er jedoch nicht und der Container wird bei jedem Start der Aufgabe heruntergeladen, was sich negativ auswirkt der Ausführungszeitpunkt.

Speichern Sie die Pipeline und erstellen Sie Variablen, die zum Erstellen der Lizenzdatei verwendet werden. Öffnen Sie dazu das Pipeline-Bearbeitungsfenster und klicken Sie oben rechts auf "Variablen".

Bild 14

Fügen Sie dann zwei Variablen hinzu - PVS_USERNAME und PVS_KEY , die den Benutzernamen bzw. den Lizenzschlüssel enthalten. Vergessen Sie beim Erstellen der Variablen PVS_KEY nicht, "Diesen Wert geheim halten" auszuwählen, um die Werte der Variablen mit einem 2048-Bit-RSA-Schlüssel zu verschlüsseln und die Ausgabe des Variablenwerts im Aufgabenleistungsprotokoll zu unterdrücken.

Bild 15

Speichern Sie Variablen und führen Sie die Pipeline aus, indem Sie auf "Ausführen" klicken.

Die zweite Option zum Ausführen der Analyse: Verwenden Sie einen selbst gehosteten Agenten. Wir können selbst gehostete Agenten selbst anpassen und verwalten. Solche Agenten bieten mehr Möglichkeiten zur Installation von Software, die zum Erstellen und Testen unseres Softwareprodukts erforderlich ist.

Bevor Sie solche Agenten verwenden, müssen Sie sie gemäß den Anweisungen konfigurieren und den statischen Analysator installieren und konfigurieren .

Um die Aufgabe auf einem selbst gehosteten Agenten auszuführen, ersetzen wir die vorgeschlagene Konfiguration durch die folgende:

 # Setting up triggers # Run the analysis for master-branch trigger: - master # The task is run on a self-hosted agent from the pool 'MyPool' pool: 'MyPool' steps: - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | # Restore the project and download dependencies nuget restore .\ShareX.sln # Create the directory where files with analyzer reports will be saved md .\PVSTestResults # Run the static analyzer and convert the report in html. "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\ShareX.sln -o .\PVSTestResults\ShareX.plog "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t html -o .\PVSTestResults\ .\PVSTestResults\ShareX.plog # Save analyzer reports - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults 

Sobald die Aufgabe abgeschlossen ist, können Sie das Archiv mit den Analyseberichten auf der Registerkarte "Zusammenfassung" herunterladen oder die Erweiterung "E- Mail senden" verwenden , mit der Sie E-Mails konfigurieren oder ein anderes praktisches Tool auf dem Marktplatz in Betracht ziehen können.

Bild 21

Analyseergebnisse


Schauen wir uns nun einige Fehler im getesteten Projekt ShareX an.

Übermäßige Überprüfungen

Beginnen wir zum Aufwärmen mit einfachen Fehlern im Code, nämlich mit redundanten Überprüfungen:

 private void PbThumbnail_MouseMove(object sender, MouseEventArgs e) { .... IDataObject dataObject = new DataObject(DataFormats.FileDrop, new string[] { Task.Info.FilePath }); if (dataObject != null) { Program.MainForm.AllowDrop = false; dragBoxFromMouseDown = Rectangle.Empty; pbThumbnail.DoDragDrop(dataObject, DragDropEffects.Copy | DragDropEffects.Move); Program.MainForm.AllowDrop = true; } .... } 

PVS-Studio-Warnung: V3022 [CWE-571] Der Ausdruck 'dataObject! = Null' ist immer wahr. TaskThumbnailPanel.cs 415

Achten wir auf die Überprüfung der dataObject- Variablen auf null . Warum ist es hier? dataObject kann in diesem Fall nicht null sein , da es durch eine Referenz auf ein erstelltes Objekt initialisiert wird. Infolgedessen haben wir eine übermäßige Überprüfung. Kritisch? Nein, nein. Sieht prägnant aus? Nein, nein. Diese Überprüfung ist eindeutig besser zu entfernen, um den Code nicht zu überladen.

Schauen wir uns ein weiteres Codefragment an, das wir auf ähnliche Weise kommentieren können:

 private static Image GetDIBImage(MemoryStream ms) { .... try { .... return new Bitmap(bmp); .... } finally { if (gcHandle != IntPtr.Zero) { GCHandle.FromIntPtr(gcHandle).Free(); } } .... } private static Image GetImageAlternative() { .... using (MemoryStream ms = dataObject.GetData(format) as MemoryStream) { if (ms != null) { try { Image img = GetDIBImage(ms); if (img != null) { return img; } } catch (Exception e) { DebugHelper.WriteException(e); } } } .... } 

PVS-Studio-Warnung: V3022 [CWE-571] Der Ausdruck 'img! = Null' ist immer wahr. ClipboardHelpers.cs 289

In der GetImageAlternative- Methode wird die Variable img überprüft, dass sie direkt nach dem Erstellen einer neuen Instanz der Bitmap- Klasse nicht null ist. Der Unterschied zum vorherigen Beispiel besteht darin, dass wir die GetDIBImage- Methode anstelle des Konstruktors verwenden, um die img- Variable zu initialisieren. Der Code-Autor schlägt vor, dass bei dieser Methode eine Ausnahme auftreten könnte, deklariert jedoch nur blocks try und schließlich das Auslassen von catch . Wenn eine Ausnahme auftritt, erhält die Aufrufermethode GetImageAlternative daher keinen Verweis auf ein Objekt vom Typ Bitmap , sondern muss die Ausnahme in einem eigenen catch- Block behandeln. In diesem Fall wird die Variable img nicht initialisiert und der Ausführungsthread erreicht nicht einmal die Prüfung img! = Null , sondern gelangt in den catch-Block. Folglich wies der Analysator auf eine übermäßige Überprüfung hin.

Betrachten wir das folgende Beispiel einer V3022- Warnung:

 private void btnCopyLink_Click(object sender, EventArgs e) { .... if (lvClipboardFormats.SelectedItems.Count == 0) { url = lvClipboardFormats.Items[0].SubItems[1].Text; } else if (lvClipboardFormats.SelectedItems.Count > 0) { url = lvClipboardFormats.SelectedItems[0].SubItems[1].Text; } .... } 

PVS-Studio-Warnung: V3022 [CWE-571] Der Ausdruck 'lvClipboardFormats.SelectedItems.Count> 0' ist immer wahr. AfterUploadForm.cs 155

Schauen wir uns den zweiten bedingten Ausdruck genauer an. Dort überprüfen wir den Wert der schreibgeschützten Count- Eigenschaft. Diese Eigenschaft zeigt die Anzahl der Elemente in der Instanz der Auflistung SelectedItems an . Die Bedingung wird nur ausgeführt, wenn die Count- Eigenschaft größer als Null ist. Es wäre alles in Ordnung, aber in der externen if- Anweisung Count ist bereits auf 0 geprüft. Die Instanz der SelectedItems- Auflistung kann nicht die Anzahl der Elemente kleiner als Null haben, daher ist Count entweder gleich oder größer als 0. Da wir haben Die Count- Prüfung für 0 wurde bereits in der ersten if- Anweisung durchgeführt, und sie war falsch. Es macht keinen Sinn, eine weitere Count- Prüfung zu schreiben, wenn sie im Zweig else größer als Null ist.

Das letzte Beispiel für eine V3022- Warnung ist das folgende Codefragment:

 private void DrawCursorGraphics(Graphics g) { .... int cursorOffsetX = 10, cursorOffsetY = 10, itemGap = 10, itemCount = 0; Size totalSize = Size.Empty; int magnifierPosition = 0; Bitmap magnifier = null; if (Options.ShowMagnifier) { if (itemCount > 0) totalSize.Height += itemGap; .... } .... } 

PVS-Studio-Warnung: V3022 Der Ausdruck 'itemCount> 0' ist immer falsch. RegionCaptureForm.cs 1100

Der Analysator hat festgestellt, dass die Bedingung itemCount> 0 immer falsch ist, da die Variable itemCount deklariert und gleichzeitig oben Null zugewiesen wird. Diese Variable wird bis zur Bedingung nirgendwo verwendet, daher hatte der Analysator Recht mit dem bedingten Ausdruck, dessen Wert immer falsch ist.

Nun, schauen wir uns jetzt etwas wirklich Faules an.

Der beste Weg, einen Fehler zu verstehen, besteht darin, einen Fehler zu visualisieren

Es scheint uns, dass an dieser Stelle ein ziemlich interessanter Fehler gefunden wurde:

 public static void Pixelate(Bitmap bmp, int pixelSize) { .... float r = 0, g = 0, b = 0, a = 0; float weightedCount = 0; for (int y2 = y; y2 < yLimit; y2++) { for (int x2 = x; x2 < xLimit; x2++) { ColorBgra color = unsafeBitmap.GetPixel(x2, y2); float pixelWeight = color.Alpha / 255; r += color.Red * pixelWeight; g += color.Green * pixelWeight; b += color.Blue * pixelWeight; a += color.Alpha * pixelWeight; weightedCount += pixelWeight; } } .... ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount)); .... } 

Ich möchte nicht alle Karten zeigen und enthüllen, was unser Analysator gefunden hat, also lassen Sie es uns für eine Weile beiseite legen.

Unter dem Namen der Methode lässt sich leicht erraten, was sie tut - Sie geben ihr ein Bild oder ein Fragment eines Bildes und es verpixelt es. Der Code der Methode ist ziemlich lang, daher werden wir ihn nicht vollständig zitieren, sondern nur versuchen, den Algorithmus zu erklären und zu erklären, welche Art von Fehler PVS-Studio gefunden hat.

Diese Methode empfängt zwei Parameter: ein Objekt vom Typ Bitmap und den Wert vom Typ int , der die Größe der Pixelierung angibt. Der Operationsalgorithmus ist recht einfach:

1) Teilen Sie das empfangene Bildfragment in Quadrate mit der Seite, die der Größe der Pixelierung entspricht. Wenn wir beispielsweise eine Pixelgröße von 15 haben, erhalten wir ein Quadrat mit 15 x 15 = 225 Pixel.

2) Ferner durchlaufen wir jedes Pixel in diesem Quadrat und akkumulieren die Werte der Felder Rot , Grün , Blau und Alpha in Zwischenvariablen. Davor multiplizieren wir den Wert der entsprechenden Farbe und des Alphakanals mit der pixelWeight- Variablen, die durch erhalten wird Teilen des Alpha- Werts durch 255 (die Alpha- Variable ist vom Bytetyp ). Auch beim Durchlaufen von Pixeln addieren wir die in pixelWeight geschriebenen Werte in die Variable weightedCount . Das Codefragment, das die obigen Aktionen ausführt, lautet wie folgt:

 ColorBgra color = unsafeBitmap.GetPixel(x2, y2); float pixelWeight = color.Alpha / 255; r += color.Red * pixelWeight; g += color.Green * pixelWeight; b += color.Blue * pixelWeight; a += color.Alpha * pixelWeight; weightedCount += pixelWeight; 

Beachten Sie übrigens, dass pixelWeight der weightedCount- Variablen keinen Wert für dieses Pixel hinzufügt, wenn der Wert der Alpha- Variablen Null ist. Das werden wir in Zukunft brauchen.

3) Nachdem wir alle Pixel im aktuellen Quadrat durchlaufen haben, können wir eine gemeinsame "durchschnittliche" Farbe für dieses Quadrat erstellen. Der Code dafür sieht wie folgt aus:

 ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount)); 

4) Wenn wir nun die endgültige Farbe erhalten und in die Variable meanColor geschrieben haben , können wir erneut jedes Pixel des Quadrats durchlaufen und ihm einen Wert von durchschnittlicher Farbe zuweisen .

5) Gehen Sie zurück zu Punkt 2, während wir nicht behandelte Quadrate haben.

Auch hier entspricht die Variable weightedCount nicht der Anzahl aller Pixel in einem Quadrat. Wenn ein Bild beispielsweise ein vollständig transparentes Pixel enthält (Nullwert im Alphakanal), ist die Variable pixelWeight für dieses Pixel Null ( 0/255 = 0). Daher wirkt sich dieses Pixel nicht auf die Bildung der Variable weightedCount aus . Es ist ziemlich logisch - es macht keinen Sinn, die Farben eines vollständig transparenten Pixels zu berücksichtigen.

Es scheint also alles vernünftig - die Pixelierung muss korrekt funktionieren. Und das tut es tatsächlich. Dies gilt nur nicht für PNG-Bilder, die Pixel mit Werten im Alphakanal unter 255 und ungleich Null enthalten. Beachten Sie das pixelige Bild unten:

Bild 3

Hast du die Pixelierung gesehen? Wir auch nicht. Okay, jetzt lassen Sie uns diese kleine Intrige enthüllen und erklären, wo genau sich der Fehler in dieser Methode versteckt. Der Fehler hat sich in die Zeile der pixelWeight- Variablenberechnung eingeschlichen:

 float pixelWeight = color.Alpha / 255; 

Tatsache ist, dass der Code-Autor beim Deklarieren der pixelWeight- Variablen als float angedeutet hat, dass er beim Teilen des Alpha- Felds durch 255 zusätzlich zu Null und Eins Bruchzahlen erhält. Hier verbirgt sich das Problem, da die Alpha- Variable vom Bytetyp ist . Wenn wir um 255 tauchen, erhalten wir einen ganzzahligen Wert. Erst danach wird es implizit in den Float- Typ umgewandelt, was bedeutet, dass der Bruchteil verloren geht.

Es ist leicht zu erklären, warum es unmöglich ist, PNG-Bilder mit etwas Transparenz zu pixelieren. Da für diese Pixel die Werte des Alphakanals im Bereich 0 <Alpha <255 liegen, ergibt die Alpha- Variable geteilt durch 255 immer 0. Daher werden auch die Werte der Variablen pixelWeight , r , g , b , a , weightedCount verwendet Immer 0. Daher hat unsere durchschnittliche Farbe in allen Kanälen Nullwerte: Rot - 0, Blau - 0, Grün - 0, Alpha - 0. Durch Malen eines Quadrats in dieser Farbe wird die ursprüngliche Farbe nicht geändert der Pixel, da die durchschnittliche Farbe absolut transparent ist. Um diesen Fehler zu beheben, müssen wir das Alpha- Feld nur explizit in den Float- Typ umwandeln . Die feste Version der Codezeile könnte folgendermaßen aussehen:

 float pixelWeight = (float)color.Alpha / 255; 

Nun, es ist höchste Zeit, die Nachricht von PVS-Studio für den falschen Code zu zitieren:

PVS-Studio-Warnung: V3041 [CWE-682] Der Ausdruck wurde implizit vom Typ 'int' in den Typ 'float' umgewandelt. Erwägen Sie die Verwendung eines expliziten Typgusses, um den Verlust eines Bruchteils zu vermeiden. Ein Beispiel: double A = (double) (X) / Y; ImageHelpers.cs 1119

Zum Vergleich zitieren wir den Screenshot eines wirklich pixeligen Bildes, das mit der korrigierten Anwendungsversion erhalten wurde:

Bild 6

Mögliche NullReferenceException

 public static bool AddMetadata(Image img, int id, string text) { .... pi.Value = bytesText; if (pi != null) { img.SetPropertyItem(pi); return true; } .... } 

PVS-Studio-Warnung: V3095 [CWE-476] Das ' pi' -Objekt wurde verwendet, bevor es gegen null verifiziert wurde. Überprüfen Sie die Zeilen: 801, 803. ImageHelpers.cs 801

Dieses Codefragment zeigt, dass der Autor erwartet hat, dass die pi- Variable null sein kann. Deshalb findet vor dem Aufrufen der Methode SetPropertyItem die Prüfung pi! = Null statt. Es ist seltsam, dass der Eigenschaft vor dieser Überprüfung ein Array von Bytes zugewiesen wird, denn wenn pi null ist , wird eine Ausnahme vom Typ NullReferenceException ausgelöst.

Eine ähnliche Situation wurde an einer anderen Stelle festgestellt:

 private static void Task_TaskCompleted(WorkerTask task) { .... task.KeepImage = false; if (task != null) { if (task.RequestSettingUpdate) { Program.MainForm.UpdateCheckStates(); } .... } .... } 

PVS-Studio-Warnung: V3095 [CWE-476] Das Objekt 'task' wurde verwendet, bevor es gegen null verifiziert wurde. Überprüfen Sie die Zeilen: 268, 270. TaskManager.cs 268

PVS-Studio hat einen weiteren ähnlichen Fehler gefunden. Der Punkt ist der gleiche, so dass das Codefragment nicht unbedingt zitiert werden muss. Die Analysatormeldung reicht aus.

PVS-Studio-Warnung: V3095 [CWE-476] Das Objekt 'Config.PhotobucketAccountInfo' wurde verwendet, bevor es gegen Null verifiziert wurde. Überprüfen Sie die Zeilen: 216, 219. UploadersConfigForm.cs 216

Der gleiche Rückgabewert

In der EvalWindows- Methode der WindowsList- Klasse wurde ein verdächtiges Codefragment gefunden, das in allen Fällen true zurückgibt:

 public class WindowsList { public List<IntPtr> IgnoreWindows { get; set; } .... public WindowsList() { IgnoreWindows = new List<IntPtr>(); } public WindowsList(IntPtr ignoreWindow) : this() { IgnoreWindows.Add(ignoreWindow); } .... private bool EvalWindows(IntPtr hWnd, IntPtr lParam) { if (IgnoreWindows.Any(window => hWnd == window)) { return true; // <= } windows.Add(new WindowInfo(hWnd)); return true; // <= } } 

PVS-Studio-Warnung: V3009 Es ist seltsam, dass diese Methode immer ein und denselben Wert von 'true' zurückgibt. WindowsList.cs 82

Es scheint logisch, dass die Methode false zurückgeben muss, wenn in der Liste mit dem Namen IgnoreWindows ein Zeiger mit demselben Namen wie hWnd vorhanden ist.

Die IgnoreWindows- Liste kann entweder beim Aufrufen des Konstruktors WindowsList (IntPtr ignoreWindow) oder direkt durch Zugriff auf die öffentliche Eigenschaft gefüllt werden. Laut Visual Studio ist diese Liste derzeit im Code nicht gefüllt. Dies ist ein weiterer seltsamer Ort dieser Methode.

Unsicherer Aufruf von Ereignishandlern

 protected void OnNewsLoaded() { if (NewsLoaded != null) { NewsLoaded(this, EventArgs.Empty); } } 

PVS-Studio-Warnung: V3083 [CWE-367] Unsicherer Aufruf des Ereignisses 'NewsLoaded', NullReferenceException ist möglich. Überlegen Sie, ob Sie einer lokalen Variablen ein Ereignis zuweisen möchten, bevor Sie sie aufrufen. NewsListControl.cs 111

Hier kann ein sehr böser Fall auftreten. Nach dem Überprüfen der NewsLoaded- Variablen auf null kann die Methode, die ein Ereignis behandelt, beispielsweise in einem anderen Thread abgemeldet werden. In diesem Fall ist die Variable NewsLoaded bereits null, wenn wir in den Hauptteil der if-Anweisung gelangen . Eine NullReferenceException kann auftreten, wenn versucht wird, Abonnenten über das Ereignis NewsLoaded anzurufen , das null ist. Es ist viel sicherer, einen nullbedingten Operator zu verwenden und den obigen Code wie folgt neu zu schreiben:

 protected void OnNewsLoaded() { NewsLoaded?.Invoke(this, EventArgs.Empty); } 

Der Analysator zeigte auf 68 ähnliche Fragmente. Wir werden sie nicht alle beschreiben - sie haben alle ein ähnliches Anrufmuster.

Geben Sie null von ToString zurück

Kürzlich habe ich aus einem interessanten Artikel meines Kollegen herausgefunden, dass Microsoft nicht empfiehlt, null von der überschriebenen Methode ToString zurückzugeben . PVS-Studio ist sich dessen bewusst:

 public override string ToString() { lock (loggerLock) { if (sbMessages != null && sbMessages.Length > 0) { return sbMessages.ToString(); } return null; } } 

PVS-Studio-Warnung: V3108 Es wird nicht empfohlen, 'null' von der Methode 'ToSting ()' zurückzugeben. Logger.cs 167

Warum zugewiesen, wenn nicht verwendet?

 public SeafileCheckAccInfoResponse GetAccountInfo() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "account/info/?format=json"); .... } 

PVS-Studio-Warnung: V3008 Der Variablen 'url' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Kontrollzeilen: 197, 196. Seafile.cs 197

Wie wir aus dem Beispiel sehen können, wird der URL- Variable beim Deklarieren ein Wert zugewiesen, der von der Methode FixPrefix zurückgegeben wird . In der nächsten Zeile löschen wir den erhaltenen Wert, auch ohne ihn irgendwo zu verwenden. Wir bekommen etwas Ähnliches wie toten Code: Es funktioniert, hat aber keinen Einfluss auf das Ergebnis. Dieser Fehler ist höchstwahrscheinlich auf ein Kopieren und Einfügen zurückzuführen, da solche Codefragmente in 9 weiteren Methoden auftreten. Als Beispiel nennen wir zwei Methoden mit einer ähnlichen ersten Zeile:

 public bool CheckAuthToken() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "auth/ping/?format=json"); .... } .... public bool CheckAPIURL() { string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "ping/?format=json"); .... } 

Schlussfolgerungen


Wie wir sehen können, hängt die Konfigurationskomplexität der automatischen Analysatorprüfungen nicht von einem ausgewählten CI-System ab. Wir brauchten buchstäblich 15 Minuten und mehrere Mausklicks, um die Überprüfung unseres Projektcodes mit einem statischen Analysegerät zu konfigurieren.

Abschließend laden wir Sie ein, den Analysator für Ihre Projekte herunterzuladen und zu testen .

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


All Articles