PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft
Wir machen die Nutzung von PVS-Studio weiterhin komfortabler. Unser Analysator ist jetzt in Chocolatey, einem Paketmanager für Windows, verfügbar. Wir glauben, dass dies den Einsatz von PVS-Studio insbesondere in Cloud-Diensten erleichtern wird. Um nicht zu weit zu gehen, überprüfen wir den Quellcode desselben Chocolatey. Azure DevOps fungiert als CI-System.

Hier finden Sie eine Liste unserer weiteren Artikel zum Thema Integration mit Cloud-Systemen:

Ich empfehle Ihnen, den ersten Artikel zur Integration mit Azure DevOps zu beachten, da in diesem Fall einige Punkte weggelassen werden, um sie nicht zu duplizieren.

Also, die Helden dieses Artikels:

PVS Studio ist ein statisches Code-Analysetool zur Identifizierung von Fehlern und potenziellen Schwachstellen in Programmen, die in C, C++, C# und Java geschrieben sind. Läuft auf 64-Bit-Windows-, Linux- und macOS-Systemen und kann Code analysieren, der für 32-Bit-, 64-Bit- und eingebettete ARM-Plattformen entwickelt wurde. Wenn Sie zum ersten Mal die statische Code-Analyse zur Überprüfung Ihrer Projekte ausprobieren, empfehlen wir Ihnen, sich damit vertraut zu machen ein Artikel Informationen dazu, wie Sie schnell die interessantesten PVS-Studio-Warnungen anzeigen und die Fähigkeiten dieses Tools bewerten können.

Azure-DevOps — eine Reihe von Cloud-Diensten, die gemeinsam den gesamten Entwicklungsprozess abdecken. Diese Plattform umfasst Tools wie Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos und Azure Test Plans, mit denen Sie den Prozess der Softwareerstellung beschleunigen und ihre Qualität verbessern können.

Schoko ist ein Open-Source-Paketmanager für Windows. Ziel des Projekts ist die Automatisierung des gesamten Software-Lebenszyklus von der Installation bis zur Aktualisierung und Deinstallation auf Windows-Betriebssystemen.

Über die Verwendung von Chocolatey

Hier können Sie sehen, wie Sie den Paketmanager selbst installieren Link. Eine vollständige Dokumentation zur Installation des Analysators finden Sie unter Link Weitere Informationen finden Sie im Abschnitt „Installation mit dem Chocolatey-Paketmanager“. Ich werde einige Punkte von dort kurz wiederholen.

Befehl zum Installieren der neuesten Version des Analysators:

choco install pvs-studio

Befehl zum Installieren einer bestimmten Version des PVS-Studio-Pakets:

choco install pvs-studio --version=7.05.35617.2075

Standardmäßig ist nur der Kern des Analysators, die Core-Komponente, installiert. Alle anderen Flags (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) können mit --package-parameters übergeben werden.

Ein Beispiel für einen Befehl, der einen Analysator mit einem Plugin für Visual Studio 2019 installiert:

choco install pvs-studio --package-parameters="'/MSVS2019'"

Schauen wir uns nun ein Beispiel für die praktische Verwendung des Analysators unter Azure DevOps an.

Einstellung

Ich möchte Sie daran erinnern, dass es einen separaten Abschnitt zu Themen wie der Registrierung eines Kontos, der Erstellung einer Build-Pipeline und der Synchronisierung Ihres Kontos mit einem Projekt im GitHub-Repository gibt. Beitrag. Unser Setup beginnt sofort mit dem Schreiben einer Konfigurationsdatei.

Lassen Sie uns zunächst einen Startauslöser einrichten, der angibt, dass wir nur bei Änderungen in starten Master Zweig:

trigger:
- master

Als nächstes müssen wir eine virtuelle Maschine auswählen. Vorerst wird es ein von Microsoft gehosteter Agent mit Windows Server 2019 und Visual Studio 2019 sein:

pool:
  vmImage: 'windows-latest'

Kommen wir zum Hauptteil der Konfigurationsdatei (Block Schritte). Obwohl man keine beliebige Software in einer virtuellen Maschine installieren kann, habe ich keinen Docker-Container hinzugefügt. Wir können Chocolatey als Erweiterung für Azure DevOps hinzufügen. Gehen wir dazu zu Link. Klicken Kostenlos bekommen. Wenn Sie bereits autorisiert sind, wählen Sie als Nächstes einfach Ihr Konto aus. Wenn nicht, führen Sie nach der Autorisierung dasselbe aus.

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Hier müssen Sie auswählen, wo wir die Erweiterung hinzufügen möchten, und auf die Schaltfläche klicken Installieren.

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Klicken Sie nach erfolgreicher Installation auf Weiter zur Organisation:

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Im Fenster sehen Sie nun die Vorlage für die Chocolatey-Aufgabe und Aufgaben beim Bearbeiten einer Konfigurationsdatei azure-pipelines.yml:

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Klicken Sie auf Chocolatey und sehen Sie eine Liste der Felder:

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Hier müssen wir auswählen installieren auf dem Feld mit den Mannschaften. IN Nuspec-Dateiname Geben Sie den Namen des erforderlichen Pakets an – pvs-studio. Wenn Sie die Version nicht angeben, wird die neueste Version installiert, was uns völlig entgegenkommt. Drücken wir den Knopf hinzufügen und wir werden die generierte Aufgabe in der Konfigurationsdatei sehen.

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

Kommen wir als Nächstes zum Hauptteil unserer Datei:

- task: CmdLine@2
  inputs:
    script: 

Jetzt müssen wir eine Datei mit der Analyselizenz erstellen. Hier PVSNAME и PVSKEY – Namen von Variablen, deren Werte wir in den Einstellungen angeben. Sie speichern den PVS-Studio-Login und den Lizenzschlüssel. Um ihre Werte festzulegen, öffnen Sie das Menü Variablen->Neue Variable. Lassen Sie uns Variablen erstellen PVSNAME zum Anmelden und PVSKEY für den Analysatorschlüssel. Vergessen Sie nicht, das Kontrollkästchen zu aktivieren Halten Sie diesen Wert geheim für PVSKEY. Befehlscode:

сall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials 
–u $(PVSNAME) –n $(PVSKEY)

Erstellen wir das Projekt mit der bat-Datei im Repository:

сall build.bat

Erstellen wir einen Ordner, in dem Dateien mit den Ergebnissen des Analysators gespeichert werden:

сall mkdir PVSTestResults

Beginnen wir mit der Analyse des Projekts:

сall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog 

Wir konvertieren unseren Bericht mit dem Dienstprogramm PlogСonverter in das HTML-Format:

сall "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
–t html –o PVSTestResults .PVSTestResultsChoco.plog

Jetzt müssen Sie eine Aufgabe erstellen, damit Sie den Bericht hochladen können.

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

Die komplette Konfigurationsdatei sieht so aus:

trigger:
- master

pool:
  vmImage: 'windows-latest'

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

- task: CmdLine@2
  inputs:
    script: |
      call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      credentials –u $(PVSNAME) –n $(PVSKEY)
      call build.bat
      call mkdir PVSTestResults
      call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      –t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
      call "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
      –t html –o .PVSTestResults .PVSTestResultsChoco.plog

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

Lasst uns klicken Speichern->Speichern->Ausführen um die Aufgabe auszuführen. Laden Sie den Bericht herunter, indem Sie zur Registerkarte „Aufgaben“ gehen.

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Das Chocolatey-Projekt enthält nur 37615 Zeilen C#-Code. Schauen wir uns einige der gefundenen Fehler an.

Testergebnisse

Warnung N1

Warnung des Analysators: V3005 Die Variable „Provider“ wird sich selbst zugewiesen. CrytpoHashProviderSpecs.cs 38

public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
  ....
  protected CryptoHashProvider Provider;
  ....
  public override void Context()
  {
    Provider = Provider = new CryptoHashProvider(FileSystem.Object);
  }
}

Der Analysator hat eine Zuordnung der Variablen zu sich selbst festgestellt, was keinen Sinn ergibt. Höchstwahrscheinlich sollte es anstelle einer dieser Variablen eine andere geben. Nun ja, oder das ist ein Tippfehler und die zusätzliche Zuweisung kann einfach entfernt werden.

Warnung N2

Warnung des Analysators: V3093 [CWE-480] Der Operator „&“ wertet beide Operanden aus. Möglicherweise sollte stattdessen ein Kurzschlussoperator „&&“ verwendet werden. Platform.cs 64

public static PlatformType get_platform()
{
  switch (Environment.OSVersion.Platform)
  {
    case PlatformID.MacOSX:
    {
      ....
    }
    case PlatformID.Unix:
    if(file_system.directory_exists("/Applications")
      & file_system.directory_exists("/System")
      & file_system.directory_exists("/Users")
      & file_system.directory_exists("/Volumes"))
      {
        return PlatformType.Mac;
      }
        else
          return PlatformType.Linux;
    default:
      return PlatformType.Windows;
  }
}

Betreiberunterschied & vom Betreiber && ist das, wenn die linke Seite des Ausdrucks ist falsch, dann wird trotzdem die rechte Seite berechnet, was in diesem Fall unnötige Methodenaufrufe mit sich bringt system.directory_exists.

Im betrachteten Fragment handelt es sich hierbei um einen geringfügigen Fehler. Ja, diese Bedingung kann durch Ersetzen des &-Operators durch den &&-Operator optimiert werden, aber aus praktischer Sicht hat dies keine Auswirkungen. In anderen Fällen kann eine Verwechslung zwischen & und && jedoch zu ernsthaften Problemen führen, wenn die rechte Seite des Ausdrucks mit falschen/ungültigen Werten behandelt wird. In unserer Fehlersammlung finden Sie beispielsweise mithilfe der V3093-Diagnose identifiziert, es gibt diesen Fall:

if ((k < nct) & (s[k] != 0.0))

Auch wenn der Index k falsch ist, wird es für den Zugriff auf ein Array-Element verwendet. Als Ergebnis wird eine Ausnahme ausgelöst IndexOutOfRangeException.

Warnungen N3, N4

Warnung des Analysators: V3022 [CWE-571] Der Ausdruck „shortPrompt“ ist immer wahr. InteractivePrompt.cs 101
Warnung des Analysators: V3022 [CWE-571] Der Ausdruck „shortPrompt“ ist immer wahr. InteractivePrompt.cs 105

public static string 
prompt_for_confirmation(.... bool shortPrompt = false, ....)
{
  ....
  if (shortPrompt)
  {
    var choicePrompt = choice.is_equal_to(defaultChoice) //1
    ?
    shortPrompt //2
    ?
    "[[{0}]{1}]".format_with(choice.Substring(0, 1).ToUpperInvariant(), //3
    choice.Substring(1,choice.Length - 1))
    :
    "[{0}]".format_with(choice.ToUpperInvariant()) //0
    : 
    shortPrompt //4
    ? 
    "[{0}]{1}".format_with(choice.Substring(0,1).ToUpperInvariant(), //5
    choice.Substring(1,choice.Length - 1)) 
    :
    choice; //0
    ....
  }
  ....
}

In diesem Fall steckt eine seltsame Logik hinter der Funktionsweise des ternären Operators. Schauen wir mal genauer hin: Wenn die Bedingung, die ich mit Nummer 1 markiert habe, erfüllt ist, dann kommen wir zu Bedingung 2, die immer erfüllt ist was immer dies auch sein sollte., was bedeutet, dass Zeile 3 ausgeführt wird. Wenn sich herausstellt, dass Bedingung 1 falsch ist, gehen wir zu der mit Nummer 4 gekennzeichneten Zeile, deren Bedingung auch immer gilt was immer dies auch sein sollte., was bedeutet, dass Zeile 5 ausgeführt wird. Daher werden die mit Kommentar 0 markierten Bedingungen niemals erfüllt, was möglicherweise nicht genau der vom Programmierer erwarteten Operationslogik entspricht.

Warnung N5

Warnung des Analysators: V3123 [CWE-783] Möglicherweise funktioniert der Operator „?:“ anders als erwartet. Seine Priorität ist niedriger als die Priorität anderer Betreiber in seinem Zustand. Optionen.cs 1019

private static string GetArgumentName (...., string description)
{
  string[] nameStart;
  if (maxIndex == 1)
  {
    nameStart = new string[]{"{0:", "{"};
  }
  else
  {
    nameStart = new string[]{"{" + index + ":"};
  }
  for (int i = 0; i < nameStart.Length; ++i) 
  {
    int start, j = 0;
    do 
    {
      start = description.IndexOf (nameStart [i], j);
    } 
    while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
    ....
    return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
  }
}

Die Diagnose funktionierte für die Zeile:

while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)

Da die Variable j Ein paar Zeilen oben wird auf Null initialisiert, der ternäre Operator gibt den Wert zurück falsch. Aufgrund dieser Bedingung wird der Schleifenkörper nur einmal ausgeführt. Es scheint mir, dass dieser Code überhaupt nicht so funktioniert, wie es der Programmierer beabsichtigt hat.

Warnung N6

Warnung des Analysators: V3022 [CWE-571] Der Ausdruck „installedPackageVersions.Count != 1“ ist immer wahr. NugetService.cs 1405

private void remove_nuget_cache_for_package(....)
{
  if (!config.AllVersions && installedPackageVersions.Count > 1)
  {
    const string allVersionsChoice = "All versions";
    if (installedPackageVersions.Count != 1)
    {
      choices.Add(allVersionsChoice);
    }
    ....
  }
  ....
}

Hier gibt es eine seltsame verschachtelte Bedingung: installedPackageVersions.Count != 1was immer so sein wird was immer dies auch sein sollte.. Häufig weist eine solche Warnung auf einen logischen Fehler im Code hin, in anderen Fällen weist sie lediglich auf eine redundante Überprüfung hin.

Warnung N7

Warnung des Analysators: V3001 Es gibt identische Unterausdrücke 'commandArguments.contains("-apikey")' links und rechts von '||' Operator. ArgumentsUtility.cs 42

public static bool arguments_contain_sensitive_information(string
 commandArguments)
{
  return commandArguments.contains("-install-arguments-sensitive")
  || commandArguments.contains("-package-parameters-sensitive")
  || commandArguments.contains("apikey ")
  || commandArguments.contains("config ")
  || commandArguments.contains("push ")
  || commandArguments.contains("-p ")
  || commandArguments.contains("-p=")
  || commandArguments.contains("-password")
  || commandArguments.contains("-cp ")
  || commandArguments.contains("-cp=")
  || commandArguments.contains("-certpassword")
  || commandArguments.contains("-k ")
  || commandArguments.contains("-k=")
  || commandArguments.contains("-key ")
  || commandArguments.contains("-key=")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key");
}

Der Programmierer, der diesen Codeabschnitt geschrieben hat, hat die letzten beiden Zeilen kopiert und eingefügt und vergessen, sie zu bearbeiten. Aus diesem Grund konnten Chocolatey-Benutzer den Parameter nicht anwenden API-Schlüssel noch ein paar Möglichkeiten. Ähnlich wie bei den oben genannten Parametern kann ich folgende Optionen anbieten:

commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");

Es besteht eine hohe Wahrscheinlichkeit, dass Fehler beim Kopieren und Einfügen früher oder später in jedem Projekt mit einer großen Menge Quellcode auftauchen, und eines der besten Tools, um sie zu bekämpfen, ist die statische Analyse.

PS Und wie immer tritt dieser Fehler am Ende einer mehrzeiligen Bedingung auf :). Siehe Veröffentlichung „Last-Line-Effekt".

Warnung N8

Warnung des Analysators: V3095 [CWE-476] Das Objekt „installedPackage“ wurde verwendet, bevor es gegen Null überprüft wurde. Überprüfen Sie die Zeilen: 910, 917. NugetService.cs 910

public virtual ConcurrentDictionary<string, PackageResult> get_outdated(....)
{
  ....
  var pinnedPackageResult = outdatedPackages.GetOrAdd(
    packageName, 
    new PackageResult(installedPackage, 
                      _fileSystem.combine_paths(
                        ApplicationParameters.PackagesLocation, 
                        installedPackage.Id)));
  ....
  if (   installedPackage != null
      && !string.IsNullOrWhiteSpace(installedPackage.Version.SpecialVersion) 
      && !config.UpgradeCommand.ExcludePrerelease)
  {
    ....
  }
  ....
}

Klassischer Fehler: Zuerst das Objekt Installiertes Paket verwendet und anschließend überprüft wird null. Diese Diagnose informiert uns über eines von zwei Problemen im Programm: entweder Installiertes Paket niemals gleich null, was zweifelhaft ist, und dann ist die Prüfung überflüssig, oder es könnte möglicherweise ein schwerwiegender Fehler im Code auftreten – ein Versuch, auf eine Nullreferenz zuzugreifen.

Abschluss

Also haben wir einen weiteren kleinen Schritt gemacht – die Nutzung von PVS-Studio ist jetzt noch einfacher und komfortabler geworden. Ich möchte auch sagen, dass Chocolatey ein guter Paketmanager mit einer geringen Anzahl von Fehlern im Code ist, die bei Verwendung von PVS-Studio sogar noch geringer sein könnten.

Wir laden ein скачать und probieren Sie PVS-Studio aus. Die regelmäßige Verwendung eines statischen Analysegeräts verbessert die Qualität und Zuverlässigkeit des von Ihrem Team entwickelten Codes und trägt dazu bei, Fehler zu vermeiden Zero-Day-Schwachstellen.

PS

Vor der Veröffentlichung haben wir den Artikel an die Chocolatey-Entwickler geschickt, und sie haben ihn positiv aufgenommen. Wir haben nichts Kritisches gefunden, aber ihnen gefiel zum Beispiel der Fehler, den wir im Zusammenhang mit dem „api-key“-Schlüssel gefunden haben.

PVS-Studio ist jetzt in Chocolatey: Chocolatey wird unter Azure DevOps überprüft

Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Übersetzungslink: Vladislav Stolyarov. PVS-Studio ist jetzt in Chocolatey: Überprüfung von Chocolatey unter Azure DevOps.

Source: habr.com

Kommentar hinzufügen