Vi uma publicação sobre como o PVS finalmente aprendeu a analisar no Linux e decidi experimentar em meus projetos. E aqui está o que eu obtive.
Conteúdo
Suporte responsivo
Eu solicitei uma chave de teste e, no mesmo dia, recebi-a.
Documentação bastante clara
Consegui iniciar o analisador sem muitos problemas. Também há ajuda para os comandos do console (embora haja críticas, consulte a seção ).
Possibilidade de análise em múltiplas threads
O analisador tem uma opção "padrão" -j, que permite realizar análises simultaneamente em várias tarefas. Isso economiza muito tempo.
Boa visualização
Muitos formatos de saída diferentes, desde texto até uma interface web simples. .
Integração simples na compilação
Toda a documentação está disponível no site deles, vou dizer apenas que se seu projeto é compilado com CMake, é tudo muito simples.
Boas descrições de diagnósticos
Se você gerar a saída no modo fullhtml, cada mensagem terá um link para a descrição do diagnóstico, com explicações, exemplos de código e links adicionais.
Desconhecimento do analisador sobre a linguagem C++
Infelizmente, o PVS às vezes erra na sintaxe e gera mensagens de falso positivo com código 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, a palavra-chave auto pode significar void, para isso existe auto. Mas o PVS emitiu as seguintes mensagens:
dynamic_tuple_management.hpp:29:1: error: V591 Função não-void deve retornar um valor.
dynamic_tuple_management.hpp:29:1: error: V2542 Função com um tipo de retorno não-void deve retornar um valor de todos os caminhos de saída.Site muito lento
Sim, na interface web, ao lado de cada mensagem há um link para a descrição correspondente do diagnóstico com exemplos. Mas ao clicar no link, a espera é considerável, e às vezes aparece também um .
Linguagem
Todas as descrições estão em russo, o que é ótimo. Mas os links dos relatórios sempre levam à versão em inglês. Seria bom ter a possibilidade de alternar o idioma para que as diagnósticas pudessem ser visualizadas imediatamente em russo. Não encontrei essa opção na interface.
É inconveniente trabalhar com os níveis de diagnósticos através do console.
Começaremos pelo fato de que as duas equipes utilizadas têm pvs-studio-analyzer e plog-converter) diferentes formatos de atribuição de diagnósticos.
A documentação para pvs-studio-analyzer diz:
-a [MODE], --analysis-mode [MODE]
MODE define o tipo de avisos:
1 - erros de 64 bits;
2 - reservado;
4 - Análise Geral;
8 - Micro-otimizações;
16 - Solicitações Específicas de Clientes;
32 - MISRA.
Os modos podem ser combinados somando os valores
Padrão: 4Demorei a entender onde precisava adicionar as chaves. Tentei listá-las com vírgula:
pvs-studio-analyzer analyze ... -a 1,4,16Tentei escrever a chave várias vezes:
pvs-studio-analyzer analyze ... -a 1 -a 4 -a 16E só então percebi que eram máscaras bit a bit! E era necessário somar, e não adicionar os valores. Por exemplo, para obter diagnósticos gerais, diagnósticos de micro-otimizações e MISRA, é preciso somá-los (4 + 8 + 32 = 44):
pvs-studio-analyzer analyze ... -a 44O uso de máscaras bit a bit em interfaces de usuário costuma ser, por regra, mal visto. Todo esse procedimento poderia ser feito internamente, e o usuário apenas definir um conjunto de flags.
Além disso, existe uma ferramenta plog-converter, que gera informações mais legíveis sobre a análise estática. Ela possui outras peculiaridades.
A documentação do programa plog-converter informa:
-a, --analyzer Especifica o(s) analisador(es) e nível(is) a serem
utilizados para filtragem, ou seja,
'GA:1,2;64:1;OP:1,2,3;CS:1;MISRA:1,2'
Padrão: GA:1,2Aqui surgiram alguns "níveis", que não existiam antes, e eu também não encontrei informações sobre eles na documentação.
Em resumo, não estava claro. Portanto, configurei tudo no máximo.
Muita reclamação sem sentido no Catch
Em dois dos três projetos que analisei, foi utilizada a biblioteca de teste modular . E a maioria das mensagens (!!! 90 de 138 em um e 297 de 344 no outro !!!) tem o seguinte formato:

Não considera a multithreading
Muitos alarmes falsos sobre supostas variáveis imutáveis ou laços infinitos, ao mesmo tempo em que a manipulação dessas variáveis ocorre em diferentes threads, e se isso não fosse o caso, os testes modulares não teriam sido acionados.

No entanto, será que um analisador estático pode considerar isso? Não sei.
O PVS não encontrou nenhum erro real em meus projetos abertos e , bem como em um projeto de trabalho que, por razões óbvias, não posso apresentar. No entanto, vale ressaltar que algumas falhas já foram identificadas e corrigidas anteriormente com a ajuda de e .
A impressão geral sobre todos esses analisadores é mais ou menos a mesma: sim, eles capturam algo, às vezes até algo importante, mas, no geral, um compilador é suficiente.
Talvez (e pessoalmente gosto de pensar assim) nossa equipe utilize práticas de desenvolvimento de software que geram a quantidade mínima de código problemático. É melhor não criar problemas do que superá-los de forma heroica.
Portanto, ouso dar algumas dicas sobre como programar em C++ de maneira a não atirar no próprio pé e evitar os golpes de raquetas na testa.
Use ao máximo os diagnósticos do compilador.
Nossa equipe utiliza (e recomenda a você) 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-promoInclua-as em seu projeto, e você aprenderá muito sobre seu código.
Adira ao padrão.
Evite utilizar elementos dependentes de plataforma, se houver análogos padrões, e se, por alguma razão, não for possível prescindir deles, encapsule-os em blocos especiais sob macros (ou de outra forma) e simplesmente impeça a compilação do seu código em condições não suportadas.
Mantenha a semântica padrão das operações.
A adição deve ser adição, a multiplicação — multiplicação, a chamada de função — chamada de função, a cópia deve copiar, a transferência — transferir, um contêiner deve ser iterável, e o iterador deve ter progresso ++ e desreferenciamento. *. E assim por diante.
Acredito que a ideia esteja clara. Existem convenções estabelecidas que não são obrigatórias, mas que todos os usuários e leitores do seu código esperam ver. Não tente superar os outros, ou você acabará se superando.
Escreva código compatível.
Em primeiro lugar, refiro-me à biblioteca padrão. É muito desejável que as interfaces de suas classes e funções possam ser utilizadas com bibliotecas padrão e outras bibliotecas (como a Boost).
Não hesite em observar as interfaces STL e Boost. Com raras exceções, ali você encontrará exemplos dignos de imitação.
Utilize ao máximo ferramentas abertas.
Para essa mesma análise estática, existem pelo menos duas ferramentas abertas e gratuitas que se conectam a qualquer projeto com o sistema de construção CMake.
.
Por último, gostaria de ressaltar que não estou sugerindo que você não use o PVS ou qualquer outro analisador estático. Mas eu encorajo a refletir sobre como é possível que o analisador estático encontre continuamente erros significativos em seu código.
Isso é apenas uma consequência. É preciso procurar e eliminar a causa.
Fonte: habr.com
