PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a
Nastavljamo da činimo korištenje PVS-Studio praktičnijim. Naš analizator je sada dostupan u Chocolatey, paket menadžeru za Windows. Vjerujemo da će ovo olakšati implementaciju PVS-Studio, posebno u cloud servisima. Da ne bismo otišli daleko, provjerimo izvorni kod iste Chocolatey. Azure DevOps će djelovati kao CI sistem.

Evo liste naših drugih članaka na temu integracije sa cloud sistemima:

Savjetujem vam da obratite pažnju na prvi članak o integraciji sa Azure DevOps-om, jer su u ovom slučaju neke tačke izostavljene kako se ne bi duplicirale.

Dakle, junaci ovog članka:

PVS Studio je alat za statičnu analizu koda dizajniran za identifikaciju grešaka i potencijalnih ranjivosti u programima napisanim na C, C++, C# i Javi. Radi na 64-bitnim Windows, Linux i macOS sistemima i može analizirati kod dizajniran za 32-bitne, 64-bitne i ugrađene ARM platforme. Ako vam je ovo prvi put da pokušavate statičku analizu koda kako biste provjerili svoje projekte, preporučujemo da se upoznate s njima članak o tome kako brzo pogledati najzanimljivija upozorenja PVS-Studio i procijeniti mogućnosti ovog alata.

Azure DevOps — skup usluga u oblaku koji zajedno pokrivaju cijeli proces razvoja. Ova platforma uključuje alate kao što su Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, koji vam omogućavaju da ubrzate proces kreiranja softvera i poboljšate njegov kvalitet.

Chocolatey je upravitelj paketa otvorenog koda za Windows. Cilj projekta je automatizacija cjelokupnog životnog ciklusa softvera od instalacije do ažuriranja i deinstalacije na Windows operativnim sistemima.

O korištenju Chocolatey

Ovdje možete vidjeti kako instalirati sam upravitelj paketa link. Kompletna dokumentacija za ugradnju analizatora dostupna je na adresi link Pogledajte odjeljak Instalacija pomoću Chocolatey menadžera paketa. Ukratko ću ponoviti neke tačke odatle.

Naredba za instaliranje najnovije verzije analizatora:

choco install pvs-studio

Naredba za instaliranje određene verzije paketa PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

Podrazumevano je instalirano samo jezgro analizatora, komponenta Core. Sve ostale zastavice (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) mogu se proslijediti pomoću --package-parameters.

Primjer naredbe koja će instalirati analizator s dodatkom za Visual Studio 2019:

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

Pogledajmo sada primjer zgodne upotrebe analizatora pod Azure DevOps.

podešavanje

Dozvolite mi da vas podsjetim da postoji poseban odjeljak o takvim pitanjima kao što su registracija naloga, kreiranje Build Pipeline-a i sinhronizacija vašeg naloga sa projektom koji se nalazi u GitHub repozitorijumu. članak. Naše podešavanje će odmah započeti pisanjem konfiguracijske datoteke.

Prvo, postavimo pokretač pokretanja, koji označava da pokrećemo samo za promjene u majstor grana:

trigger:
- master

Zatim moramo odabrati virtuelnu mašinu. Za sada će to biti agent koji hostuje Microsoft sa Windows Server 2019 i Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

Prijeđimo na tijelo konfiguracijske datoteke (block koraci). Uprkos činjenici da ne možete instalirati proizvoljan softver u virtuelnu mašinu, nisam dodao Docker kontejner. Možemo dodati Chocolatey kao ekstenziju za Azure DevOps. Da bismo to uradili, idemo na link. Kliknite Oslobodite ga. Zatim, ako ste već ovlašteni, jednostavno odaberite svoj račun, a ako niste, učinite istu stvar nakon autorizacije.

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Ovdje trebate odabrati gdje ćemo dodati ekstenziju i kliknite na dugme Instaliraj.

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Nakon uspješne instalacije, kliknite Nastavite sa organizacijom:

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Sada možete vidjeti predložak za zadatak Chocolatey u prozoru zadaci prilikom uređivanja konfiguracijske datoteke azure-pipelines.yml:

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Kliknite na Chocolatey i pogledajte listu polja:

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Ovdje trebamo odabrati instalirajte na terenu sa timovima. IN Nuspec Ime datoteke navedite naziv potrebnog paketa – pvs-studio. Ako ne navedete verziju, biće instalirana najnovija, što nam u potpunosti odgovara. Hajde da pritisnemo dugme dodati i vidjet ćemo generirani zadatak u konfiguracijskoj datoteci.

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

Dalje, idemo na glavni dio našeg fajla:

- task: CmdLine@2
  inputs:
    script: 

Sada treba da kreiramo fajl sa licencom analizatora. Evo PVSNAME и PVSKEY – imena varijabli čije vrijednosti navodimo u postavkama. Oni će pohraniti PVS-Studio login i licencni ključ. Da biste postavili njihove vrijednosti, otvorite meni Varijable->Nova varijabla. Kreirajmo varijable PVSNAME za prijavu i PVSKEY za ključ analizatora. Ne zaboravite označiti polje Čuvajte ovu vrijednost u tajnosti do PVSKEY. Šifra komande:

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

Hajde da napravimo projekat koristeći bat fajl koji se nalazi u spremištu:

сall build.bat

Kreirajmo fasciklu u kojoj će biti pohranjeni fajlovi sa rezultatima analizatora:

сall mkdir PVSTestResults

Počnimo sa analizom projekta:

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

Konvertujemo naš izvještaj u html format pomoću uslužnog programa PlogSonverter:

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

Sada morate kreirati zadatak kako biste mogli učitati izvještaj.

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

Kompletan konfiguracijski fajl izgleda ovako:

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()

Hajde da kliknemo Sačuvaj->Sačuvaj->Pokreni da pokrenete zadatak. Preuzmimo izvještaj tako što ćemo otići na karticu zadaci.

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Projekat Chocolatey sadrži samo 37615 linija C# koda. Pogledajmo neke od pronađenih grešaka.

Rezultati testa

Upozorenje N1

Upozorenje analizatora: V3005 Varijabla 'Provider' je dodijeljena samoj sebi. CrytpoHashProviderSpecs.cs 38

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

Analizator je otkrio dodjelu varijable samoj sebi, što nema smisla. Najvjerovatnije bi umjesto jedne od ovih varijabli trebala biti neka druga. Pa, ili je ovo greška u kucanju, a dodatni zadatak se jednostavno može ukloniti.

Upozorenje N2

Upozorenje analizatora: V3093 [CWE-480] Operator '&' procjenjuje oba operanda. Možda bi se umjesto toga trebao koristiti operator kratkog spoja '&&'. 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;
  }
}

Razlika u operateru & od operatera && je da ako je lijeva strana izraza lažan, tada će desna strana i dalje biti izračunata, što u ovom slučaju podrazumijeva nepotrebne pozive metoda system.directory_exists.

U razmatranom fragmentu ovo je manji nedostatak. Da, ovaj uslov se može optimizirati zamjenom operatora & operatorom &&, ali s praktične tačke gledišta, to ne utiče ni na šta. Međutim, u drugim slučajevima, zbrka između & i && može uzrokovati ozbiljne probleme kada se desna strana izraza tretira netačnim/nevažećim vrijednostima. Na primjer, u našoj kolekciji grešaka, identificiran pomoću V3093 dijagnostike, postoji ovaj slučaj:

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

Čak i ako je indeks k je netačan, koristit će se za pristup elementu niza. Kao rezultat toga, bit će izbačen izuzetak IndexOutOfRangeException.

Upozorenja N3, N4

Upozorenje analizatora: V3022 [CWE-571] Izraz 'shortPrompt' je uvijek istinit. InteractivePrompt.cs 101
Upozorenje analizatora: V3022 [CWE-571] Izraz 'shortPrompt' je uvijek istinit. 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
    ....
  }
  ....
}

U ovom slučaju, postoji čudna logika iza rada ternarnog operatora. Pogledajmo bliže: ako je ispunjen uslov koji sam označio brojem 1, onda ćemo preći na uslov 2, koji je uvek istinski, što znači da će se izvršiti red 3. Ako se ispostavi da je uslov 1 netačan, onda ćemo preći na red označen brojem 4, uslov u kojem je takođe uvek istinski, što znači da će se izvršiti red 5. Dakle, uslovi označeni komentarom 0 nikada neće biti ispunjeni, što možda nije baš logika rada koju je programer očekivao.

Upozorenje N5

Upozorenje analizatora: V3123 [CWE-783] Možda operator '?:' radi na drugačiji način nego što se očekivalo. Njegov prioritet je niži od prioriteta drugih operatera u njegovom stanju. 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 < 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);
  }
}

Dijagnostika je radila za liniju:

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

Pošto je promenljiva j nekoliko redova iznad se inicijalizira na nulu, ternarni operator će vratiti vrijednost lažan. Zbog ovog uslova, tijelo petlje će se izvršiti samo jednom. Čini mi se da ovaj dio koda uopće ne radi kako je programer zamislio.

Upozorenje N6

Upozorenje analizatora: V3022 [CWE-571] Izraz 'installedPackageVersions.Count != 1' je uvijek istinit. 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);
    }
    ....
  }
  ....
}

Ovdje je čudno ugniježđeno stanje: InstalledPackageVersions.Count != 1što će uvek biti istinski. Često takvo upozorenje ukazuje na logičku grešku u kodu, au drugim slučajevima jednostavno ukazuje na suvišnu provjeru.

Upozorenje N7

Upozorenje analizatora: V3001 Postoje identični podizrazi 'commandArguments.contains("-apikey")' lijevo i desno od '||' operater. 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");
}

Programer koji je napisao ovaj dio koda je kopirao i zalijepio zadnja dva reda i zaboravio ih urediti. Zbog toga korisnici Chocolatey-a nisu mogli primijeniti parametar apikey još par načina. Slično gore navedenim parametrima, mogu ponuditi sljedeće opcije:

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

Copy-paste greške imaju velike šanse da se pojave prije ili kasnije u bilo kojem projektu s velikom količinom izvornog koda, a jedan od najboljih alata za borbu protiv njih je statička analiza.

PS I kao i uvijek, ova greška ima tendenciju da se pojavi na kraju višelinijskog uvjeta :). Pogledajte publikaciju "Efekat poslednje linije".

Upozorenje N8

Upozorenje analizatora: V3095 [CWE-476] Objekt 'installedPackage' je korišten prije nego što je verifikovan u odnosu na null. Provjerite linije: 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)
  {
    ....
  }
  ....
}

Klasična greška: objekt prvi InstalledPackage se koristi, a zatim se provjerava null. Ova dijagnostika nam govori o jednom od dva problema u programu: bilo koji InstalledPackage nikad jednaka null, što je sumnjivo, a onda je provjera suvišna ili bismo potencijalno mogli dobiti ozbiljnu grešku u kodu - pokušaj pristupa nultoj referenci.

zaključak

Dakle, napravili smo još jedan mali korak - sada je korištenje PVS-Studio postalo još lakše i praktičnije. Takođe bih želeo da kažem da je Chocolatey dobar menadžer paketa sa malim brojem grešaka u kodu, kojih bi moglo biti i manje kada koristite PVS-Studio.

Pozivamo скачать i isprobajte PVS-Studio. Redovna upotreba statičkog analizatora poboljšat će kvalitetu i pouzdanost koda koji vaš tim razvija i pomoći će spriječiti mnoge ranjivosti nultog dana.

PS

Prije objavljivanja, poslali smo članak Chocolatey programerima i oni su ga dobro primili. Nismo našli ništa kritično, ali njima se, na primjer, svidjela greška koju smo pronašli vezana za ključ "api-key".

PVS-Studio je sada u Chocolateyju: provjeravam Chocolatey ispod Azure DevOps-a

Ako želite da podelite ovaj članak sa publikom koja govori engleski, koristite link za prevod: Vladislav Stolyarov. PVS-Studio je sada u Chocolateyju: Provjeravam Chocolatey pod Azure DevOps-om.

izvor: www.habr.com

Dodajte komentar