
Wir arbeiten weiterhin daran, die Nutzung von PVS-Studio zu erleichtern. Unser Analysetool ist jetzt in Chocolatey, dem Paketmanager für Windows, verfügbar. Wir glauben, dass dies die Bereitstellung von PVS-Studio, insbesondere in Cloud-Diensten, erleichtert. Um konkret zu werden, überprüfen wir den Quellcode von Chocolatey. Azure DevOps wird als CI-System fungieren.
Hier ist eine Liste unserer weiteren Artikel zum Thema Integration mit Cloud-Systemen:
Ich empfehle, auf den ersten Artikel über die Integration mit Azure DevOps zu achten, da in diesem Fall einige Punkte weggelassen wurden, um Doppelungen zu vermeiden.
Also, die Hauptakteure dieses Artikels:
— ein Tool zur statischen Codeanalyse, das entwickelt wurde, um Fehler und potenzielle Schwachstellen in Programmen zu identifizieren, die in C, C++, C# und Java geschrieben sind. Es funktioniert auf 64-Bit-Systemen unter Windows, Linux und macOS und kann Code analysieren, der für 32-Bit-, 64-Bit- und eingebettete ARM-Plattformen bestimmt ist. Wenn Sie zum ersten Mal die statische Codeanalyse ausprobieren, um Ihre Projekte zu überprüfen, empfehlen wir Ihnen, sich mit auseinanderzusetzen, wie Sie schnell die interessantesten Warnungen von PVS-Studio einsehen und die Möglichkeiten dieses Tools bewerten können.
— eine Sammlung von Cloud-Diensten, die den gesamten Entwicklungsprozess abdecken. Die Plattform umfasst Tools wie Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos und Azure Test Plans, die den Softwareentwicklungsprozess beschleunigen und die Qualität verbessern.
– ein Open-Source-Paketmanager für Windows. Ziel des Projekts ist es, den gesamten Lebenszyklus von Software von der Installation über Updates bis hin zur Deinstallation in Windows-Betriebssystemen zu automatisieren.
Über die Verwendung von Chocolatey
Klicken Sie hier, um zu sehen, wie Sie den Paketmanager selbst installieren können. . Die vollständige Dokumentation zur Installation des Analysewerkzeugs ist verfügbar unter im Abschnitt „Installation mit dem Paketmanager Chocolatey“. Hier sind einige wichtige Punkte zusammengefasst.
Der Befehl zur Installation der neuesten Version des Analysewerkzeugs lautet:
choco install pvs-studioDer Befehl zur Installation einer bestimmten Version des PVS-Studio-Pakets lautet:
choco install pvs-studio --version=7.05.35617.2075Standardmäßig wird nur der Kern des Analysewerkzeugs installiert – die Komponente Core. Alle anderen Flags (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) können mit —package-parameters übergeben werden.
Ein Beispielbefehl, der das Analysewerkzeug mit dem Plugin für Visual Studio 2019 installiert:
choco install pvs-studio --package-parameters="'/MSVS2019'"Nun betrachten wir ein praktisches Beispiel für die Verwendung des Analysewerkzeugs mit Azure DevOps.
Konfiguration
Ich erinnere daran, dass es zu Themen wie der Registrierung eines Kontos, der Erstellung einer Build-Pipeline und der Synchronisierung des Kontos mit einem in einem GitHub-Repository gespeicherten Projekt eine separate . Unsere Konfiguration beginnt direkt mit dem Schreiben der Konfigurationsdatei.
Zunächst konfigurieren wir den Trigger für die Ausführung, indem wir angeben, dass die Ausführung nur für Änderungen in master dem Branch erfolgt:
trigger:
- masterAls Nächstes wählen wir die virtuelle Maschine aus. Dies wird aktuell ein von Microsoft gehosteter Agent mit Windows Server 2019 und Visual Studio 2019 sein:
pool:
vmImage: 'windows-latest'Lassen Sie uns zum Hauptteil der Konfigurationsdatei (Block steps). Obwohl wir auf der virtuellen Maschine keine beliebige Software installieren können, habe ich keinen Docker-Container hinzugefügt. Wir können Chocolatey als Erweiterung für Azure DevOps hinzufügen. Gehen wir dazu zu . Klicken Sie auf Jetzt kostenlos erhalten. Wenn Sie bereits angemeldet sind, wählen Sie einfach Ihr Konto aus; wenn nicht, melden Sie sich an und wiederholen Sie den Vorgang.

Hier müssen wir auswählen, wo wir die Erweiterung hinzufügen, und die Schaltfläche Installieren.

Nach erfolgreicher Installation klicken wir auf Zur Organisation fortfahren:

Jetzt können wir die Vorlage für die Chocolatey-Aufgabe im Fenster tasks beim Bearbeiten der Konfigurationsdatei azure-pipelines.yml:

Klicken Sie auf Chocolatey und wir sehen die Liste der Felder:

Hier müssen wir auswählen install im Feld mit den Befehlen. In Nuspec File Name geben wir den Namen des gewünschten Pakets ein – pvs-studio. Wenn wir die Version nicht angeben, wird die neueste installiert, was für uns völlig in Ordnung ist. Klicken wir auf die Schaltfläche add und sehen wir die generierte Aufgabe in der Konfigurationsdatei.
steps:
- task: ChocolateyCommand@0
inputs:
command: 'install'
installPackageId: 'pvs-studio'Lass uns nun zum Hauptteil unserer Datei übergehen:
- task: CmdLine@2
inputs:
script: Jetzt müssen wir eine Lizenzdatei für den Analyzer erstellen. Hier PVSNAME und PVSKEY – das sind die Namen der Variablen, deren Werte wir in den Einstellungen angeben. Sie werden den Login und den Lizenzschlüssel von PVS-Studio speichern. Um ihre Werte festzulegen, öffnen wir das Menü Variablen->Neue Variable. Wir erstellen Variablen PVSNAME für den Login und PVSKEY für den Schlüssel des Analyzers. Vergessen Sie nicht, das Häkchen Wert geheim halten für PVSKEY. Der Befehlscode lautet:
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials
–u $(PVSNAME) –n $(PVSKEY)Wir bauen das Projekt mithilfe der bat-Datei zusammen, die im Repository liegt:
call build.batWir erstellen einen Ordner, in dem die Dateien mit den Ergebnissen der Analyse gespeichert werden:
call mkdir PVSTestResultsWir starten die Analyse des Projekts:
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog Wir konvertieren unseren Bericht in das html-Format mithilfe des PlogConverter-Tools:
call "C:Program Files (x86)PVS-StudioPlogConverter.exe"
–t html –o PVSTestResults.PVSTestResultsChoco.plogJetzt müssen wir eine Aufgabe erstellen, um den Bericht exportieren zu können.
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: PVSTestResults
artifactName: PVSTestResults
condition: always()Die vollständige 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()Klicken wir Speichern->Speichern->Ausführen Um die Aufgabe auszuführen. Wir werden den Bericht herunterladen, indem wir zum Aufgabentab wechseln.
Das Chocolatey-Projekt enthält insgesamt 37.615 Zeilen C#-Code. Schauen wir uns einige der gefundenen Fehler an.
Überprüfungsergebnisse
Warnung Nr. 1
Warnung des Analysewerkzeugs: 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 Analyzer hat eine Zuweisung der Variablen zu sich selbst festgestellt, was keinen Sinn ergibt. Wahrscheinlich sollte anstelle einer dieser Variablen eine andere stehen. Oder es handelt sich um einen Tippfehler, und die überflüssige Zuweisung kann einfach entfernt werden.
Warnung N2
Warnung des Analysewerkzeugs: [CWE-480] Der ‚&‘ Operator evaluiert beide Operanden. Vielleicht 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;
}
}Der Unterschied zwischen dem Operator & und dem Operator && besteht darin, dass, wenn der linke Teil des Ausdrucks false, trotzdem der rechte Teil ausgewertet wird, was in diesem Fall überflüssige Methodenaufrufe impliziert system.directory_exists.
In dem betrachteten Fragment handelt es sich um ein kleines Versehen. Ja, diese Bedingung kann optimiert werden, indem der Operator & durch den Operator && ersetzt wird, aber aus praktischer Sicht hat das keine Auswirkung. In anderen Fällen kann jedoch die Verwirrung zwischen & und && ernsthafte Probleme verursachen, wenn der rechte Teil des Ausdrucks mit ungültigen/inkorrekten Werten arbeitet. Zum Beispiel haben wir in unserer Fehlerkollektion, , einen solchen Fall:
if ((k < nct) & (s[k] != 0.0))Selbst wenn der Index k ist ungültig und wird zum Zugriff auf das Array-Element verwendet. Daher wird eine Ausnahme generiert. IndexOutOfRangeException.
Warnungen N3, N4
Warnung des Analysewerkzeugs: [CWE-571] Ausdruck ‘shortPrompt’ ist immer wahr. InteractivePrompt.cs 101
Warnung des Analysewerkzeugs: [CWE-571] 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 gibt es eine seltsame Logik der Funktionsweise des ternären Operators. Lassen Sie uns näher betrachten: Wenn die Bedingung, die ich mit der Nummer 1 markiert habe, erfüllt ist, gehen wir zur Bedingung 2 über, die immer true, was bedeutet, dass Zeile 3 ausgeführt wird. Wenn jedoch Bedingung 1 falsch ist, gehen wir zur Zeile mit der Nummer 4, deren Bedingung ebenfalls immer true, was bedeutet, dass Zeile 5 ausgeführt wird. Somit werden die Bedingungen, die mit Kommentar 0 markiert sind, niemals erfüllt, was möglicherweise nicht die Logik ist, die der Programmierer erwartet hat.
Warnung N5
Warnung des Analysewerkzeugs: [CWE-783] Vielleicht funktioniert der ‘?:’ Operator anders als erwartet. Seine Priorität ist niedriger als die anderer Operatoren in seiner Bedingung. Options.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 = 0 && j != 0 ? description [j++ - 1] == '{' : false);
....
return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
}
}Die Diagnose wurde für die Zeile ausgelöst:
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)Da die Variable j ein paar Zeilen weiter oben mit null initialisiert wird, gibt der ternäre Operator den Wert zurück false. Aufgrund dieser Bedingung wird der Schleifeninhalt nur einmal ausgeführt. Ich denke, dieser Codeabschnitt funktioniert ganz anders, als der Programmierer beabsichtigt hat.
Warnung N6
Warnung des Analysewerkzeugs: [CWE-571] 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 = "Alle Versionen";
if (installedPackageVersions.Count != 1)
{
choices.Add(allVersionsChoice);
}
....
}
....
}Hier ist eine seltsame verschachtelte Bedingung: installedPackageVersions.Count != 1, die immer wahr sein wird true. Diese Warnung deutet oft auf einen logischen Fehler im Code hin, in anderen Fällen auf übermäßige Prüfungen.
Warnung N7
Warnung des Analysewerkzeugs: Es gibt identische Unterausdrücke 'commandArguments.contains("-apikey")' links und rechts des '||' Operators. 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 verfasst hat, hat die letzten beiden Zeilen kopiert und vergessen, sie zu bearbeiten. Dadurch haben Nutzer von Chocolatey die Möglichkeit verloren, den Parameter apikey auf andere Weise zu verwenden. Ähnlich wie bei den oben genannten Parametern schlage ich die folgenden Varianten vor:
commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");Copy-Paste-Fehler treten in Projekten mit umfangreichem Quellcode früher oder später häufig auf. Eines der besten Mittel zu ihrer Bekämpfung ist die statische Analyse.
P.S. Und wie immer neigt dieser Fehler dazu, am Ende einer mehrzeiligen Bedingung aufzutreten :). Siehe Beitrag "".
Warnung N8
Warnung des Analysewerkzeugs: [CWE-476] Das Objekt 'installedPackage' wurde verwendet, bevor es auf null überprüft wurde. Überprüfen Sie die Zeilen: 910, 917. NugetService.cs 910
public virtual ConcurrentDictionary 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 wird das Objekt installedPackage verwendet und dann auf nullüberprüft. Diese Diagnose weist auf eines von zwei Problemen im Programm hin: Entweder installedPackage niemals gleich null, was fraglich ist, und dann wäre die Überprüfung überflüssig, oder wir könnten potenziell einen ernsthaften Fehler im Code erhalten – einen Versuch, auf einen Nullverweis zuzugreifen.
Fazit
Wir haben einen weiteren kleinen Schritt gemacht – die Nutzung von PVS-Studio ist jetzt noch einfacher und bequemer. Ich möchte auch sagen, dass Chocolatey ein guter Paketmanager ist, der nur wenige Fehler im Code aufweist, von denen es noch weniger geben könnte, wenn PVS-Studio verwendet wird.
Wir laden ein und PVS-Studio auszuprobieren. Die regelmäßige Nutzung des statischen Analysators wird die Qualität und Zuverlässigkeit des von Ihrem Team entwickelten Codes verbessern und viele .
P.S.
Vor der Veröffentlichung haben wir den Artikel den Entwicklern von Chocolatey zugesandt, und sie haben ihn gut aufgenommen. Wir haben nichts Kritisches gefunden, aber sie waren zum Beispiel von dem Fehler beeindruckt, den wir mit dem Schlüssel „api-key“ gefunden haben.
Falls Sie diesen Artikel mit einem englischsprachigen Publikum teilen möchten, verwenden Sie bitte den Link zur Übersetzung: Vladislav Stolyarov. .
Quelle: habr.com
