Dies ist der zweite Artikel über die Verwendung des statischen Analysators PVS-Studio in Cloud-CI-Systemen. Dieses Mal wird die Azure DevOps-Plattform betrachtet - eine Cloud-CI \ CD-Lösung von Microsoft. Betrachten Sie diesmal ShareX als analysiertes Projekt.
Wir werden drei Komponenten benötigen. Der erste ist der statische Analysator PVS-Studio. Das zweite ist Azure DevOps, in das wir den Analysator integrieren werden. Das dritte Projekt wird überprüft, um die Funktionen von PVS-Studio bei der Arbeit in der Cloud zu demonstrieren. Also fangen wir an.
PVS-Studio ist ein statischer Code-Analysator zur Suche nach Fehlern und Sicherheitsmängeln. Führt eine Code-Analyse in C, C ++, C # und Java durch.
Azure DevOps . Die Azure DevOps-Plattform enthält Tools wie Azure Pipeline, Azure Board, Azure Artifacts und andere, um das Erstellen von Software zu beschleunigen und deren Qualität zu verbessern.
ShareX ist eine kostenlose Anwendung, mit der Sie jeden Teil des Bildschirms erfassen und aufzeichnen können. Das Projekt ist in C # geschrieben und eignet sich hervorragend zur Demonstration der Ausführung des statischen Analysators. Der Quellcode für das Projekt
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 in Verbindung mit einer Cloud-Plattform zu demonstrieren.
Lass uns einrichten
Um in Azure DevOps zu beginnen, klicken Sie auf den
Link und dann auf die Schaltfläche "Kostenlos mit GitHub starten".
Gewähren der Microsoft-Anwendung Zugriff auf die Daten des GitHub-Kontos.
Um die Registrierung abzuschließen, muss ein Microsoft-Konto erstellt werden.
Erstellen Sie nach der Registrierung ein Projekt:
Als nächstes müssen wir zum Abschnitt "Pipelines" - "Builds" gehen und eine neue Build-Pipeline erstellen
Auf die Frage, wo sich unser Code befindet, werden wir antworten - GitHub.
Wir autorisieren die Azure Pipelines-Anwendung und wählen das Repository mit dem Projekt aus, für das wir den Start des statischen Analysators konfigurieren möchten
Wählen Sie im Vorlagenauswahlfenster "Starter-Pipeline".
Wir können eine statische Analyse des Projektcodes auf zwei Arten durchführen: mithilfe von Microsoft-gehosteten oder selbst gehosteten Agenten.
In der ersten Version werden von Microsoft gehostete Agenten verwendet. Solche Agenten sind normale virtuelle Maschinen, die beim Starten unserer Pipeline gestartet und nach dem Ende der Aufgabe gelöscht werden. Durch die Verwendung solcher Agenten können Sie keine Zeit damit verschwenden, sie zu unterstützen und zu aktualisieren. Sie unterliegen jedoch einigen Einschränkungen, z. B. der Unmöglichkeit, zusätzliche Software zu installieren, die zum Erstellen des Projekts verwendet wird.
Ersetzen Sie unsere Standardkonfiguration durch die folgende für die Verwendung von von Microsoft gehosteten Agenten:
# # master- trigger: - master # # , Docker-, # Windows Server 1803 pool: vmImage: 'win1803' container: microsoft/dotnet-framework:4.7.2-sdk-windowsservercore-1803 steps: # - 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: | # nuget restore .\ShareX.sln # , md .\PVSTestResults # PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /COMPONENTS=Core # "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" credentials -u $(PVS_USERNAME) -n $(PVS_KEY) # 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 # - 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 funktioniert dieser Artikel jedoch nicht und der Container wird bei jedem Start der Aufgabe heruntergeladen, was sich negativ auf die Ausführungszeit auswirkt.
Speichern Sie die Pipeline und erstellen Sie die Variablen, die zum Erstellen der Lizenzdatei verwendet werden. Öffnen Sie dazu das Pipeline-Bearbeitungsfenster und klicken Sie in der oberen rechten Ecke auf die Schaltfläche „Variablen“.
Fügen Sie 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, das
Element "Diesen Wert geheim halten" zu
aktivieren ,
um den Variablenwert mit einem 2048-Bit-RSA-Schlüssel zu verschlüsseln und die Ausgabe des Variablenwerts an das
Taskausführungsprotokoll zu unterdrücken.
Wir speichern die Variablen und starten die Pipeline mit der Schaltfläche "Ausführen".
Die zweite Option zum Ausführen der Analyse ist die Verwendung eines selbst gehosteten Agenten. Selbst gehostete Agenten sind Agenten, die wir selbst konfigurieren und verwalten. Solche Agenten bieten mehr Möglichkeiten für die Installation von Software, die für die Montage und das Testen unseres Softwareprodukts erforderlich ist.
Vor der Verwendung solcher Agenten müssen sie gemäß den
Anweisungen konfiguriert und ein statischer Analysator installiert und
konfiguriert werden .
Um die Aufgabe auf einem selbst gehosteten Agenten zu starten, ersetzen wir die vorgeschlagene Standardkonfiguration durch die folgende:
# # master- trigger: - master # self-hosted 'MyPool' pool: 'MyPool' steps: - task: CmdLine@2 inputs: workingDirectory: $(System.DefaultWorkingDirectory) script: | # nuget restore .\ShareX.sln # , md .\PVSTestResults # 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 # - task: PublishBuildArtifacts@1 inputs: pathToPublish: PVSTestResults artifactName: PVSTestResults
Nach Abschluss der Aufgabe kann das Archiv mit den Analyseberichten auf der Registerkarte "Zusammenfassung" heruntergeladen werden, oder wir können die Erweiterung "E-Mail
senden" verwenden , mit der Sie das Senden von E-Mails konfigurieren oder auf dem
Marktplatz nach einem für uns bequemeren Tool suchen können.
Über Analyseergebnisse
Schauen wir uns nun einige der Fehler an, die im überprüften Projekt gefunden wurden - ShareX.
Redundante SchecksBeginnen 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 Sie darauf, die Variable
dataObject auf
null zu überprüfen. Wofür ist sie hier?
dataObject kann in diesem Fall einfach nicht
null sein , da es mit einem Verweis auf das erstellte Objekt initialisiert wird. Infolgedessen haben wir eine redundante Überprüfung. Ist es kritisch? Nein. Sieht prägnant aus? Nein. Diese Prüfung wird deutlich besser entfernt, um den Code nicht zu überladen.
Werfen wir einen Blick auf einen anderen Code, zu dem Sie ähnliche Kommentare abgeben 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
Die
GetImageAlternative- Methode überprüft erneut, ob die Variable
img unmittelbar nach dem Erstellen einer neuen Instanz der
Bitmap- Klasse nicht
null ist . Der Unterschied zum vorherigen Beispiel besteht darin, dass zum Initialisieren der Variablen
img nicht der Konstruktor, sondern die
GetDIBImage- Methode verwendet wird. Der Autor des Codes geht davon aus, dass bei dieser Methode eine Ausnahme auftreten kann, deklariert jedoch nur
try und blockiert
schließlich , wobei
catch weggelassen wird. Wenn eine Ausnahme auftritt, erhält die aufrufende Methode
- 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 fällt sofort in den
catch-Block . Daher zeigte der Analysator eine redundante Validierung an.
Betrachten Sie das folgende
Warnbeispiel mit Code
V3022 :
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 an. Dort überprüfen wir den Wert der schreibgeschützten
Count- Eigenschaft. Diese Eigenschaft zeigt die Anzahl der Elemente in einer Instanz der
SelectedItems- Auflistung an. Die Bedingung ist nur erfüllt, wenn die
Count- Eigenschaft größer als Null ist. Alles wäre in Ordnung, aber nur in der externen
if-Anweisung ist der
Count bereits überprüft. Eine Instanz der
SelectedItems- Auflistung kann nicht die Anzahl der Elemente kleiner als Null haben. Daher nimmt
Count einen Wert an, der entweder gleich Null oder größer als Null ist. Da wir bereits in der ersten
if-Anweisung überprüft haben, dass
Count Null ist und sich als falsch herausgestellt hat, ist es nicht sinnvoll, eine weitere Prüfung für den else-Zweig zu schreiben, bei dem
Count größer als Null ist.
Das letzte Beispiel für die Fehlernummer
V3022 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 eine etwas höhere Deklaration durchgeführt wird und gleichzeitig die Variable
itemCount auf Null gesetzt wird. Bis zur Bedingung wird diese Variable nirgendwo verwendet und ändert sich nicht. Daher hat der Analysator die richtige Schlussfolgerung über den bedingten Ausdruck gezogen, dessen Wert immer falsch ist.
Schauen wir uns jetzt etwas wirklich Interessantes an.
Der beste Weg, um den Fehler zu verstehen, besteht darin, den 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 sofort alle Karten aufdecken und zeigen, was unser Analysator hier gefunden hat. Verschieben wir diesen Moment also für eine kurze Zeit.
Anhand des Namens der Methode lässt sich leicht erraten, was sie bewirkt: Sie senden ihr ein Bild oder ein Fragment des Bildes als Eingabe und es führt seine Pixelierung durch. Der Methodencode ist ziemlich lang, daher geben wir ihn hier nicht vollständig an, sondern versuchen einfach, seinen Algorithmus zu erklären und zu erklären, welche Art von Fehler PVS-Studio hier gefunden hat.
Diese Methode akzeptiert zwei Parameter als Eingabe: ein Objekt vom Typ
Bitmap und einen Wert vom Typ
int , der die Größe der Pixel angibt. Der Operationsalgorithmus ist recht einfach:
1) Wir zerlegen das Fragment des am Eingang empfangenen Bildes in Quadrate mit einer 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) Als nächstes gehen wir um jedes Pixel in diesem Quadrat herum und akkumulieren die Werte der Felder
Rot ,
Grün ,
Blau und
Alpha in Zwischenvariablen und multiplizieren zuvor den Wert der entsprechenden Farbe und den Alphakanalwert mit der Variablen
pixelWeight , die durch Teilen des
Alpha- Werts durch 255 erhalten wird (die
Alpha- Variable hat Typ
Byte ). Außerdem durchlaufen wir beim Durchlaufen von Pixeln die in
pixelWeight aufgezeichneten
Werte zu einer Variablen namens
weightedCount .
Das Code-Snippet, das die obigen Schritte 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 Variablen
weightedCount für dieses Pixel keinen Wert hinzufügt, wenn der Wert der
Alpha- Variablen Null ist. Wir werden das in Zukunft brauchen.
3) Nachdem wir alle Pixel im aktuellen Quadrat umgangen haben, können wir die allgemeine „durchschnittliche“ Farbe für dieses Quadrat ermitteln. Der Code, der diese Aktionen ausführt, lautet wie folgt:
ColorBgra averageColor = new ColorBgra((byte)(b / weightedCount), (byte)(g / weightedCount), (byte)(r / weightedCount), (byte)(a / pixelCount));
4)
Nachdem wir die endgültige Farbe haben und sie in die Variable
durchschnittlicher Farbe
schreiben , können wir jedes Pixel im Quadrat erneut
umgehen und ihm einen Wert aus der
durchschnittlichen Farbe zuweisen .
5) Wir kehren zu Schritt 2 zurück, solange noch rohe Quadrate vorhanden sind.
Wir stellen erneut fest, dass die Variable
weightedCount nicht der Anzahl aller quadratischen Pixel entspricht. Wenn beispielsweise ein absolut transparentes Pixel im Bild auftritt (der Wert im Alphakanal ist Null), ist die Variable
pixelWeight für dieses Pixel Null (
0/255 = 0). Daher trägt dieses Pixel nicht zur Bildung des Werts der Variablen
weightedCount bei . Dies ist logisch - es macht keinen Sinn, die Farben eines absolut transparenten Pixels zu berücksichtigen.
Alles scheint ziemlich vernünftig - Pixelierung sollte korrekt funktionieren. Und es funktioniert wirklich richtig. Dies gilt nur nicht für PNG-Bilder mit Pixeln mit Werten im Alphakanal von weniger als 255 und ungleich Null. Achten Sie auf das pixelige Bild unten:
Hast du Pixelierung gesehen? Und wir sind nicht. Nun wollen wir diese kleine Intrige enthüllen und erklären, wo genau der Fehler in dieser Methode versteckt ist. Der Fehler hat sich in die Zeile zur Berechnung des Werts der
pixelWeight- Variablen eingeschlichen:
float pixelWeight = color.Alpha / 255;
Tatsache ist, dass der Autor des Codes, der die Variable
pixelWeight als float deklarierte, implizierte, dass beim Teilen des
Alpha- Feldes durch 255 zusätzlich zu Null und Eins Bruchzahlen erhalten werden sollten. Hier liegt das Problem, da die
Alpha- Variable vom Typ
Byte ist und wenn wir sie durch 255 teilen, erhalten wir einen ganzzahligen Wert, und nur dann wird er implizit in
float umgewandelt , sodass der Bruchteil verloren geht.
Die Unfähigkeit, PNG-Bilder mit einem gewissen Grad an Transparenz zu pixelisieren, ist leicht zu erklären. Da die Alpha-Kanalwerte für diese Pixel im Bereich 0 <Alpha <255 liegen, erhalten wir beim Teilen der
Alpha- Variablen durch 255 immer 0. Daher sind auch die Werte der
Variablen pixelWeight ,
r ,
g ,
b ,
a und
weightedCount immer immer wird Null sein. Infolgedessen hat unsere durchschnittliche
Farbdurchschnittsfarbe über alle Kanäle hinweg Nullwerte: Rot - 0, Blau - 0, Grün - 0, Alpha - 0. Wenn Sie das Quadrat mit dieser Farbe
füllen, ändern wir die ursprüngliche Farbe der Pixel nicht, da die
Durchschnittsfarbe absolut transparent ist . Um diesen Fehler zu beheben, müssen Sie nur das
Alpha- Feld explizit in den
Float- Typ
umwandeln . Die korrigierte Codezeile kann folgendermaßen aussehen:
float pixelWeight = (float)color.Alpha / 255;
Und es ist Zeit, die Nachricht zu zitieren, die PVS-Studio an den falschen Code ausgegeben hat:
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 geben wir einen Screenshot eines wirklich pixeligen Bildes, das mit einer festen Version der Anwendung 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 Variable
pi null ist, weshalb die Prüfung
pi! = Null durchgeführt wird, bevor die
SetPropertyItem- Methode
aufgerufen wird. Es ist seltsam, dass vor dieser Überprüfung der Eigenschaft
pi.Value ein Byte-Array zugewiesen wird, da bei
pi null eine Ausnahme vom Typ
NullReferenceException ausgelöst wird.
Eine ähnliche Situation wurde anderswo gesehen:
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. Die Bedeutung ist immer noch dieselbe, daher besteht keine große Notwendigkeit, ein Codefragment anzugeben. Wir beschränken uns auf die Analysator-Nachricht.
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ächtiger Code entdeckt, der unter keinen Umständen
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 erscheint logisch, dass die Methode
false zurückgeben sollte, wenn in der Liste ein Zeiger mit demselben Wert wie
hWnd mit dem Namen
IgnoreWindows gefunden wurde.
Die
IgnoreWindows- Liste kann entweder durch Aufrufen des
WindowsList- Konstruktors
(IntPtr ignoreWindow) oder direkt durch Zugriff auf die Eigenschaft
ausgefüllt werden , da sie öffentlich ist. Auf die eine oder andere Weise wird diese Liste laut Visual Studio derzeit im Code in keiner Weise ausgefü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
In diesem Fall kann die folgende unangenehme Situation auftreten: Nach dem Überprüfen der
NewsLoaded- Variablen auf
Null- Ungleichung kann die Methode, die das Ereignis verarbeitet, beispielsweise in einem anderen Thread abgemeldet werden, und wenn wir in den Hauptteil der bedingten
if-Anweisung gelangen , wird die
NewsLoaded- Variable gleich
null .
Wenn Sie versuchen, Abonnenten für ein
NewsLoaded- Ereignis
anzurufen , das
null ist, wird eine
NullReferenceException ausgelöst . Es ist viel sicherer, den bedingten Nulloperator zu verwenden und den obigen Code wie folgt neu zu schreiben:
protected void OnNewsLoaded() { NewsLoaded?.Invoke(this, EventArgs.Empty); }
Der Analysator zeigte
68 weitere ähnliche Stellen an. Wir werden sie hier nicht beschreiben - das Muster des Ereignisaufrufs in ihnen ist ähnlich.
Geben Sie null von ToString zurückVor nicht allzu langer Zeit habe ich aus dem
interessanten Artikel eines Kollegen herausgefunden, dass Microsoft nicht empfiehlt,
null von einer überschriebenen
ToString- Methode 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 'ToSting ()' - Methode zurückzugeben. Logger.cs 167
Warum angemessen, 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 Sie dem Beispiel
entnehmen können, wird der Deklaration der
URL- Variablen ein Wert zugewiesen, der von der
FixPrefix- Methode zurückgegeben wird. In der nächsten Zeile „schleifen“ wir den resultierenden Wert, auch ohne ihn irgendwo zu verwenden. Wir bekommen etwas Ähnliches wie "toter Code" - es macht die Arbeit, es hat keinen Einfluss auf das Endergebnis. Dieser Fehler ist höchstwahrscheinlich das Ergebnis des Kopierens und Einfügens, da solche Codefragmente in 9 weiteren Methoden gefunden werden.
Als Beispiel geben wir zwei Methoden mit einer ähnlichen ersten Zeile an:
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"); .... }
Insgesamt
Wie wir sehen können, hängt die Komplexität der Einrichtung der automatischen Überprüfung durch den Analysator nicht vom ausgewählten CI-System ab. In nur 15 Minuten und wenigen Mausklicks richten wir die Überprüfung unseres Projektcodes mit einem statischen Analysator ein.
Abschließend empfehlen wir Ihnen
, den Analysator für Ihre Projekte
herunterzuladen und zu testen .

Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Oleg Andreev, Ilya Gainulin.
PVS-Studio in den Clouds: Azure DevOps .