Revisão independente do PVS-Studio (Linux, C++)

Vi uma publicação que o PVS aprendeu a analisar no Linux e decidi experimentá-la em meus próprios projetos. E foi isso que resultou disso.


Conteúdo

  1. Prós
  2. Contras
  3. Resultados de
  4. Posfácio

Prós

Suporte responsivo

Solicitei uma chave de teste e eles me enviaram no mesmo dia.

Documentação bastante clara

Conseguimos lançar o analisador sem problemas. A ajuda para comandos do console também está disponível (embora haja algumas reclamações aqui, consulte a seção Contras).

Possibilidade de análise multithread

O analisador possui uma opção "padrão" -j, permitindo que análises sejam realizadas paralelamente em diversas tarefas. Isso economiza muito tempo.

Boa visualização

Muitos formatos de saída diferentes, desde texto até um pequeno focinho de teia. A interface da web é conveniente, concisa, com dicas próximas às linhas do código e links para descrições de diagnóstico.

Fácil integração na montagem

Toda a documentação está no site deles, só posso dizer que se o seu projeto for construído no CMake então tudo é muito simples.

Boas descrições de diagnóstico

Se você gerar saída no modo fullhtml, cada mensagem terá um link para uma descrição de diagnóstico, com explicações, exemplos de código e links adicionais.

Contras

Ignorância da linguagem C++ pelo analisador

Infelizmente, o PVS às vezes comete erros de sintaxe e gera mensagens falso-positivas quando o código está completamente correto.

Por exemplo, existe uma função que retorna void:

template <typename T>
auto copy (const void * source, void * destination)
    ->
        std::enable_if_t
        <
            std::is_copy_constructible<T>::value
        >
{
    new (destination) T(*static_cast<const T *>(source));
}

Sim, palavra-chave auto Pode significar void, é para isso que serve auto. Mas o PVS produziu as seguintes mensagens:

dynamic_tuple_management.hpp:29:1: error: V591 Non-void function should return a value.
dynamic_tuple_management.hpp:29:1: error: V2542 Function with a non-void return type should return a value from all exit paths.

Site muito lento

Sim, na interface web ao lado de cada mensagem existe um link para a descrição do diagnóstico correspondente com exemplos. Mas quando você clica em um link, você tem que esperar muito tempo, e às vezes isso acontece Tempo Limite do Gateway 504.

Linguagem

Todas as descrições estão em russo, o que é ótimo. Mas os links do relatório sempre levam à versão em inglês. Seria bom poder mudar o idioma para que você pudesse visualizar o diagnóstico imediatamente em russo. Não encontrei essa opção na interface.

É inconveniente trabalhar com níveis de diagnóstico através do console

Vamos começar com o fato de que os dois comandos utilizados (este pvs-studio-analyzer и plog-converter) formatos diferentes para especificar diagnósticos.

Ajuda para pvs-studio-analyzer lê:

-a [MODE], --analysis-mode [MODE]
    MODE defines the type of warnings:
    1 - 64-bit errors;
    2 - reserved;
    4 - General Analysis;
    8 - Micro-optimizations;
    16 - Customers Specific Requests;
    32 - MISRA.
    Modes can be combined by adding the values
    Default: 4

Passei muito tempo tentando descobrir para onde ir adicionar (“adicionando os valores”) chaves. Tentei listá-los separados por vírgulas:

pvs-studio-analyzer analyze ... -a 1,4,16

Tentei cadastrar a chave diversas vezes:

pvs-studio-analyzer analyze ... -a 1 -a 4 -a 16

E só então percebi que eram máscaras de bits! E você precisa resumirE não adicionar significados. Por exemplo, para obter diagnósticos gerais, diagnósticos de microotimizações e MISRA, você precisa resumi-los (4 + 8 + 32 = 44):

pvs-studio-analyzer analyze ... -a 44

Usar máscaras de bits em interfaces de usuário geralmente é uma má forma. Tudo isso poderia ser resumido internamente e um conjunto de sinalizadores poderia ser definido para o usuário.

Além disso, há também um utilitário plog-converter, que gera informações de análise estática legíveis por humanos. Ela tem outros problemas.

Ajuda para o programa plog-converter relatórios:

-a, --analyzer            Specifies analyzer(s) and level(s) to be
                          used for filtering, i.e.
                          'GA:1,2;64:1;OP:1,2,3;CS:1;MISRA:1,2'
                          Default: GA:1,2

Apareceram aqui alguns “níveis” que não existiam antes, e também não encontrei nada sobre eles na documentação.

Em geral, não está claro. É por isso que coloquei tudo no máximo.

Um monte de palavrões estúpidos sobre Catch

Dois dos três projetos que analisei usam uma biblioteca de testes unitários Catch2. E a maior parte das mensagens (!!! 90 de 138 em uma e 297 de 344 na outra!!!) tem o seguinte formato:

Revisão independente do PVS-Studio (Linux, C++)

Não leva em conta multithreading

Existem muitos falsos positivos sobre variáveis ​​​​supostamente imutáveis ​​​​ou loops infinitos, enquanto o trabalho com essas variáveis ​​ocorre a partir de threads diferentes e, se não fosse assim, os testes unitários não funcionariam.

Revisão independente do PVS-Studio (Linux, C++)

No entanto, um analisador estático pode levar isso em consideração? Não sei.

Resultados de

PVS não encontrou nenhum bug real em meus projetos de código aberto Explosão и Proxima, bem como num projecto de trabalho que, por razões óbvias, não posso apresentar. É verdade que vale a pena ter em mente que algumas deficiências já foram detectadas e corrigidas anteriormente usando Cppverificar и scan-build.

Em geral, a impressão de todos esses analisadores é aproximadamente a mesma: sim, eles capturam algo, às vezes até algo importante, mas no geral o compilador é suficiente.

É possível (e eu pessoalmente gosto de pensar assim) que nossa equipe utilize práticas de desenvolvimento de software que nos permitam gerar uma quantidade mínima de código de merda. É melhor não criar problemas do que superá-los heroicamente.

Portanto, tomo a liberdade de dar alguns conselhos sobre como escrever em C++ de forma a não atirar nas pernas de ninguém ou bater na testa de alguém com um ancinho.

Aproveite ao máximo o diagnóstico do compilador

Nossa equipe usa (e aconselha) as seguintes opções de compilação:

-Werror

-Wall
-Wextra
-Wpedantic

-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wenum-compare
-Wfloat-equal
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo

Habilite-os em seu projeto e aprenda muito sobre seu código.

Atenha-se ao padrão

Tente não usar itens dependentes de plataforma se houver análogos padrão e, se você não puder viver sem eles, envolva-os em blocos especiais para macros (ou qualquer outra coisa) e simplesmente não permita que seu código seja compilado em condições não suportadas.

Atenha-se à semântica de operação padrão

Adição deve ser adição, multiplicação deve ser multiplicação, chamada de função deve ser chamada de função, cópia deve ser cópia, transporte deve ser transporte, contêiner deve ser iterável, iterador deve ter promoção ++ e desreferenciação *. E assim por diante.

Acho que a ideia é clara. Existem convenções estabelecidas que não são vinculativas, mas que todos os usuários e leitores do seu código esperam ver. Não tente enganar os outros, caso contrário você será mais esperto que você mesmo.

Escreva código compatível

Em primeiro lugar, quero dizer a biblioteca padrão. É altamente desejável que as interfaces de suas classes e funções possam ser usadas com bibliotecas padrão e outras (por exemplo, Boost).

Sinta-se à vontade para dar uma olhada nas interfaces STL e Boost. Com raras exceções, você verá ali um modelo digno.

Aproveite ao máximo as ferramentas de código aberto

Para a mesma análise estática, existem pelo menos duas ferramentas abertas e gratuitas que podem ser conectadas apenas uma vez a qualquer projeto com o sistema de construção CMake.

Você pode ler mais sobre isso em minha publicação recente.

Posfácio

Por fim, gostaria de enfatizar que não estou defendendo o não uso do PVS ou de quaisquer outros analisadores estáticos. Mas eu encorajo você a pensar em como o analisador estático encontra constantemente erros significativos em seu código.

Isto é apenas uma consequência. Precisamos procurar e eliminar a causa.

Fonte: habr.com

Adicionar um comentário