PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps
Continuamos a tornar o uso do PVS-Studio mais conveniente. Agora nosso analisador está disponível no Chocolatey, um gerenciador de pacotes para Windows. Acreditamos que isso facilitará a implantação do PVS-Studio, especialmente em serviços em nuvem. Para não nos afastarmos muito, vamos verificar o código-fonte do próprio Chocolatey. O Azure DevOps será o sistema de CI.

Aqui está uma lista de nossos outros artigos sobre integração com sistemas em nuvem:

Recomendo prestar atenção ao primeiro artigo sobre integração com o Azure DevOps, pois alguns pontos foram omitidos neste caso para não duplicar informações.

Então, os heróis deste artigo são:

PVS-Studio — uma ferramenta de análise estática de código, destinada a identificar erros e vulnerabilidades potenciais em programas escritos nas linguagens C, C++, C# e Java. Funciona em sistemas de 64 bits no Windows, Linux e macOS, e pode analisar código destinado a plataformas ARM de 32 bits, 64 bits e embarcadas. Se você estiver tentando análise de código estática pela primeira vez em seus projetos, recomendamos ler sobre como visualizar rapidamente os avisos mais interessantes do PVS-Studio e avaliar as funcionalidades dessa ferramenta. artigo — um conjunto de serviços em nuvem que cobre todo o processo de desenvolvimento. Esta plataforma inclui ferramentas como Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos e Azure Test Plans, que permitem acelerar o processo de criação de software e melhorar sua qualidade.

Azure DevOps – um gerenciador de pacotes de código aberto para Windows. O objetivo do projeto é automatizar todo o ciclo de vida do software, desde a instalação até a atualização e remoção em sistemas operacionais Windows.

Chocolatey Sobre o uso do Chocolatey

Você pode ver como instalar o próprio gerenciador de pacotes neste

. A documentação completa sobre a instalação do analisador está disponível na seção "Instalação usando o gerenciador de pacotes Chocolatey". Resumindo, vou repetir alguns pontos de lá. linkComando para instalar a versão mais recente do analisador: link choco install pvs-studio

Comando para instalar uma versão específica do pacote PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

Команда установки конкретной версии пакета PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

Por padrão, apenas o núcleo do analisador é instalado — o componente Core. Todas as outras flags (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) podem ser passadas usando —package-parameters.

Exemplo de comando que instalará o analisador com o plugin para Visual Studio 2019:

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

Agora vamos olhar para um exemplo prático de uso do analisador no Azure DevOps.

Configuração

Lembro que sobre tópicos como registro de conta, criação de Build Pipeline e sincronização da conta com o projeto no repositório no GitHub, existe um separado artigo. Nossa configuração começará imediatamente com a escrita do arquivo de configuração.

Primeiro, configuraremos o trigger, especificando que iniciamos apenas para mudanças em master branch:

trigger:
- master

A seguir, precisamos escolher a máquina virtual. Neste momento, será um agente hospedado pela Microsoft com Windows Server 2019 e Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

Vamos para o corpo do arquivo de configuração (bloco steps). Apesar de que não é possível instalar software arbitrário na máquina virtual, não adicionei um container Docker. Podemos adicionar Chocolatey como uma extensão para Azure DevOps. Para isso, vamos em link. Clique em Get it free. Em seguida, se você já estiver autenticado, basta escolher sua conta; caso contrário, faça o mesmo após o login.

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

Aqui precisamos escolher onde vamos adicionar a extensão e clicar no botão Instalar.

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

Após a instalação bem-sucedida, clique em Proceed to organization:

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

Agora é possível ver o modelo para a tarefa Chocolatey na janela tasks ao editar o arquivo de configuração azure-pipelines.yml:

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

Clique em Chocolatey e veja a lista de campos:

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

Aqui precisamos escolher install no campo de comandos. Em Nuspec File Name especificaremos o nome do pacote desejado – pvs-studio. Se não for especificada a versão, será instalada a mais recente, o que nos atende completamente. Clique no botão add e veremos a tarefa gerada no arquivo de configuração.

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

Em seguida, vamos para a parte principal do nosso arquivo:

- task: CmdLine@2
  inputs:
    script: 

Agora precisamos criar um arquivo com a licença do analisador. Aqui PVSNAME e PVSKEY – são os nomes das variáveis, cujos valores indicaremos nas configurações. Eles armazenarão o login e a chave de licença do PVS-Studio. Para definir seus valores, abriremos o menu Variables->New variable. Vamos criar as variáveis PVSNAME para o login e PVSKEY para a chave do analisador. Não se esqueça de marcar a caixa Mantenha este valor em segredo para PVSKEY. Código do comando:

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

Vamos construir o projeto usando o arquivo bat que está no repositório:

chame build.bat

Vamos criar uma pasta onde estarão os arquivos com os resultados do trabalho do analisador:

chame mkdir PVSTestResults

Vamos iniciar a análise do projeto:

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

Convertemos nosso relatório para o formato html usando a ferramenta PlogConverter:

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

Agora precisamos criar uma tarefa para que possamos exportar o relatório.

- tarefa: PublishBuildArtifacts@1
  entradas:
    caminhoParaPublicar: PVSTestResults
    nomeDoArtefato: PVSTestResults
    condição: sempre()

O arquivo de configuração completo é assim:

trigger:
- master

pool:
  vmImage: 'windows-latest'

steps:
- tarefa: ChocolateyCommand@0
  entradas:
    comando: 'install'
    installPackageId: 'pvs-studio'

- tarefa: CmdLine@2
  entradas:
    script: |
      chame "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      credenciais –u $(PVSNAME) –n $(PVSKEY)
      chame build.bat
      chame mkdir PVSTestResults
      chame "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      –t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
      chame "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
      –t html –o .PVSTestResults .PVSTestResultsChoco.plog

- tarefa: PublishBuildArtifacts@1
  entradas:
    caminhoParaPublicar: PVSTestResults
    nomeDoArtefato: PVSTestResults
    condição: sempre()

Clique em Salvar->Salvar->Executar para iniciar a tarefa. Vamos exportar o relatório acessando a aba de tarefas.

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

O projeto Chocolatey contém apenas 37615 linhas de código C#. Vamos considerar alguns dos erros encontrados.

Resultados da verificação

Aviso N1

Advertência do analisador: V3005 A variável ‘Provider’ está atribuída a si mesma. CrytpoHashProviderSpecs.cs 38

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

O analisador detectou a atribuição de uma variável a si mesma, que não faz sentido. Provavelmente, uma das variáveis deveria ser outra. Ou é um erro de digitação e a atribuição excessiva pode ser simplesmente removida.

Aviso N2

Advertência do analisador: V3093 [CWE-480] O operador ‘&’ avalia ambos os operandos. Talvez um operador de curto-circuito ‘&&’ devesse ser usado em seu lugar. 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;
  }
}

A diferença entre o operador & e o operador && é que se a parte esquerda da expressão — falso, então ainda será calculada a parte direita, o que neste caso implica chamadas desnecessárias do método system.directory_exists.

No fragmento analisado, isso é uma pequena falha. Sim, essa condição pode ser otimizada, substituindo o operador & pelo operador &&, mas, do ponto de vista prático, isso não tem efeito. No entanto, em outros casos, a confusão entre & e && pode causar sérios problemas, quando a parte direita da expressão lida com valores inválidos/indesejados. Por exemplo, na nossa coleção de erros, detectados com o diagnóstico V3093, existe este caso:

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

Mesmo que o índice k seja inválido, ele será usado para acessar o elemento do array. Como resultado, uma exceção será gerada IndexOutOfRangeException.

Avisos N3, N4

Advertência do analisador: V3022 [CWE-571] A expressão ‘shortPrompt’ é sempre verdadeira. InteractivePrompt.cs 101
Advertência do analisador: V3022 [CWE-571] A expressão ‘shortPrompt’ é sempre verdadeira. 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
    ....
  }
  ....
}

Neste caso, há uma lógica estranha no funcionamento do operador ternário. Vamos analisar detalhadamente: se a condição marcada com o número 1 for satisfeita, então procederemos para a condição 2, que é sempre verdadeiro, portanto, a linha 3 será executada. Se a condição 1 for falsa, vamos para a linha marcada com o número 4, cuja condição também é sempre verdadeiro, portanto, a linha 5 será executada. Assim, as condições marcadas com o comentário 0 nunca serão executadas, o que pode não ser a lógica que o programador esperava.

V587

Advertência do analisador: V3123 [CWE-783] Talvez o operador ‘?:’ funcione de maneira diferente do esperado. Sua prioridade é menor que a prioridade de outros operadores na sua condição. 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);
  }
}

O diagnóstico acionou na linha:

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

Como a variável j Na linha acima, a variável é inicializada como zero; o operador ternário retornará um valor. falsoDevido a essa condição, o corpo do loop será executado apenas uma vez. Parece-me que esse trecho de código não funciona como o programador pretendia.

Aviso N6

Advertência do analisador: V3022 [CWE-571] A expressão ‘installedPackageVersions.Count != 1’ é sempre verdadeira. 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);
    }
    ....
  }
  ....
}

Aqui há uma condição aninhada estranha: installedPackageVersions.Count != 1, que sempre será verdadeiro. Frequentemente, esse aviso indica um erro lógico no código, e em outros casos, apenas uma verificação redundante.

Aviso N7

Advertência do analisador: V3001 Existem sub-expressões idênticas ‘commandArguments.contains("-apikey")’ à esquerda e à direita do operador ‘||’. 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");
}

O programador que escreveu essa parte do código copiou e colou as duas últimas linhas e esqueceu de editá-las. Por causa disso, os usuários do Chocolatey perderam a capacidade de aplicar o parâmetro apikey de outras maneiras. Semelhante aos parâmetros acima, eu posso sugerir as seguintes opções:

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

Erros de copy-paste têm uma alta probabilidade de aparecer em qualquer projeto com uma grande quantidade de código-fonte, e um dos melhores meios de combatê-los é a análise estática.

P.S. E como sempre, esse erro tende a aparecer no final de uma condição de múltiplas linhas :). Veja a publicação "Efeito da última linha".

Aviso N8

Advertência do analisador: V3095 [CWE-476] O objeto ‘installedPackage’ foi utilizado antes de ser verificado contra nulo. Verifique as linhas: 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)
  {
    ....
  }
  ....
}

Erro clássico: o objeto é utilizado antes de ser verificado installedPackage na null. Este diagnóstico indica um dos dois problemas no programa: ou installedPackage nunca é igual a null, o que é duvidoso, e então a verificação é redundante, ou podemos potencialmente ter um erro sério no código – uma tentativa de acesso a um ponteiro nulo.

Conclusão

Demos mais um pequeno passo – agora usar o PVS-Studio se tornou ainda mais fácil e conveniente. Também gostaria de dizer que o Chocolatey é um bom gerenciador de pacotes com poucos erros de código, que poderiam ter sido ainda menos se o PVS-Studio tivesse sido utilizado.

Convidamos baixar e experimentar o PVS-Studio. O uso regular do analisador estático aumentará a qualidade e a confiabilidade do código desenvolvendo por sua equipe e ajudará a prevenir muitas vulnerabilidades de zero-day.

P.S.

Antes da publicação, enviamos o artigo para os desenvolvedores do Chocolatey, e eles o receberam bem. Nada crítico foi encontrado, mas, por exemplo, eles gostaram do erro que encontramos relacionado à chave "api-key".

PVS-Studio agora está no Chocolatey: análise do Chocolatey via Azure DevOps

Se você deseja compartilhar este artigo com um público de língua inglesa, por favor, utilize o link para a tradução: Vladislav Stolyarov. PVS-Studio Agora no Chocolatey: Verificando Chocolatey sob o Azure DevOps.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster