
Continuăm să facem utilizarea PVS-Studio mai confortabilă. Acum, analizorul nostru este disponibil în Chocolatey, managerul de pachete pentru Windows. Credem că acest lucru va facilita desfășurarea PVS-Studio, în special în serviciile de cloud. Pentru a nu ne abate, să verificăm codul sursă al aceluiași Chocolatey. Sistemul CI va fi Azure DevOps.
Iată lista altor articole de-ale noastre pe tema integrării cu sistemele de cloud:
Recomand să acordați atenție primului articol despre integrarea cu Azure DevOps, deoarece în acest caz au fost omise anumite aspecte pentru a nu se repeta.
Așadar, eroii acestui articol sunt:
— un instrument de analiză statică a codului, destinat identificării erorilor și vulnerabilităților potențiale în programele scrise în limbajele C, C++, C# și Java. Funcționează pe sisteme de 64 de biți pe Windows, Linux și macOS și poate analiza cod destinat platformelor ARM de 32 de biți, 64 de biți și încorporate. Dacă încercați pentru prima dată analiza statică a codului pentru a verifica proiectele dumneavoastră, vă recomandăm să consultați despre cum să vizualizați rapid cele mai interesante avertizări PVS-Studio și să evaluați posibilitățile acestui instrument.
— un set de servicii cloud care acoperă în mod colaborativ întregul proces de dezvoltare. Această platformă include instrumente precum Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, care permit accelerarea procesului de creare a software-ului și îmbunătățirea calității acestuia.
– un manager de pachete pentru Windows cu sursă deschisă. Scopul proiectului este de a automatiza întregul ciclu de viață al software-ului, de la instalare la actualizare și ștergere în sistemele de operare Windows.
Despre utilizarea Chocolatey
Puteți vedea cum să instalați managerul de pachete vizitând această . Documentația completă pentru instalarea analizorului este disponibilă la în secțiunea „Instalare folosind managerul de pachete Chocolatey”. Pe scurt, voi repeta câteva puncte de acolo.
Comanda pentru instalarea celei mai recente versiuni a analizorului:
choco install pvs-studioComanda pentru instalarea unei versiuni specifice a pachetului PVS-Studio:
choco install pvs-studio --version=7.05.35617.2075Implicit este instalat doar nucleul analizei - componenta Core. Toate celelalte flag-uri (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) pot fi transmise prin intermediul —package-parameters.
Exemplu de comandă care va instala analiza cu plugin pentru Visual Studio 2019:
choco install pvs-studio --package-parameters="'\/MSVS2019'"Acum să ne uităm la un exemplu de utilizare ușoară a analizei sub Azure DevOps.
Configurare
Îmi amintesc că pentru aspecte precum înregistrarea contului, crearea unui Build Pipeline și sincronizarea contului cu proiectul din repository-ul de pe GitHub, există un ghid separat. . Configurarea noastră va începe direct cu scrierea fișierului de configurare.
Pentru început, să configurăm trigger-ul de pornire, specificând că facem pornirea doar pentru modificările din master ramura:
trigger:
- masterUrmătoarea etapă este să alegem mașina virtuală. Deocamdată, aceasta va fi un agent Microsoft-hosted cu Windows Server 2019 și Visual Studio 2019:
pool:
vmImage: 'windows-latest'Să trecem la corpul fișierului de configurare (bloc steps). Deși nu putem instala software arbitrar pe mașina virtuală, nu am adăugat un container Docker. Putem adăuga Chocolatey ca extensie pentru Azure DevOps. Pentru aceasta, accesați . Apăsați Get it free. Apoi, dacă sunteți deja autentificat, alegeți contul dvs., iar dacă nu, faceți aceleași lucruri după autentificare.

Aici trebuie să selectați unde vom adăuga extensia și să apăsați butonul Instalează.

După instalare, apăsați Proceed to organization:

Acum putem vedea un șablon pentru sarcina Chocolatey în fereastra tasks când edităm fișierul de configurare azure-pipelines.yml:

Apăsați pe Chocolatey și veți vedea lista de câmpuri:

Aici trebuie să alegem install în câmpul cu comenzi. În Nuspec File Name vom indica numele pachetului necesar - pvs-studio. Dacă nu specificați versiunea, se va instala ultima, ceea ce ne satisface pe deplin. Apăsați pe butonul add și vom vedea sarcina generată în fișierul de configurare.
steps:
- task: ChocolateyCommand@0
inputs:
command: 'install'
installPackageId: 'pvs-studio'Apoi să trecem la partea principală a fișierului nostru:
- task: CmdLine@2
inputs:
script: Acum trebuie să creăm un fișier cu licența analizei. Aici PVSNAME și PVSKEY – sunt denumirile variabilelor, valorile cărora le vom specifica în setări. Acestea vor păstra login-ul și cheia de licență PVS-Studio. Pentru a le seta valorile, deschideți meniul Variables->New variable. Să creăm variabilele PVSNAME pentru login și PVSKEY pentru cheia analizoarelor. Nu uitați să bifați căsuța Păstrați acest valoare secretă pentru PVSKEY. Codul comenzii:
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials
–u $(PVSNAME) –n $(PVSKEY)Să compilăm proiectul folosind fișierul bat aflat în repository:
call build.batVom crea un folder unde vor fi stocate fișierele cu rezultatele analizei:
call mkdir PVSTestResultsVom lansa analiza proiectului:
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog Vom converti raportul nostru în format html folosind utilitarul PlogConverter:
call "C:Program Files (x86)PVS-StudioPlogConverter.exe"
–t html –o PVSTestResults .PVSTestResultsChoco.plogAcum trebuie să creăm o sarcină pentru a putea exporta raportul.
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: PVSTestResults
artifactName: PVSTestResults
condition: always()Fișierul complet de configurare arată astfel:
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()Să facem clic Save->Save->Run pentru a lansa sarcina. Vom exporta raportul accesând tab-ul sarcinii.
Proiectul Chocolatey conține în total 37615 linii de cod C#. Să analizăm câteva din erorile identificate.
Rezultatele verificării
Avertisment N1
Avertisment al analizoarei: Variabila 'Provider' este asignată ei însăși. CrytpoHashProviderSpecs.cs 38
public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
....
protected CryptoHashProvider Provider;
....
public override void Context()
{
Provider = Provider = new CryptoHashProvider(FileSystem.Object);
}
}Analizorul a descoperit o atribuire a variabilei către sine, ceea ce nu are sens. Probabil că în locul uneia dintre aceste variabile ar trebui să existe o altă variabilă. Sau ar putea fi o greșeală de tipar, iar atribuirea suplimentară poate fi pur și simplu ștearsă.
Avertisment N2
Avertisment al analizoarei: [CWE-480] Operatorul '&' evaluează ambele operande. Poate ar trebui utilizat în schimb operatorul de scurtcircuit '&&'. 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;
}
}Diferența operatorului & de la operator && constă în faptul că, dacă partea stângă a expresiei — false, va fi totuși calculată partea dreaptă, ceea ce în acest caz implică apeluri redundante ale metodei system.directory_exists.
În fragmentul analizat, acesta este o mică neatenție. Da, această condiție poate fi optimizată, înlocuind operatorul & cu operatorul &&, dar, din punct de vedere practic, acest lucru nu afectează nimic. Totuși, în alte cazuri, confuzia între & și && poate provoca probleme serioase, când partea dreaptă a expresiei va lucra cu valori incorecte/invalid. De exemplu, în colecția noastră de erori, , există un astfel de caz:
if ((k < nct) & (s[k] != 0.0))Chiar dacă indexul k este incorect, va fi folosit pentru a accesa un element al array-ului. Ca rezultat, va fi generată o excepție IndexOutOfRangeException.
Avertizările N3, N4
Avertisment al analizoarei: [CWE-571] Expresia ‘shortPrompt’ este întotdeauna adevărată. InteractivePrompt.cs 101
Avertisment al analizoarei: [CWE-571] Expresia ‘shortPrompt’ este întotdeauna adevărată. 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
....
}
....
}În acest caz există o logică ciudată a operatorului ternar. Să analizăm mai în detaliu: dacă se îndeplinește condiția marcată cu cifra 1, atunci vom trece la condiția 2, care este întotdeauna true, ceea ce înseamnă că se va executa linia 3. Dacă, totuși, condiția 1 se dovedește a fi falsă, atunci vom trece la linia marcată cu cifra 4, condiția care de asemenea este întotdeauna true, ceea ce înseamnă că se va executa linia 5. Astfel, condițiile marcate cu comentariul 0 nu vor fi niciodată îndeplinite, ceea ce poate reprezenta o logică de lucru diferită de cea la care se aștepta programatorul.
Avertizarea N5
Avertisment al analizoarei: [CWE-783] Poate că operatorul ‘?:’ funcționează într-un mod diferit decât era așteptat. Prioritatea sa este mai mică decât prioritatea celorlalte operații din condiția sa. 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);
}
}Diagnosticul a fost activat pe linia:
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)Întrucât variabila j este inițializată cu zero cu câteva linii mai sus, operatorul ternar va returna valoarea false. Din cauza acestei condiții, corpul buclei va fi executat doar o singură dată. Mi se pare că acest fragment de cod nu funcționează deloc așa cum a intenționat programatorul.
Avertizare N6
Avertisment al analizoarei: [CWE-571] Expresia ‘installedPackageVersions.Count != 1’ este întotdeauna adevărată. NugetService.cs 1405
private void remove_nuget_cache_for_package(....)
{
if (!config.AllVersions && installedPackageVersions.Count > 1)
{
const string allVersionsChoice = "Toate versiunile";
if (installedPackageVersions.Count != 1)
{
choices.Add(allVersionsChoice);
}
....
}
....
}Aici este o condiție înfășurată ciudată: installedPackageVersions.Count != 1, care va fi întotdeauna true. Adesea, astfel de avertizări indică o eroare logică în cod, iar în alte cazuri pur și simplu o verificare redundantă.
Avertizare N7
Avertisment al analizoarei: Există sub-expresii identice ‘commandArguments.contains("-apikey")’ pe stânga și pe dreapta operatorului ‘||’. 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");
}Programatorul care a scris acest cod a copiat ultimele două linii și a uitat să le editeze. Din această cauză, utilizatorii Chocolatey au fost privați de posibilitatea de a aplica parametrul apikey în încă câteva moduri. Similar parametrilor de mai sus, pot sugera următoarele variante:
commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");Erorile de tip copiere și lipire au o șansă mare de a apărea mai devreme sau mai târziu în orice proiect cu un volum mare de cod sursă, iar unul dintre cele mai bune instrumente pentru a lupta împotriva lor este analiza statică.
P.S. Și, ca întotdeauna, această eroare tinde să apară la sfârșitul unei condiții multi-linie :). Vezi publicația "".
Avertizare N8
Avertisment al analizoarei: [CWE-476] Obiectul ‘installedPackage’ a fost folosit înainte de a fi verificat împotriva null. Verificați liniile: 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)
{
....
}
....
}Eroare clasică: obiectul este utilizat mai întâi installedPackage și apoi verificat pentru null. Această diagnosticare ne indică una dintre cele două probleme în program: fie installedPackage nu este niciodată egal cu null, ceea ce este îndoielnic, și atunci verificarea este redundantă, fie putem obține o eroare gravă în cod – o încercare de accesare a unei referințe nule.
Concluzie
Iată că am realizat un alt pas mic – acum utilizarea PVS-Studio a devenit și mai simplă și mai convenabilă. De asemenea, vreau să spun că Chocolatey este un bun manager de pachete cu un număr mic de erori în cod, care ar putea să fie și mai puține cu utilizarea PVS-Studio.
Vă invităm să încercați PVS-Studio. Utilizarea regulată a analizatorului static va îmbunătăți calitatea și fiabilitatea codului dezvoltat de echipa dumneavoastră și va ajuta la prevenirea multor .
P.S.
Înainte de publicare, am trimis articolul dezvoltatorilor Chocolatey, iar aceștia l-au primit bine. Nu am găsit nimic critic, dar, de exemplu, le-a plăcut eroarea pe care am identificat-o legată de cheia „api-key”.
Dacă doriți să împărtășiți acest articol cu o audiență anglofonă, vă rog să folosiți linkul la traducere: Vladislav Stolyarov. .
Sursa: habr.com
