Em outro artigo, expliquei como fazer revisões de código corretamente. Recomendei o aproveitamento de ferramentas de análise estática como Findbugs, PMD, Klocwork ou Fortify para verificar se há erros comuns no código antes de enviá-lo para um revisor, tornando o trabalho do revisor mais fácil e as revisões mais eficazes.
Alguns leitores perguntaram se ferramentas de análise estática podem ser usadas em vez de revisões manuais de código. Revisões manuais de código adicionam atrasos e custos de desenvolvimento, enquanto as ferramentas de análise estática estão ficando cada vez melhores, mais rápidas e mais precisas. Assim, você pode automatizar as revisões de código, da mesma forma que muitas equipes automatizam testes funcionais? É necessário fazer revisões manuais também, ou é possível contar com a tecnologia para fazer o trabalho para você?
Vamos começar por compreender onde as ferramentas de verificação de erros de análise estática são boas, e onde não são.
O que as ferramentas de análise estática podem fazer – e o que não podem
Neste artigo, Paul Anderson na GrammaTech faz um bom trabalho em explicar como a análise estática pode encontrar bugs em códigos, problemas simples de sintaxe (encontrando todos os problemas reais), tem maior precisão (minimizando falsos positivos), velocidade e as limitações práticas de usar ferramentas de análise estática para encontrar bugs.
Ferramentas de análise estática são muito boas para encontrar alguns tipos de erros, incluindo a corrupção de memória e estouros de buffer (para C/C++), vazamentos de memória, operações ilegais e inseguras, ponteiros nulos, loops infinitos, código incompleto, código redundante e código morto (absolutamente sem uso) e sabe se está sendo chamada uma biblioteca incorretamente (contanto que reconheça a função), se você está usando a linguagem de forma incorreta (problemas que um compilador poderia encontrar, mas não consegue) ou de forma inconsistente (indicando que o programador pode ter feito algo errado).
Também podem identificar problemas de manutenção, código que não respeita as boas práticas ou padrões, é complexo demais ou mal estruturado e um bom candidato para refatoração.
Mas essas ferramentas não podem dizer quando os requisitos estão errados ou quando o desenvolvedor tiver esquecido alguma coisa ou se perdeu algo importante – porque elas não sabem o que o código supostamente deve fazer. Uma ferramenta pode encontrar erros comuns off-by-one e alguns loops infinitos, mas não vai pegar erros de lógica do aplicativo, como a classificação em ordem decrescente em vez de ordem crescente, ou divisões quando você quis dizer multiplicações, referindo-se ao comprador, quando deveria ter se referido ao vendedor, ou então ao locatário em vez do locador. Esses são erros que não podem ser encontrados em testes unitários, dado que a mesma pessoa que escreveu o código escreveu os testes e irá cometer os mesmos erros.
Ferramentas de análise estática não conseguem encontrar funções faltando ou recursos não implementados, além de checagens que deveriam ter sido feitas, mas não foram. Também não podem encontrar erros ou buracos em fluxos de trabalho. Ou descuidos em auditoria ou de registro, nem realizar a depuração de código deixado por acidente.
Essas ferramentas são capazes de encontrar alguns backdoors ou armadilhas de segurança – as mais simples, pelo menos, e podem encontrar alguns problemas de concorrência – impasses, problemas e erros ou inconsistências no bloqueio. Mas as ferramentas vão deixar passar muitos desses erros também.
Ferramentas de análise estática como o Findbugs podem fazer verificações de segurança para você: as chamadas e operações inseguras, o uso de algoritmos de criptografia fracos, números aleatórios fracos, uso de senhas codificadas e pelo menos alguns casos de XSS, CSRF e injeção SQL simples. Ferramentas comerciais mais avançadas que fazem a análise inter-processual do fluxo de dados (olhando para as fontes, pontos de escoamento de dados e caminhos) podem encontrar outros bugs, incluindo problemas de injeção de dados que são difíceis e demorados de serem localizados à mão.
Mas a ferramenta não pode lhe dizer que você esqueceu de criptografar um dado importante, ou que você não deve armazenar determinados tipos de dados. Não pode encontrar erros de lógica em recursos de segurança críticos, se informações sensíveis podem vazar, quando você tem uma verificação de controle de acesso errado, ou se o código poderia deixar alguma opção aberta em vez de fechada.
Utilizar uma ferramenta de análise estática por conta própria para verificar o código pode não ser suficiente. As avaliações de ferramentas de análise estática, como a do projeto SAMATE do NIST (uma série de estudos comparativos, nos quais muitas ferramentas são executadas contra o mesmo código para verificar as diferenças de resultados obtidos), mostram quase nenhuma sobreposição entre os problemas encontrados por diferentes ferramentas (fora de algumas áreas comuns, como erros de buffer), mesmo quando as ferramentas supostamente farão os mesmos tipos de checagens. O que significa que, para obter o máximo de análise estática, você precisará executar duas ou mais ferramentas contra o mesmo código (que é o que o SonarQube, por exemplo, que integra seus próprios resultados de análise estática com outras ferramentas, incluindo ferramentas gratuitas populares, faz para você). Se você está pagando por ferramentas comerciais, isso pode ficar muito caro rapidamente.
Avaliação manual vs. ferramentas de análise
Ferramentas podem encontrar casos de má codificação ou má digitação, mas estes são problemas que você obrigatoriamente teria de encontrar por meio de revisões manuais.
Um estudo de 2005 comparando ferramentas que encontram bugs com críticas e testes manuais utilizou software open source voltado especificamente para encontrar bugs (incluindo Findbugs e PMD) em 5 bases de código diferentes, comparando o que as ferramentas encontraram com o que foi encontrado através de revisões de código e testes funcionais feitos manualmente. Ferramentas de análise estática encontram apenas um pequeno subconjunto dos bugs achados em revisões manuais, embora as ferramentas fossem mais consistentes – a análise manual deixou passar alguns casos que as ferramentas pegaram.
Assim como revisões manuais, as ferramentas encontram mais problemas com a manutenção do que defeitos reais (isso acontece em parte porque uma das ferramentas avaliadas – PMD – concentra-se na estrutura do código e nas melhores práticas). Testes encontraram menos bugs do que análise manual, mas encontraram também diferentes tipos de bugs. Não houve sobreposição dos bugs encontrados em testes manuais e os bugs encontrados pelas ferramentas de análise estática.
Encontrando problemas que poderiam acontecer – ou não
Ferramentas de análise estática são boas para encontrar problemas que “podem acontecer”, mas não necessariamente problemas que “acontecem”.
Pesquisadores da Universidade Estadual do Colorado utilizaram ferramentas de análise estática contra vários tipos diferentes de projetos open source e compararam os resultados obtidos com os das análises e correções que os desenvolvedores fizeram ao longo de um período de alguns anos – para ver se as ferramentas de análise poderiam prever corretamente as correções que precisam ser feitas e qual código precisa ser reformulado.
As ferramentas relataram centenas de problemas no código, mas encontraram poucos dos graves problemas que os desenvolvedores acabaram corrigindo manualmente. Uma ferramenta simples (Jlint) não encontrou qualquer coisa que realmente foi corrigida ou limpa por desenvolvedores manualmente. De 112 bugs sérios que foram corrigidos em um projeto, apenas 3 foram também encontrados por ferramentas de análise estática. Em outro projeto, apenas 4 dos 136 erros que foram efetivamente informados e corrigidos foram encontrados pelas ferramentas automáticas. Muitos dos erros que os desenvolvedores corrigiram foram problemas como ponteiros nulos e operações em cadeia incorretas – problemas que ferramentas de análise estática deveriam ser boas em pegar, mas não o fizeram.
As ferramentas fizeram um trabalho muito melhor prevendo o código que deveria ser reformulado: os desenvolvedores acabaram refatorando e limpando mais de 70% da estrutura do código e melhorando sua clareza, questões que as ferramentas relatadas (como o PMD, uma ferramenta de verificação de código livre, que foi especialmente útil para isso).
A Ericsson avaliou diferentes ferramentas de análise estática comercial contra códigos bem testados, aplicativos grandes e maduros. Em um aplicativo C, uma ferramenta comercial encontrou 40 problemas – nada que pudesse causar um acidente, mas, ainda assim, eram problemas que precisavam ser corrigidos. Em outra grande base de código C, 1% dos resultados da ferramenta acabaram por ser bugs sérios o suficiente para serem corrigidos. No terceiro projeto, foram testadas duas ferramentas comerciais contra uma versão antiga de um sistema em C com vazamentos de memória conhecidos. Uma ferramenta encontrou 32 bugs nesse código, outra encontrou 16 bugs, mas apenas 3 dos bugs foram encontrados por ambas as ferramentas. Surpreendentemente, nenhuma ferramenta encontrou os vazamentos de memória já conhecidos – todos os bugs encontrados eram novos.
Em um sistema Java com bugs conhecidos, foram utilizadas três ferramentas diferentes. Nenhuma delas encontrou qualquer um dos bugs conhecidos, mas uma das ferramentas encontrou 19 novos bugs que a equipe efetuou a correção.
A experiência da Ericsson é que ferramentas de análise estática encontram bugs que são extremamente difíceis de achar de outra forma. Mas é muito raro encontrar erros que comprometam o código – especialmente em código de produção – por meio de análise estática.
Esse método é apoiado por outro estudo sobre o uso de análise estática (com Findbugs) no Google e no Sun JDK 1.6.0. Com a ferramenta, os engenheiros encontraram uma grande quantidade de erros que eram reais, mas não valeram o custo da correção: erros deliberados, erros mascarados, situações inviáveis, código que já havia sido condenado, erros no código de teste ou código de registro, erros no código antigo que “ia ser modificado logo” ou outros casos relativamente pouco importantes. Apenas cerca de 10% dos erros que precisavam de correção tinham prioridade média ou alta e foram encontrados pela ferramenta eram erros reais que tinha absoluta necessidade de correção.
O processo de segurança
Até agora, a maioria dos analistas olhou para a análise estática em busca da verificação de correção em tempo de execução e na qualidade do código geral, não para a segurança.
Embora a segurança se baseie na qualidade do código – vulnerabilidades são apenas bugs que hackers procuram e exploram -, a verificação de código para correção e clareza não é o suficiente para um aplicativo seguro. Muitos investimentos em tecnologia de análise estática ao longo dos últimos 5/10 anos têm sido feitos para encontrar problemas de segurança em códigos, como problemas comuns enumerados no Top 10 do OWASP ou no Top 25 erros de software mais perigosos do SANS/CWE.
Alguns estudos analisaram a eficácia das ferramentas de análise estática em comparação com revisões manuais em encontrar vulnerabilidades de segurança. O primeiro estudo focava em um grande aplicativo que tinha 15 vulnerabilidades de segurança conhecidas, encontradas através de uma avaliação manual de sua estrutura, realizada por especialistas em segurança. Duas ferramentas de análise estática comerciais diferentes foram executadas pelo código. As ferramentas em conjunto encontraram menos de metade das falhas conhecidas de segurança – apenas as mais simples, os erros que não exigem uma profunda compreensão do código ou o design.
E, claro, as ferramentas relataram milhares de outras questões que precisavam ser revistas e qualificadas ou descartadas como falsos positivos. Entre essas questões estão incluídos alguns problemas de tempo de execução, ponteiros nulos e vazamentos de recursos e resultados de qualidade de código (código morto, variáveis não utilizadas), mas não outras vulnerabilidades de segurança real, além das já encontradas pela revisão de segurança manual.
Mas isso pressupõe que você tenha um especialista em segurança por perto para revisar o código. Para encontrar vulnerabilidades de segurança, um revisor precisa entender o código (a linguagem e o que o código faz), e também precisa saber por quais tipo de problemas de segurança deve procurar.
Outro estudo mostra como isso é difícil. Trinta desenvolvedores foram contratados para fazer revisões independentes na segurança do código de um pequeno aplicativo web (alguns eram especialistas em segurança, outros eram desenvolvedores web). Eles não foram autorizados a usar ferramentas de análise estática. O aplicativo tinha 6 vulnerabilidades conhecidas. 20% dos revisores não encontraram nenhum dos bugs conhecidos. Nenhum deles encontrou todos os bugs conhecidos, embora vários tenham achado uma nova vulnerabilidade XSS da qual os pesquisadores não tinham conhecimento. Em média, 10 revisores teriam apenas 80% de chance de encontrar todos os bugs de segurança.
E, não Ou
Ferramentas de análise estática são especialmente úteis para os desenvolvedores que trabalham com linguagens inseguras como C / C ++ (onde há uma grande variedade de ferramentas disponíveis para encontrar erros comuns) ou linguagens de script com tipagem dinâmica como Javascript ou PHP (infelizmente as ferramentas para PHP não são boas) e para as equipes começando a aprender uma nova linguagem e estrutura. Utilizar análise estática é (ou deveria ser) uma exigência altamente regulada, especialmente para ambientes críticos de segurança como dispositivos médicos e aviônicos. E até que mais desenvolvedores obtenham mais conhecimento e entendam mais sobre como escrever um software seguro, vamos todos precisam nos apoiar em ferramentas de análise estática (e de análises dinâmicas) para a realização de testes de segurança com a finalidade de encontrar vulnerabilidades.
Mas a análise estática não é um substituto para revisões de código. Sim, revisões de código levam tempo extra pra serem feitas e adicionam os custos ao desenvolvimento, mesmo se você for esperto sobre como deve fazê-las – e ser inteligente inclui a execução de controles de análise estática antes de fazer comentários. Se você quer mover-se rapidamente e escrever bons códigos, com alta qualidade e segurança, ainda terá que fazer revisões no código. Não conte apenas com ferramentas de análise estática.
***
Jim Bird faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://swreflections.blogspot.com.br/2014/09/can-static-analysis-replace-code-reviews.html