Qual a utilidade da análise dinâmica quando você tem análise estática?

Para verificar a qualidade do software, você precisa usar muitas ferramentas diferentes, incluindo analisadores estáticos e dinâmicos. Neste artigo, tentaremos descobrir por que apenas um tipo de análise, estática ou dinâmica, pode não ser suficiente para uma análise abrangente do software e por que é preferível usar as duas.

Figura 1


Nossa equipe escreve muito sobre a utilidade da análise estática e os benefícios que ela traz para seus projetos. Gostamos de executar nossa ferramenta em vários projetos de código aberto para encontrar possíveis erros, que é a nossa maneira de popularizar o método de análise de código estático. Por sua vez, a análise estática ajuda a tornar os programas mais de alta qualidade e confiáveis, além de reduzir o número de possíveis vulnerabilidades. Talvez todo mundo que esteja diretamente envolvido no trabalho com o código-fonte tenha a sensação de satisfação por corrigir os erros. Mas mesmo que o processo de detectar (e corrigir) erros com êxito não ative suas endorfinas, você certamente desfruta da ideia de reduzir as despesas de desenvolvimento graças ao analisador estático, que ajudou seus programadores a usar seu tempo com mais eficácia e eficiência. Para descobrir mais sobre como você pode se beneficiar do uso da análise estática em termos de dinheiro, consulte este artigo . Ele fornece uma estimativa aproximada para o PVS-Studio, mas esses resultados podem ser extrapolados para outras ferramentas de análise estática disponíveis no mercado.

Tudo dito acima parece sugerir que o objetivo da análise estática é encontrar erros no código fonte o mais cedo possível, reduzindo assim as despesas com a correção de erros. Mas por que precisamos de análise dinâmica e por que aderir apenas a uma das duas técnicas pode ser insuficiente? Vamos dar definições mais formais e claras de análises estáticas e dinâmicas e tentar responder a essas perguntas.

A análise de código estático é o processo de detecção de erros e odores de código no código-fonte do software. Para analisar um programa, você não precisa executá-lo; a análise será realizada na base de código disponível. A analogia mais próxima da análise estática é a chamada revisão de código, exceto que a análise estática é uma versão automatizada da revisão de código (isto é, realizada por um programa bot).

Os principais profissionais da análise estática:

  1. Detecção de erros nos estágios iniciais de desenvolvimento. Isso ajuda a tornar a correção de bugs muito mais barata, porque quanto mais cedo um defeito for detectado, mais fácil - e, portanto, mais barato - será corrigido.
  2. Ele permite que você localize com precisão o bug em potencial no código fonte.
  3. Cobertura de código completo. Não importa quantas vezes um bloco de código ou outro obtenha controle durante a execução, a análise estática verifica toda a base de código.
  4. Fácil de usar. Você não precisa preparar nenhum conjunto de dados de entrada para fazer uma verificação.
  5. Os analisadores estáticos detectam erros de digitação e copiam e colam erros relacionados com rapidez e facilidade.

Os contras objetivos da análise estática:

  1. Inevitáveis ​​falsos positivos. Um analisador estático pode ficar com raiva de fragmentos de código que, na verdade, não contêm bugs. Somente o programador pode resolver esse problema e marcar um aviso como falso positivo, o que significa que levará algum tempo de trabalho.
  2. A análise estática geralmente é ruim na detecção de vazamentos de memória e erros relacionados à concorrência. Para detectar esses erros, você precisaria executar alguma parte do programa no modo virtual, o que é uma tarefa extremamente difícil. Além disso, esses algoritmos exigiriam muita memória e tempo de CPU. Analisadores estáticos normalmente não vão além de analisar alguns casos simples. Os analisadores dinâmicos são mais adequados para diagnosticar vazamentos de memória e erros relacionados à concorrência.

Note-se que os analisadores estáticos não se concentram exclusivamente na captura de bugs. Por exemplo, eles podem fornecer recomendações sobre formatação de código. Algumas ferramentas permitem que você verifique seu código quanto à conformidade com o padrão de codificação que sua empresa segue. Isso inclui a indentação de várias construções, o uso de caracteres de espaço / tabulação e assim por diante. Além disso, a análise estática pode ser útil para medir métricas. Uma métrica de software é uma medida quantitativa do grau em que um programa ou suas especificações possuem alguma propriedade. Consulte este artigo para aprender sobre outros usos da análise estática.

Análise dinâmica de código é a análise realizada em um programa no tempo de execução. Isso significa que você deve ter seu código-fonte convertido em um arquivo executável primeiro. Em outras palavras, o código que contém erros de compilação ou compilação não pode ser verificado por esse tipo de análise. A verificação é feita com um conjunto de dados de entrada alimentados ao programa em análise. É por isso que a eficácia da análise dinâmica depende diretamente da qualidade e quantidade dos dados de entrada do teste. São esses dados que determinam a extensão da cobertura do código no final do teste.

Com o teste dinâmico, você pode obter as seguintes métricas e avisos:

  1. Recursos utilizados: tempo de execução de todo o programa ou de suas partes individuais, número de consultas externas (por exemplo, a um banco de dados), quantidade de RAM e outros recursos utilizados pelo programa.
  2. A extensão da cobertura do código por testes e outras métricas.
  3. Bugs de software: divisão por zero, desreferência nula, vazamentos de memória, condições de corrida.
  4. Algumas vulnerabilidades de segurança.

Os principais profissionais da análise dinâmica:

  1. Você não precisa ter acesso ao código fonte do programa para analisá-lo. Deve-se notar, no entanto, que as ferramentas de análise dinâmica são diferenciadas pela maneira como interagem com o programa em análise (isso é discutido em mais detalhes aqui ). Por exemplo, uma técnica de análise dinâmica bastante comum envolve a instrumentação de código antes da verificação, ou seja, a adição de fragmentos de código especiais ao código-fonte do aplicativo para que o analisador possa diagnosticar erros. Nesse caso, você precisa ter o código fonte do programa em mãos.
  2. Ele pode detectar erros complexos de manipulação de memória, como indexação além dos limites da matriz e vazamentos de memória.
  3. Ele pode analisar o código multithread no tempo de execução, detectando possíveis problemas relacionados ao acesso a recursos compartilhados ou possíveis conflitos.
  4. A maioria das implementações de analisadores dinâmicos não gera falsos positivos, pois os erros são detectados à medida que ocorrem. Portanto, um aviso emitido por um analisador dinâmico não é uma previsão feita pela ferramenta com base na análise do modelo do programa, mas uma mera declaração do fato de que ocorreu um erro.

Os contras da análise dinâmica:

  1. A cobertura completa do código não é garantida. Ou seja, é improvável que você obtenha 100% de cobertura por testes dinâmicos.
  2. Os analisadores dinâmicos são ruins na detecção de erros lógicos. Por exemplo, uma condição sempre verdadeira não é um bug da perspectiva de um analisador dinâmico, pois uma verificação incorreta simplesmente desaparece mais cedo na etapa de compilação.
  3. É mais difícil localizar com precisão o erro no código.
  4. A análise dinâmica é mais difícil de usar em comparação com a análise estática, pois você precisa alimentar dados suficientes para o programa para obter melhores resultados e obter a cobertura máxima de código possível.

A análise dinâmica é particularmente útil nas áreas em que a confiabilidade do programa, o tempo de resposta ou os recursos consumidos são a principal preocupação. Um sistema em tempo real que gerencia um setor de produção crítico ou um servidor de banco de dados são alguns exemplos desses sistemas. Qualquer erro nessas áreas pode ser crítico.

Voltando à pergunta por que a aderência apenas a um dos dois tipos de análise pode não ser suficiente, vamos dar uma olhada em alguns exemplos bastante triviais de bugs que um método de análise não tem problemas em diagnosticar enquanto o outro não está apto a detectar e vice-versa.

O exemplo a seguir é retirado do projeto Clang:

MapTy PerPtrTopDown; MapTy PerPtrBottomUp; void clearBottomUpPointers() { PerPtrTopDown.clear(); } void clearTopDownPointers() { PerPtrTopDown.clear(); } 

Um analisador estático indicaria que os corpos das duas funções são idênticos. Obviamente, duas funções com corpos idênticos não são necessariamente um sinal definitivo de um bug, mas é muito provável que tenham resultado do uso da técnica de copiar e colar combinada com descuido do lado do programador - e isso leva a um comportamento inesperado. Nesse caso, o método clearBottomUpPointers deve chamar o método PerPtrBottomUp.clear . A análise dinâmica não notaria nada de errado neste exemplo, porque é um trecho de código absolutamente legítimo do ponto de vista dele.

Outro exemplo Suponha que tenhamos a seguinte função:

 void OutstandingIssue(const char *strCount) { unsigned nCount; sscanf_s(strCount, "%u", &nCount); int array[10]; memset(array, 0, nCount * sizeof(int)); } 

Em teoria, um analisador estático pode suspeitar que haja algo errado com esse código, mas implementar esse diagnóstico é uma tarefa muito difícil e sem sentido. O exemplo é retirado deste artigo , que também explica por que é uma má idéia ensinar aos analisadores estáticos como diagnosticar erros como esse. Em resumo, os analisadores estáticos são muito ruins para descobrir que uma chamada da função memset pode resultar na indexação além dos limites da matriz, pois eles não podem prever qual número será lido na string strCount ; e se o valor de strCount for lido de um arquivo, ele se tornará uma tarefa impossível para a análise estática. Por outro lado, um analisador dinâmico não teria problemas em perceber e apontar o erro de manipulação de memória nesse código (dado que o programa recebe os dados corretos).

Este artigo não tem como objetivo comparar análises estáticas e dinâmicas. Não existe uma técnica única que possa diagnosticar toda a variedade de defeitos de software. Nenhum tipo de análise pode substituir completamente o outro. Para melhorar a qualidade dos seus programas, você precisará usar diferentes tipos de ferramentas para que elas se complementem. Espero que os exemplos mostrados acima sejam suficientemente convincentes.

Não desejo parecer muito tendencioso em relação à análise estática, mas é essa técnica que está sendo mais comentada e, mais importante, incluída pelas empresas em seus processos de IC ultimamente. A análise estática atua como uma das etapas dos chamados portões de qualidade para a construção de um produto de software confiável e de alta qualidade. Acreditamos que a análise estática se tornará uma prática padrão de desenvolvimento de software em alguns anos, assim como o teste de unidade.

Para finalizar, gostaria de salientar mais uma vez que a análise dinâmica e a análise estática são apenas dois métodos diferentes, que se complementam. No final, todas essas técnicas servem ao único objetivo de aumentar a qualidade do software e reduzir as despesas de desenvolvimento.

Referências:

  1. Terminologia. Análise de código estático .
  2. Terminologia. Análise dinâmica de código .
  3. Andrey Karpov. Análise de código estático e dinâmico .
  4. Andrey Karpov. Mitos sobre análise estática. O terceiro mito - a análise dinâmica é melhor que a análise estática .
  5. Andrey Karpov. ROI do PVS-Studio .

Source: https://habr.com/ru/post/pt461173/


All Articles