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:
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".
Gewähren Sie der Microsoft-Anwendung Zugriff auf die GitHub-Kontodaten.
Sie müssen ein Microsoft-Konto erstellen, um Ihre Registrierung abzuschließen.
Erstellen Sie nach der Registrierung ein Projekt:
Als nächstes müssen wir zu "Pipelines" - "Builds" wechseln und eine neue Build-Pipeline erstellen.
Auf die Frage, wo sich unser Code befindet, antworten wir - GitHub.
Autorisieren Sie Azure Pipelines und wählen Sie das Repository mit dem Projekt aus, für das wir den Lauf des statischen Analysators konfigurieren.
Wählen Sie im Vorlagenauswahlfenster "Starter-Pipeline".
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".
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.
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.
Analyseergebnisse
Schauen wir uns nun einige Fehler im getesteten Projekt ShareX an.
Übermäßige ÜberprüfungenBeginnen 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 visualisierenEs 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:
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:
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ückgabewertIn 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;
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ückKü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 .