PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps
Continuiamo a rendere l'uso di PVS-Studio più semplice. Ora il nostro analizzatore è disponibile su Chocolatey, il gestore di pacchetti per Windows. Riteniamo che questo faciliterà il deployment di PVS-Studio, in particolare nei servizi cloud. Per non andare lontano, controlliamo il codice sorgente dello stesso Chocolatey. Come sistema CI utilizzeremo Azure DevOps.

Ecco un elenco di altri nostri articoli sull'integrazione con i sistemi cloud:

Vi consiglio di prestare attenzione al primo articolo sull'integrazione con Azure DevOps, poiché in questo caso alcuni punti sono stati omessi per evitare ripetizioni.

Quindi, i protagonisti di questo articolo sono:

PVS-Studio — uno strumento di analisi statica del codice, progettato per individuare errori e potenziali vulnerabilità nei programmi scritti in C, C++, C# e Java. Funziona su sistemi a 64 bit su Windows, Linux e macOS, e può analizzare codice destinato a piattaforme ARM integrate, a 32 bit e a 64 bit. Se provate per la prima volta l'analisi statica del codice per controllare i vostri progetti, vi consigliamo di consultare il articolo su come visualizzare rapidamente gli avvisi più interessanti di PVS-Studio e valutare le capacità di questo strumento.

Azure DevOps — insieme di servizi cloud che coprono l'intero processo di sviluppo. All'interno di questa piattaforma ci sono strumenti come Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, che consentono di accelerare il processo di creazione del software e di migliorarne la qualità.

Chocolatey – gestore di pacchetti per Windows con codice sorgente aperto. L'obiettivo del progetto è automatizzare l'intero ciclo di vita del software, dall'installazione all'aggiornamento e alla rimozione nei sistemi operativi Windows.

Sull'uso di Chocolatey

Puoi vedere come installare il gestore di pacchetti stesso tramite questo link. La documentazione completa per l'installazione dell'analizzatore è disponibile su link nella sezione 'Installazione utilizzando il gestore di pacchetti Chocolatey'. Ricapitolando brevemente alcuni punti da lì.

Il comando per installare l'ultima versione dell'analizzatore:

choco install pvs-studio

Il comando per installare una versione specifica del pacchetto PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

Per impostazione predefinita viene installato solo il nucleo dell'analizzatore: il componente Core. Tutti gli altri flag (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) possono essere passati tramite —package-parameters.

Ecco un esempio di comando che installerà l'analizzatore con il plugin per Visual Studio 2019:

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

Vediamo ora un esempio di utilizzo pratico dell'analizzatore in Azure DevOps.

Configurazione

Ricordo che ci sono aspetti come la registrazione di un account, la creazione di un Build Pipeline e la sincronizzazione dell'account con un progetto in repository su GitHub, per i quali esiste un su Habr.. La nostra configurazione inizierà direttamente dalla scrittura del file di configurazione.

Iniziamo impostando il trigger di avvio, indicando che ci attiviamo solo per modifiche in master ramo:

trigger:
- master

Successivamente dobbiamo scegliere una macchina virtuale. Al momento, questo sarà un agente Microsoft-hosted con Windows Server 2019 e Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

Passiamo al corpo del file di configurazione (blocco steps). Sebbene non sia possibile installare software arbitrario sulla macchina virtuale, non ho aggiunto un contenitore Docker. Possiamo aggiungere Chocolatey come estensione per Azure DevOps. Per fare ciò, andiamo su link. Facciamo clic su Get it free. Successivamente, se siete già autenticati, selezionate semplicemente il vostro account, altrimenti seguite la stessa procedura dopo l'autenticazione.

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Qui è necessario scegliere dove aggiungere l'estensione e premere il pulsante Installa.

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Dopo una corretta installazione, faremo clic su Proceed to organization:

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Ora possiamo vedere il modello per il task Chocolatey nella finestra tasks mentre modifichiamo il file di configurazione azure-pipelines.yml:

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Facciamo clic su Chocolatey e vediamo l'elenco dei campi:

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Qui dobbiamo scegliere install nel campo dei comandi. In Nuspec File Name indicheremo il nome del pacchetto necessario – pvs-studio. Se non viene specificata una versione, verrà installata l'ultima, che ci va bene. Fare clic sul pulsante add e vedremo il task generato nel file di configurazione.

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

Procediamo ora alla parte principale del nostro file:

- task: CmdLine@2
  inputs:
    script: 

Ora dobbiamo creare un file con la licenza dell'analizzatore. Qui PVSNAME e PVSKEY – sono i nomi delle variabili, i cui valori specifichiamo nelle impostazioni. Queste conterranno il login e la chiave di licenza di PVS-Studio. Per impostare i loro valori, apriamo il menu Variables->New variable. Creiamo variabili PVSNAME per il login e PVSKEY per la chiave dell'analizzatore. Non dimenticare di selezionare la casella Mantieni questo valore segreto per PVSKEY. Codice del comando:

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

Compiliamo il progetto utilizzando il file bat presente nel repository:

call build.bat

Creiamo una cartella dove verranno memorizzati i file dei risultati dell'analizzatore:

call mkdir PVSTestResults

Avviamo l'analisi del progetto:

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

Convertiamo il nostro rapporto in formato html utilizzando lo strumento PlogConverter:

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

Ora dobbiamo creare un compito per poter esportare il rapporto.

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

Il file di configurazione completo appare così:

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

Clicchiamo Salva->Salva->Esegui per avviare il compito. Esporteremo il rapporto accedendo alla scheda dei compiti.

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Il progetto Chocolatey contiene solo 37615 righe di codice C#. Esaminiamo alcuni degli errori trovati.

Risultati della verifica

Warning N1

Avviso dell'analizzatore: V3005 La variabile ‘Provider’ è assegnata a se stessa. CrytpoHashProviderSpecs.cs 38

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

L'analizzatore ha rilevato un'assegnazione della variabile a se stessa, il che non ha senso. Probabilmente, in uno di questi casi, dovrebbe esserci un'altra variabile. Oppure potrebbe essere un errore di battitura e l'assegnazione extra può essere semplicemente eliminata.

Warning N2

Avviso dell'analizzatore: V3093 [CWE-480] L'operatore ‘&’ valuta entrambi gli operandi. Forse si dovrebbe utilizzare invece un operatore di corto circuito ‘&&’. 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;
  }
}

La differenza tra l'operatore & e l'operatore && risiede nel fatto che se la parte sinistra dell'espressione — false, ciò nonostante verrà calcolata la parte destra, il che in questo caso implica chiamate non necessarie al metodo system.directory_exists.

Nel frammento esaminato si tratta di una piccola imprecisione. Sì, questa condizione può essere ottimizzata sostituendo l'operatore & con l'operatore &&, ma, da un punto di vista pratico, non influisce su nulla. Tuttavia, in altri casi la confusione tra & e && può causare seri problemi, quando la parte destra dell'espressione lavora con valori non corretti/additivi. Ad esempio, nella nostra raccolta di errori, identificati tramite la diagnosi V3093, c'è un caso come questo:

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

Anche se l'indice k è errato, sarà utilizzato per accedere all'elemento dell'array. Di conseguenza verrà generata un'eccezione IndexOutOfRangeException.

Avvisi N3, N4

Avviso dell'analizzatore: V3022 [CWE-571] L'espressione ‘shortPrompt’ è sempre vera. InteractivePrompt.cs 101
Avviso dell'analizzatore: V3022 [CWE-571] L'espressione ‘shortPrompt’ è sempre vera. 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 questo caso si presenta una strana logica di funzionamento dell'operatore ternario. Esaminiamo più da vicino: se viene soddisfatta la condizione contrassegnata dal numero 1, passeremo alla condizione 2, che è sempre true, il che significa che verrà eseguita la riga 3. Se la condizione 1 risulta falsa, passeremo alla riga contrassegnata dal numero 4, la condizione di cui è sempre true, il che significa che verrà eseguita la riga 5. Pertanto, le condizioni contrassegnate dal commento 0 non verranno mai eseguite, il che potrebbe non essere esattamente la logica che si aspettava il programmatore.

V587

Avviso dell'analizzatore: V3123 [CWE-783] Forse l'operatore ‘?:’ funziona in un modo diverso rispetto a quanto ci si aspettava. La sua priorità è inferiore a quella di altri operatori nella sua condizione. 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);
  }
}

La diagnosi ha attivato la linea:

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

Poiché la variabile j Alcuni righe sopra è inizializzato a zero, l'operatore ternario restituirà un valore false. A causa di questa condizione, il corpo del ciclo verrà eseguito solo una volta. Mi sembra che questo frammento di codice non funzioni come previsto dallo sviluppatore.

Avviso N6

Avviso dell'analizzatore: V3022 [CWE-571] L'espressione ‘installedPackageVersions.Count != 1’ è sempre vera. NugetService.cs 1405

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

Qui c'è una strana condizione annidata: installedPackageVersions.Count != 1, che sarà sempre true. Spesso questo avviso indica un errore logico nel codice, mentre in altri casi è semplicemente un controllo eccessivo.

Avviso N7

Avviso dell'analizzatore: V3001 Ci sono sub-espressioni identiche ‘commandArguments.contains("-apikey")’ a sinistra e a destra dell'operatore ‘||’. 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");
}

Lo sviluppatore che ha scritto questo frammento di codice ha copiato e incollato le ultime due righe e ha dimenticato di modificarle. A causa di ciò, gli utenti di Chocolatey hanno perso la possibilità di utilizzare il parametro apikey in altri modi. Analogamente ai parametri sopra, posso suggerire le seguenti opzioni:

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

Gli errori di copia e incolla hanno una grande probabilità di apparire, prima o poi, in qualsiasi progetto con una grande quantità di codice sorgente, e uno dei migliori strumenti per combatterli è l'analisi statica.

P.S. E come sempre, questo errore tende a comparire alla fine di una condizione multi-linea :). Vedi la pubblicazione "Effetto dell'ultima riga".

Avviso N8

Avviso dell'analizzatore: V3095 [CWE-476] L'oggetto ‘installedPackage’ è stato utilizzato prima di essere verificato contro null. Controllare le righe: 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)
  {
    ....
  }
  ....
}

Errore classico: l'oggetto viene utilizzato prima di essere verificato installedPackage per null. Questa diagnosi ci parla di uno dei due problemi nel programma: o installedPackage non è mai uguale a null, il che è dubbio, e quindi il controllo è superfluo, oppure possiamo potenzialmente avere un serio errore nel codice – un tentativo di accesso tramite un riferimento nullo.

Conclusione

Ecco che abbiamo fatto un altro piccolo passo – ora utilizzare PVS-Studio è diventato ancora più semplice e pratico. Vorrei anche dire che Chocolatey è un buon gestore di pacchetti con un numero ridotto di errori nel codice, che potrebbero essere ancora di meno con l'uso di PVS-Studio.

Ti invitiamo scaricare e provare PVS-Studio. L'uso regolare dell'analizzatore statico migliorerà la qualità e l'affidabilità del codice sviluppato dal vostro team e aiuterà a prevenire molte vulnerabilità a zero giorni.

P.S.

Prima della pubblicazione, abbiamo inviato l'articolo agli sviluppatori di Chocolatey, e loro l'hanno accolto bene. Non abbiamo trovato nulla di critico, ma a loro, ad esempio, è piaciuto l'errore che abbiamo trovato relativo alla chiave "api-key".

PVS-Studio ora disponibile in Chocolatey: verifica di Chocolatey da Azure DevOps

Se desideri condividere questo articolo con un pubblico anglofono, ti prego di utilizzare il link alla traduzione: Vladislav Stolyarov. PVS-Studio è ora in Chocolatey: Controllo di Chocolatey sotto Azure DevOps.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster