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'utilizzo di PVS-Studio più comodo. Ora il nostro analizzatore è disponibile in Chocolatey, il gestore di pacchetti per Windows. Riteniamo che ciò faciliterà il deployment di PVS-Studio, in particolare nei servizi cloud. Per non andare lontano, diamo un'occhiata al codice sorgente dello stesso Chocolatey. Come sistema CI utilizzeremo Azure DevOps.

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

Consiglio di prestare attenzione al primo articolo sull'integrazione con Azure DevOps, poiché in questo caso alcuni dettagli sono omessi per evitare duplicazioni.

Quindi, i protagonisti di questo articolo sono:

PVS-Studio — uno strumento di analisi statica del codice, progettato per identificare errori e potenziali vulnerabilità nei programmi scritti in linguaggi C, C++, C# e Java. Funziona su sistemi a 64 bit su Windows, Linux e macOS, e può analizzare codice destinato a piattaforme ARM 32-bit, 64-bit e embedded. Se stai provando per la prima volta l'analisi statica del codice per verificare i tuoi progetti, ti consigliamo di familiarizzare con articolo su come visualizzare rapidamente i messaggi di avviso più interessanti di PVS-Studio e valutare le funzionalità di questo strumento.

Azure DevOps – un insieme di servizi cloud che coprono l'intero processo di sviluppo. La piattaforma include strumenti come Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, che permettono di accelerare il processo di creazione del software e migliorarne la qualità.

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

L'utilizzo di Chocolatey

Puoi vedere come installare il gestore pacchetti stesso attraverso questo link. La documentazione completa sull'installazione dell'analizzatore è disponibile link nella sezione «Installazione utilizzando il gestore di pacchetti Chocolatey». Riassumerò 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'"

Ora diamo un'occhiata a un esempio di utilizzo pratico dell'analizzatore con Azure DevOps.

Impostazione

Ricordo che per quanto riguarda aspetti come la registrazione di un account, la creazione di un Build Pipeline e la sincronizzazione dell'account con il progetto nel repository su GitHub, ci sono informazioni separate articolo. La nostra configurazione inizierà direttamente dalla scrittura del file di configurazione.

Iniziamo configurando il trigger di avvio, specificando che eseguiamo l'avvio solo per le modifiche in master branch:

trigger:
- master

Dopo occorre selezionare la macchina virtuale. Attualmente 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). Anche se non è possibile installare software arbitrario sulla macchina virtuale, non ho aggiunto un contenitore Docker. Possiamo aggiungere Chocolatey come estensione per Azure DevOps. A tal fine, andiamo su link. Facciamo clic su Ottienilo gratis. Poi, se sei già autenticato, scegli semplicemente il tuo account, altrimenti esegui la stessa operazione dopo l'autenticazione.

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

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

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

Dopo l'installazione riuscita, premeremo Procedi all'organizzazione:

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

Ora è possibile vedere il modello per il compito Chocolatey nella finestra tasks quando si modifica il file di configurazione azure-pipelines.yml:

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

Clicchiamo su Chocolatey e vediamo l'elenco dei campi:

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

Qui dobbiamo scegliere installare nel campo dei comandi. In Nome file Nuspec indicheremo il nome del pacchetto necessario – pvs-studio. Se non viene specificata una versione, verrà installata l'ultima, il che ci soddisfa completamente. Clicchiamo sul pulsante add e vedremo il compito formattato nel file di configurazione.

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

Successivamente, passiamo 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. Essi conterranno il login e la chiave di licenza di PVS-Studio. Per impostare i loro valori, apriamo il menu Variabili->Nuova variabile. Creiamo variabili PVSNAME per il login e PVSKEY per la chiave dell'analizzatore. Non dimenticare di spuntare la casella Tieni 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 nel repository:

call build.bat

Creeremo una cartella dove saranno salvati i file con i 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 report in formato html utilizzando l'utility PlogConverter:

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

Ora dobbiamo creare un'attività per poter esportare il report.

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

Premiamo Salva->Salva->Esegui per avviare il compito. Scaricheremo il rapporto accedendo alla scheda dei compiti.

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

Il progetto Chocolatey contiene un totale di 37615 righe di codice C#. Analizziamo alcuni degli errori trovati.

Risultati dell'analisi

Avviso 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 che la variabile è assegnata a se stessa, il che non ha senso. Probabilmente, al posto di una di queste variabili dovrebbe esserci un'altra variabile. Oppure si tratta di un errore di battitura e l'assegnazione superflua può essere semplicemente rimossa.

Avviso N2

Avviso dell'analizzatore: V3093 [CWE-480] L'operatore ‘&’ valuta entrambi gli operandi. Forse dovrebbe essere usato un operatore di short-circuit ‘&&’ invece. 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 dell'operatore & dell'operatore && sta nel fatto che se la parte sinistra dell'espressione è false, allora sarà comunque calcolata la parte destra, il che in questo caso implica chiamate di metodo superflue system.directory_exists.

Nel frammento considerato, si tratta di un piccolo errore. Sì, questa condizione può essere ottimizzata sostituendo l'operatore & con l'operatore &&, ma, dal punto di vista pratico, ciò non influisce su nulla. Tuttavia, in altri casi, la confusione tra & e && può causare seri problemi, quando la parte destra dell'espressione opera con valori non corretti/non validi. Ad esempio, nella nostra collezione di errori, identificati tramite la diagnosi V3093, c'è questo caso:

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

Anche se l'indice k non corretto, verrà 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 riscontra una logica strana nell'operatore ternario. Analizziamo più nel dettaglio: se la condizione contrassegnata con il numero 1 è vera, passeremo alla condizione 2, che è sempre true, il che significa che verrà eseguita la riga 3. Se la condizione 1 è falsa, passeremo alla riga contrassegnata con il numero 4, in cui anche la condizione è sempre true, il che significa che verrà eseguita la riga 5. Pertanto, le condizioni contrassegnate con il commento 0 non verranno mai eseguite, il che potrebbe non essere la logica che il programmatore si aspettava.

Avviso N5

Avviso dell'analizzatore: V3123 [CWE-783] È possibile che l'operatore '?:' funzioni in modo diverso rispetto alle aspettative. 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 diagnostica ha colpito la stringa:

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

Poiché la variabile j è inizializzata a zero alcune righe sopra, l'operatore ternario restituirà il 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 affatto come programmato dall’autore.

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 = "All versions";
    if (installedPackageVersions.Count != 1)
    {
      choices.Add(allVersionsChoice);
    }
    ....
  }
  ....
}

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

Avviso N7

Avviso dell'analizzatore: V3001 Ci sono espressioni sub-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");
}

Il programmatore che ha scritto questa parte di codice ha semplicemente copiato e incollato le ultime due righe e si è dimenticato di modificarle. Per questo motivo, gli utenti di Chocolatey hanno perso la possibilità di usare il parametro apikey in altri modi. Analogamente ai parametri sopra, posso proporre le seguenti opzioni:

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

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

P.S. E come sempre, questo errore tende a comparire alla fine di una condizione multilinea :). Vedi il post "Effetto dell'ultima riga".

Avviso N8

Avviso dell'analizzatore: V3095 [CWE-476] L'oggetto ‘installedPackage’ è stato utilizzato prima di essere verificato contro null. Controlla 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: all'inizio l'oggetto installedPackage è usato e poi controllato 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 incorrere in un grave errore nel codice: un tentativo di accesso tramite un riferimento nullo.

Conclusione

Ecco che abbiamo fatto un altro piccolo passo: ora usare PVS-Studio è diventato ancora più semplice e comodo. Vorrei anche dire che Chocolatey è un buon gestore di pacchetti con un numero limitato di errori nel codice, che potrebbe diminuire ulteriormente con l'uso di PVS-Studio.

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

P.S.

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

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

Se desiderate condividere questo articolo con un pubblico anglofono, vi prego di utilizzare il link alla traduzione: Vladislav Stolyarov. PVS-Studio è ora su Chocolatey: controllando Chocolatey sotto Azure DevOps.

Fonte: habr.com

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