Os campos minados da cobertura MISRA
As modernas ferramentas de teste de segurança de aplicativos estáticos (SAST) são normalmente usadas para dois propósitos principais: encontrar bugs e encontrar violações dos padrões de codificação. O objetivo principal do CodeSonar é o primeiro — ele foi originalmente projetado para encontrar sérios defeitos de segurança e segurança, como erros de memória, uso indevido de API e problemas de concorrência; no entanto, ele também é perfeitamente capaz de ser usado para este último, incluindo o padrão de codificação mais popular, MISRA C 2012.
Quando os desenvolvedores são obrigados a aderir aos padrões de codificação, eles procuram uma ferramenta que possa ajudá-los a encontrar violações. Uma das métricas que eles usam para comparar ferramentas é a cobertura: a proporção de regras que a ferramenta afirma verificar, com uma estratégia ingênua sendo escolher a ferramenta que reivindica a maior cobertura do padrão.
Infelizmente, a noção de cobertura não é bem definida, e como não há uma fonte confiável de informação que possa ser usada para comparar a cobertura entre ferramentas, os clientes devem confiar nos fornecedores para interpretar razoavelmente o termo e relatar sua cobertura de forma justa. Infelizmente, alguns vendedores exageram inescrupulosamente a cobertura para obter uma vantagem competitiva, e ao fazê-lo também confundem os consumidores.
Neste artigo, eu desisto um pouco sobre por que a cobertura é uma noção escorregadia, que espero que ajude os clientes a tomar decisões informadas sobre qual ferramenta selecionar.
Alguma cobertura é fácil
Algumas regras são tão simples que é simples escrever um verificador que pode encontrar todas as violações sem falsos positivos. Para essas regras, a cobertura é fácil — a ferramenta pode encontrar violações ou não, sem nenhum fundamento no meio. No MISRA C 2012, tais regras são rotuladas de Decidáveis. Se a violação puder ser detectada olhando apenas para uma unidade de compilação, a regra também será rotulada unidade de tradução única. Por exemplo, a regra 4.2 proíbe o uso de Trigraphs e é rotulada dessa forma. Se uma ferramenta afirma ter cobertura desta categoria de regras, então é perfeitamente razoável acreditar nessa alegação.
As coisas ficam um pouco mais obscuras, no entanto, se uma violação só pode ser encontrada de forma confiável se a ferramenta precisar olhar para várias unidades de compilação ao mesmo tempo (estas são rotuladas system no padrão). Por exemplo, a regra 5.1 do MISRA C 2012: “Identificadores externos devem ser distintos” é certamente decidível, mas a única maneira de uma ferramenta encontrar uma violação de forma confiável é examinando todas as unidades de compilação e comparando todos esses identificadores encontrados em cada um.
Se uma ferramenta afirma ter cobertura completa de uma regra com escopo do Sistema, então é apenas razoável acreditar que a ferramenta também é capaz de encontrar todas as unidades de compilação que contribuem para o programa. A aproximação excessiva e a aproximação do conjunto podem levar a falsos positivos e falsos negativos. Os humanos rotineiramente erram, então um usuário de uma ferramenta que não oferece uma maneira automática de determinar o conjunto, está correndo o risco de obter resultados incorretos.
Técnicas automáticas são surpreendentemente difíceis de acertar. A abordagem mais eficaz é aquela que se integra firmemente com o sistema de construção, já que essa é, na maioria das vezes, a fonte mais confiável.
Indecidabilidade
No MISRA C 2012, algumas regras são rotuladas de “Indecidáveis”, o que significa que é fundamentalmente impossível ter um método que possa, em geral, dizer com certeza se uma violação está presente ou não. Por causa dessa propriedade, o autor de um verificador deve encontrar um ponto doce que equilibre o risco de falsos positivos com o risco de falsos negativos. A maioria dessas regras requer uma análise capaz de argumentar sobre a execução do programa, de modo que apenas as ferramentas SAST mais sofisticadas podem ser esperadas para fazer um bom trabalho. Um bom exemplo é a regra 17.2 do MISRA C 2012, que proíbe a recursão, direta e indireta (ou seja, chamadas através de ponteiros de função).
O problema é que muitas vezes são feitas alegações de cobertura que ignoram se uma ferramenta é boa ou ruim em encontrar violações. Se uma ferramenta só pode encontrar as instâncias mais óbvias e superficiais de violações, é razoável que ela afirme que tem cobertura dessa regra? O outro lado dessa moeda é interessante de se considerar também — se uma ferramenta encontra todas as violações, mas também relata tantos falsos positivos que é impraticável inspecionar todos eles, é justo dizer que tem cobertura?
Cobertura Amplitude
O aspecto final da cobertura de regras que torna complicado é que os padrões de codificação geralmente são bastante vagamente definidos, enquanto as ferramentas SAST devem ter uma definição precisa das propriedades que estão procurando. Consequentemente, é comum um verificador detectar uma propriedade que seja um superconjunto ou um subconjunto do que a regra exige.
Por exemplo, vamos considerar a cobertura da CodeSonar sobre a Norma 2.2 MISRA C 2012: “Não haverá código morto”. Para efeitos desta regra, código morto é código que é executado, mas cuja remoção não pode afetar o comportamento do programa. CodeSonar possui um verificador de valor não utilizado, que encontra lugares onde uma variável é atribuída a um valor que nunca é usado posteriormente. Todos esses lugares violam a regra do MISRA, mas há outras maneiras pelas quais a regra pode ser violada que não são detectadas por este verificador. Assim, o verificador de valor nãousado cobre apenas um subconjunto do que a regra especifica, e outros damas CodeSonar preenchem as lacunas.
Em alguns casos, a regra e o verificador não estão em uma relação subconjunto/superconjunto estrita. Eles podem se sobrepor muito ou um pouco, ou o verificador pode detectar uma propriedade que não é uma violação direta, mas é muito provável que leve a uma violação da regra.
No CodeSonar, nossa política é reivindicar cobertura apenas se houver uma grande sobreposição entre o que a regra especifica e o que nosso verificador encontrará, e onde o verificador não produz avisos que seriam razoavelmente julgados como falsos positivos para essa regra (não obstante que eles possam ser verdadeiros positivos de outra forma).
Uma regra para tocar todos eles
Existe uma regra MISRA C 2012 em particular para a qual esta questão é aguda. Os sinos de alarme devem disparar se você vir uma ferramenta SAST (particularmente uma das ferramentas superficiais) reivindicar a cobertura da Norma 1.3 MISRA C 2012: “Não haverá ocorrência de comportamento indefinido ou crítico não especificado.” Esta regra é tão ampla que precisa de um apêndice adicional de 10 páginas que lista algumas das coisas específicas para evitar. Isso, por sua vez, faz referência às normas C: aquelas para C90/99 enumerar 230 instâncias de comportamento indefinido (65 delas não estão cobertas por nenhuma outra regra MISRA) e 51 instâncias de comportamento crítico não especificado (das quais 17 não estão cobertas por nenhuma outra regra do MISRA). Além disso, a justificativa para a Diretiva 4.1 acrescenta: “a presença de um erro de tempo de execução indica uma violação da Regra 1.3”.
Consequentemente, a Regra 1.3 especifica uma enorme quantidade de comportamento proibido, incluindo dereferências nulas de ponteiros, excessos de buffer, uso de memória não nitializada, corridas de dados, uso após erros livres e muitos dos outros perigos da programação em C.
Os problemas com as reivindicações de cobertura de regras devem ser claros — embora esta regra (das 143 da norma) constitua apenas 0,7% da norma, ela cobre talvez 50% dos tipos verdadeiramente desagradáveis de falhas que podem acontecer a um programa C.
Além disso, se uma ferramenta é para reivindicar a cobertura da Regra 1.3, ela deve ter damas que tenham uma intersecção de bom tamanho com todos esses comportamentos indesejáveis. Se uma ferramenta só pode encontrar uma pequena porcentagem deles, então não é razoável que ela reivindique a cobertura.
Muitas ferramentas SAST que afirmam encontrar violações das regras da MISRA são ferramentas bastante superficiais (como as da família Lint), e, como tal, são muito fracas em encontrar violações de 1,3, embora reivindiquem a cobertura. Em contraste, ferramentas AVANÇADAs do SAST, como o CodeSonar, são explicitamente projetadas para encontrar os tipos de erros de tempo de execução que constituem violações da Regra 1.3. As análises que possibilitam que eles encontrem tais defeitos com precisão razoável devem ser completas- programa, sensíveis ao caminho, conscientes de fluxos de informações perigosos e capazes de raciocínio sobre segmentos de execução simultânea.
Avaliando as reivindicações de cobertura do MISRA
Em conclusão, deixe-me resumir os pontos mais importantes:
- Não há uma boa definição amplamente aceita de cobertura MISRA, mesmo para regras que sejam decidíveis.
- É fundamentalmente impossível ter um verificador perfeito para uma regra que é indecidível. Falsos positivos e falsos negativos para estes são inevitáveis.
- Damas e regras nem sempre se cruzam perfeitamente.
- Alegações de alta cobertura das regras da MISRA não devem ser tomadas pelo valor nominal. Os vendedores têm incentivo livre de penalidades para exagerar.
- MISRA C 2012 A regra 1.3 abrange uma vasta quantidade de comportamento a ser evitado. Apenas ferramentas SAST sofisticadas cujo objetivo principal é encontrar tais bugs são boas em encontrar violações desta regra.
o tomar uma decisão sobre qual ferramenta usar, as perguntas que se deve fazer são: “Quais são os problemas reais no meu código? Eles estão apenas codificando violações padrão, ou bugs reais? Quão bem essa ferramenta realmente encontra os problemas que eu preciso encontrar?” A melhor maneira de responder a essa pergunta é experimentar a ferramenta em seu próprio código, e avaliar os resultados racionalmente.
Para saber mais, damos as boas-vindas para baixar um artigo lido neste white paper, “Acelerando a conformidade de segurança automotiva da MISRA com testes de segurança de aplicativos estáticos”.
Autor: Christian Simko