O que é MISRA e como cozinhá-lo

Figura 1


Talvez todo desenvolvedor de programas para microcontroladores tenha provavelmente ouvido pelo menos uma vez falar sobre padrões especiais de codificação projetados para ajudar a aumentar a segurança e a portabilidade do seu código. Um desses padrões é o MISRA. Neste artigo, examinaremos em mais detalhes o que é esse padrão, qual é a sua filosofia e como usá-lo em seus projetos.

Muitos de nossos leitores ouviram dizer que o PVS-Studio suporta a classificação de seus alertas de acordo com o padrão MISRA. Atualmente, o PVS-Studio cobre mais de 100 regras MISRA C: 2012 e MISRA C ++: 2008.

Este artigo tem como objetivo matar três coelhos com uma cajadada:

  1. Diga o que é MISRA para aqueles que não estão familiarizados com esse padrão;
  2. Lembre o mundo incorporado do que somos capazes;
  3. Ajudar a aprofundar o curso dos negócios para novos funcionários que também desenvolverão ainda mais nosso analisador MISRA;

Espero poder torná-lo interessante. Então, vamos começar!

História MISRA


A história do MISRA começou há muito tempo. Então, no início dos anos 90, o programa do governo do Reino Unido, com o nome indicativo "TI Segura", alocou financiamento para vários projetos, de uma forma ou de outra relacionados à segurança dos sistemas eletrônicos. O projeto MISRA (Associação de Confiabilidade de Software da Indústria Automobilística) foi criado para criar um guia para o desenvolvimento de software para microcontroladores em veículos terrestres - em carros, em geral.

Tendo recebido financiamento do estado, a equipe do MISRA começou a trabalhar e, em novembro de 1994, lançou seu primeiro guia: " Diretrizes de desenvolvimento para software baseado em veículo ". Este guia ainda não foi vinculado a um idioma específico, mas devo admitir: o trabalho foi impressionante e provavelmente envolveu todos os aspectos possíveis do desenvolvimento de software incorporado. A propósito, os desenvolvedores deste guia comemoraram recentemente o 25º aniversário de uma data tão importante para eles.

Quando o financiamento do estado terminou, os membros do MISRA decidiram continuar trabalhando juntos de maneira informal - isso continua até hoje. De fato, o MISRA (como organização) é uma comunidade de partes interessadas de várias indústrias de automóveis e aeronaves. Agora essas festas são:

  • Bentley automóveis
  • Ford Motor Company
  • Jaguar land rover
  • Delphi diesel systems
  • HORIBA MIRA
  • Protean electric
  • Serviços de engenharia Visteon
  • Universidade de leeds
  • Ricardo uk
  • ZF TRW

Participantes de mercado muito fortes, não é? Não é de surpreender que seu primeiro padrão relacionado ao idioma, MISRA C, tenha sido amplamente aceito entre desenvolvedores embarcados de missão crítica. MISRA C ++ apareceu um pouco mais tarde. Gradualmente, as versões dos padrões foram atualizadas e refinadas para cobrir os novos recursos dos idiomas. No momento da redação deste artigo, as versões atuais são MISRA C: 2012 e MISRA C ++: 2008.

Filosofia e exemplos de regras


As características mais distintas do MISRA são sua incrível atenção aos detalhes e extrema meticulosidade para garantir a segurança. Os autores não apenas reuniram em um só lugar todos os “buracos” C e C ++ que vieram à mente (como, por exemplo, os autores do CERT) - eles elaboraram cuidadosamente os padrões internacionais dessas linguagens e anotaram todas as maneiras concebíveis e impensáveis ​​de cometer erros. E então eles pegaram e adicionaram as regras sobre a legibilidade do código de cima - para dificultar a introdução de um novo erro no código já limpo.

Para entender a extensão da seriedade, considere algumas regras retiradas do padrão.

Por um lado, existem muitas regras boas e adequadas que sempre devem ser seguidas o tempo todo, independentemente do objetivo do seu projeto. Na maioria das vezes, eles são projetados para eliminar comportamentos indefinidos / não especificados / dependentes da implementação. Por exemplo:

  • Não use o valor de uma variável não inicializada
  • Não use o ponteiro FILE após fechar o fluxo
  • Todas as funções não nulas devem retornar um valor.
  • O contador de loop não deve ter um tipo de ponto flutuante
  • ... etc.

Por outro lado, existem regras, cujos benefícios estão na superfície, mas que (do ponto de vista de projetos comuns) não são tão pecaminosos para quebrar:

  • Não use goto e longjmp
  • Cada opção deve terminar com o padrão
  • Não escreva código inacessível
  • Não use funções variáveis
  • Não use aritmética de endereço (exceto [] e ++ )
  • ...

Essas regras também não são ruins e, em combinação com as anteriores, elas já oferecem um aumento tangível na segurança, mas isso é suficiente para sistemas embarcados altamente responsáveis? Eles são usados ​​não apenas na indústria automotiva, mas também na fabricação de aeronaves, aeroespacial, militar e médica.

Não queremos que, devido a um erro de software, algumas máquinas de raios X irradiem pacientes com uma dose de 20.000 rad , para que as regras "cotidianas" usuais não sejam mais suficientes. Está em jogo vidas humanas e enormes quantias de dinheiro, e meticulosidade deve ser incluída. Aqui, o restante das regras do MISRA entra em cena:
  • O sufixo 'L' no literal deve sempre estar em maiúsculas (o pequeno 'l' pode ser confundido com a unidade)
  • Não use o operador de vírgula (aumenta a chance de cometer um erro)
  • Não use recursão (uma pequena pilha de microcontroladores pode transbordar facilmente)
  • Os corpos das instruções if , else , for , while , do , switch devem ser colocados entre chaves (você pode cometer um erro se o código não estiver alinhado corretamente )
  • Não use memória dinâmica (porque há uma chance de alocá-la sem êxito da pilha, especialmente em microcontroladores)
  • ... e muitas, muitas dessas regras.

Muitas vezes, as pessoas que encontram MISRA têm uma opinião de que a filosofia do padrão é "proibir isso e proibir isso". De fato, é assim, mas apenas em parte.

Sim, o padrão tem muitas regras semelhantes, mas seu objetivo não é proibir tudo o que é possível, mas listar todas as formas possíveis de alguma forma violar a segurança do código. Para a maioria das regras, você escolhe se as segue ou não. Vou explicar isso em mais detalhes.

No MISRA C, as regras se enquadram em três categorias principais: Obrigatório, Requerido e Consultivo. Obrigatório - são regras que não devem ser violadas sob nenhum pretexto. Por exemplo, esta seção inclui a regra "não use o valor de uma variável não inicializada". As regras necessárias são menos rigorosas: elas permitem a possibilidade de rejeição, mas somente se esses desvios forem cuidadosamente documentados e justificados por escrito. As regras restantes estão incluídas na categoria Consultivo - são regras que não precisam ser seguidas.

O MISRA C ++ é um pouco diferente: a categoria Obrigatória está ausente e a maioria das regras pertence à categoria Necessária. Portanto, de fato, você tem o direito de violar qualquer regra - lembre-se de documentar os desvios. Há também uma categoria Documento - estas são regras obrigatórias (desvios não são permitidos), associadas a práticas comuns como “Cada uso do assembler deve ser documentado” ou “a biblioteca de plug-ins deve estar em conformidade com o MISRA C ++”.

O que mais há


De fato, MISRA não consiste apenas de um conjunto de regras. De fato, este é um manual para escrever código seguro para microcontroladores e, portanto, está cheio de todos os tipos de utilidades. Vamos olhar para eles em detalhes.

Em primeiro lugar, o padrão contém uma descrição bastante completa do plano de fundo: para o que o padrão foi criado, por que o C ou C ++ foi escolhido, as vantagens e desvantagens dessas linguagens.

Estamos bem cientes das virtudes dessas línguas. Sim, e também sobre as deficiências em geral :) Quais são a alta complexidade, a especificação incompleta do padrão e a sintaxe que tornam muito fácil cometer um erro e, em seguida, procurar um erro longo. Por exemplo, você pode escrever acidentalmente isso:

for (int i = 0; i < n; ++i); { do_something(); } 

Ainda assim, há uma chance de uma pessoa não notar um ponto e vírgula extra , certo? Você também pode escrever assim :
 void SpendTime(bool doWantToKillPeople) { if (doWantToKillPeople = true) { StartNuclearWar(); } else { PlayComputerGames(); } } 

É bom que o primeiro e o segundo casos sejam facilmente capturados pelas regras MISRA (o primeiro é MISRA C: 13.4 / MISRA C ++: 6.2.1, o segundo é MISRA C: 13.4 / MISRA C ++: 6.2.1).

Além de descrever os problemas, o padrão contém um grande número de dicas sobre o que você precisa saber antes de começar: sobre como configurar o processo de desenvolvimento MISRA, sobre o uso de analisadores estáticos para verificar o código de conformidade, quais documentos você precisa manter e como preencher, e assim por diante.

Também no final, existem aplicativos que contêm: uma lista curta e uma tabela de regras resumida, uma pequena lista de vulnerabilidades do C / C ++, um exemplo de desvio da documentação da regra e várias listas de verificação projetadas para ajudar você a não se perder em toda a burocracia.

Como você pode ver, o MISRA não é apenas um conjunto de regras, mas quase toda uma infraestrutura para escrever código seguro para sistemas embarcados.

Use em seus projetos


Imagine uma situação: você irá escrever um programa para um sistema embarcado muito necessário e responsável. Ou você já tem um programa, mas precisa “transferi-lo” para o MISRA. Como verificar seu código quanto à conformidade com o padrão? Você realmente tem que fazer isso manualmente?

A verificação manual de código não é uma tarefa fácil e potencialmente impossível. Cada revisor não apenas teria que examinar cuidadosamente todas as linhas de código, mas também teria que conhecer o padrão de cor. Horror!

Portanto, os próprios desenvolvedores do MISRA são aconselhados a usar a análise estática para testar seu código. De fato, a análise estática é um processo automatizado de revisão de código. Você simplesmente executa o analisador em seu programa e em alguns minutos receberá um relatório sobre possíveis violações do padrão. O que você precisa, certo? Você apenas precisa visualizar o log e corrigir a resposta.

Próxima pergunta: em que ponto você começa a usar o MISRA? A resposta é simples: quanto mais cedo melhor. Idealmente, antes mesmo de começar a escrever o código, porque o MISRA assume que você segue o padrão ao longo da vida útil do seu código.

Obviamente, nem sempre é possível escrever MISRA desde o início. Por exemplo, muitas vezes acontece que um projeto já foi parcial ou totalmente implementado, mas o cliente desejou que o projeto estivesse em conformidade com o padrão. Nesse caso, você terá que fazer uma refatoração completa do código existente.

É aqui que a armadilha aparece. Eu diria mesmo que uma pedra subaquática aparece. O que acontece se você pegar um analisador estático e verificar o projeto "comum" quanto à conformidade com o padrão MISRA? Spoiler: você pode se assustar.

Figura 5


Obviamente, o exemplo na imagem é exagerado. Aqui você pode ver o resultado da verificação de um projeto suficientemente grande, que na verdade nunca foi pensado para trabalhar em microcontroladores. No entanto, ao verificar um código existente, você pode ver uma, duas, cinco ou até dez mil operações do analisador. E em toda essa pilha novas operações serão perdidas que foram emitidas para o código que acabou de ser escrito ou alterado.

O que fazer sobre isso? É realmente necessário deixar de lado todas as coisas e sentar-se para corrigir todos os aspectos positivos antigos?

Sabemos que na primeira vez que um projeto é verificado, muitos aspectos positivos aparecem com bastante frequência e desenvolvemos uma solução que o ajudará a obter o benefício do analisador imediatamente, sem interromper o trabalho. Essa solução é chamada de "suprimir base".

Suprimir bases é o mecanismo PVS-Studio que permite suprimir massivamente as mensagens do analisador. Se você estiver verificando o projeto pela primeira vez e descobrindo vários milhares de pontos positivos lá, basta adicioná-los à base suprimida e, na próxima vez em que executar o analisador, ele emitirá zero avisos.

Assim, você pode continuar escrevendo e modificando o código da maneira usual e, ao mesmo tempo, verá avisos apenas sobre os erros que acabaram de ser introduzidos no projeto. Ao mesmo tempo, você obterá o máximo benefício do analisador aqui e agora, sem se distrair com a correção de erros antigos. Alguns cliques - e o analisador está implementado! Você pode ler instruções detalhadas sobre isso aqui .

Você provavelmente pode perguntar: “Espere, o que fazer com respostas ocultas?” A resposta é bastante simples: não as esqueça e corrija-as silenciosamente. Você pode, por exemplo, estabelecer a base de supressão no sistema de controle de versão e permitir apenas as confirmações que não aumentam o número de operações. Assim, gradualmente, sua "rocha subaquática", mais cedo ou mais tarde, é drenada e não haverá vestígios dela.

Ok, o analisador está implementado e agora estamos prontos para continuar. O que fazer depois? Negócio claro - para trabalhar com o código. Mas o que é necessário para poder declarar conformidade com o padrão? Como provar que seu projeto está em conformidade com MISRA?

O fato é que não há um "certificado" especial que seu código esteja em conformidade com MISRA. Conforme o próprio padrão estipula, o rastreamento do código de conformidade deve ser realizado por duas partes: o cliente do software e o fornecedor do software. O fornecedor desenvolve software que cumpre com a norma e preenche os documentos necessários. O cliente, por sua vez, deve garantir que os dados desses documentos sejam verdadeiros.

Se você é um cliente e um desenvolvedor de seu próprio software, a responsabilidade pela conformidade com o padrão fica apenas em seus ombros :)

Em geral, para provar a conformidade do seu projeto, você precisará de documentos de prova. A lista de documentos que os desenvolvedores do projeto devem preparar pode variar, mas o MISRA oferece alguns como referência. Vamos considerar esse conjunto com mais detalhes.

Para reivindicar a conformidade com o padrão, você precisará de algumas coisas:

  • Na verdade, um projeto cujo código está em conformidade com as regras obrigatórias e obrigatórias
  • Guie plano de execução
  • Documentação de todos os avisos do compilador e do analisador estático
  • Documentação de todos os desvios das regras necessárias
  • Resumo de conformidade com as diretrizes

O primeiro é um plano de conformidade. Esta é a sua tabela mais importante e será a que enviará o examinador para todos os outros documentos. Na primeira coluna, há uma lista de regras MISRA; no restante, é observado se algum desvio dessas regras foi identificado. Esta tabela é mais ou menos assim:

Figura 8

O padrão recomenda a criação do seu projeto com vários compiladores, além do uso de dois ou mais analisadores estáticos para verificar a conformidade do seu código. Se o compilador ou analisador gerar algum tipo de aviso associado à regra, observe isso na tabela e no documento: por que a operação não pode ser eliminada, se é falsa etc.

Se alguma das regras não puder ser verificada com um analisador estático, você precisará executar o procedimento de revisão de código. Este procedimento também deve ser documentado, após o qual um link para esta documentação deve ser adicionado ao plano de conformidade.

Se o compilador ou o analisador estático estiver correto, ou se forem encontradas violações reais do código durante o processo de revisão de código, você deverá corrigi-las ou documentá-las. Novamente, anexando um link à documentação na tabela.

Portanto, um plano de conformidade é um documento pelo qual você pode encontrar documentação para qualquer desvio identificado no seu código.

Agora um pouco sobre a documentação dos desvios das regras. Como já mencionei, essa documentação é necessária apenas para as regras necessárias, porque você não pode violar as regras de nível obrigatório e as regras de consultoria não podem ser seguidas sem nenhuma documentação.

Se você decidir se desviar da regra, a documentação deverá conter:

  • Número de regra quebrada
  • Local de desvio exato
  • A validade do desvio
  • Evidência de que o desvio não comprometa a segurança
  • Implicações potenciais do usuário

Como você pode ver, essa abordagem da documentação faz com que você pense seriamente se a violação vale a pena. Isso é feito especificamente para violar as regras necessárias não eram boas :)

Agora, sobre o resumo da conformidade com as regras. Este documento é talvez o mais fácil de preencher:

Figura 2

A coluna central é preenchida antes de você começar a trabalhar com o código e a coluna mais à direita é depois que seu projeto está pronto.

É bastante razoável fazer uma pergunta: por que você precisa especificar categorias de regras, se elas já estão especificadas no próprio padrão? O fato é que o padrão permite o "aumento" da regra em uma categoria mais rigorosa. Por exemplo, um cliente pode solicitar que você mova uma regra de consultoria para uma categoria. Esse "aumento" deve ser feito antes de se trabalhar com o código, e um resumo da conformidade com as regras permite que isso seja claramente observado.

Com a última coluna, tudo é simples: basta observar se a regra é usada e, em caso afirmativo, há desvios.

Essa tabela inteira é necessária para que você possa ver rapidamente quais prioridades as regras têm e se o código corresponde a elas. Se de repente você se interessar em saber o motivo exato da rejeição, sempre poderá consultar o plano de conformidade e encontrar a documentação necessária.

Figura 3

Então, você escreveu o código cuidadosamente, seguindo as regras MISRA. Você fez um plano de conformidade, documentou tudo o que podia documentar e preencheu um resumo de conformidade. Se isso for verdade, você recebeu um código muito limpo, legível e muito confiável, que você agora odeia :)

Onde seu programa vai morar agora? Em uma máquina de ressonância magnética? Em um sensor de velocidade comum ou no sistema de piloto automático de algum satélite espacial? Sim, você passou por um caminho burocrático sério, mas esses são insignificantes. Como não ser meticuloso quando vidas humanas reais estão em jogo?

Se você conseguiu e conseguiu chegar a um fim vitorioso, parabenizo sinceramente: você escreve um código de segurança de alta qualidade. Obrigada

O futuro dos padrões


Por fim, quero falar um pouco sobre o futuro dos padrões.

MISRA está atualmente vivendo e se desenvolvendo. Por exemplo, no início de 2019, foi anunciada a "The MISRA C: 2012 Third Edition (First Revision)" - uma atualização e complementada pelas novas regras 2012 padrão. Ao mesmo tempo, eles anunciaram o próximo lançamento da MISRA C: 2012 Alteração 2 - C11 Core, o padrão de 2012, no qual serão adicionadas regras que abrangerão as versões do idioma C para 2011 e 2018 pela primeira vez.

Não fica parado e o MISRA C ++. Como você sabe, o padrão MISRA C ++ mais recente data de 2008, portanto, a versão mais antiga do idioma que ele cobre é C ++ 03. Por esse motivo, existe outro padrão, semelhante ao MISRA, e é chamado AUTOSAR C ++. Foi originalmente concebido como uma continuação do MISRA C ++ e pretendia abranger versões posteriores da linguagem. Ao contrário de sua mente ideal, o AUTOSAR C ++ é atualizado duas vezes por ano e atualmente suporta C ++ 14. Uma atualização adicional está planejada para C ++ 17, C ++ 20 e assim por diante.

O que eu comecei sobre algum outro padrão? O fato é que, há pouco menos de um ano, ambas as organizações anunciaram a unificação de seus padrões em um. Agora o MISRA C ++ e o AUTOSAR C ++ se tornarão um único padrão e agora serão desenvolvidos juntos. Eu acho que essas são ótimas notícias para desenvolvedores que escrevem sob microcontroladores C ++ e não menos ótimas para desenvolvedores de analisadores estáticos. Ainda há muito trabalho favorito pela frente! :)

Conclusão


Hoje aprendemos muito sobre o MISRA: lemos a história de sua ocorrência, estudamos exemplos de regras e a filosofia do padrão, consideramos tudo o que você precisa para usar o MISRA em seus projetos e até olhamos um pouco para o futuro. Espero que agora você entenda melhor o que é MISRA e como cozinhá-lo!

De acordo com a antiga tradição, deixarei um link aqui para o nosso analisador estático PVS-Studio. É capaz de encontrar não apenas desvios do padrão MISRA, mas também uma enorme variedade de erros e vulnerabilidades. Se você estiver interessado em experimentar o PVS-Studio, faça o download da versão demo e verifique seu projeto.

Isso conclui meu artigo. Desejo a todos os leitores um feliz Ano Novo e um feliz fim de semana!

Sitelinks


  1. Georgy Gribkov - " Segurança na velocidade máxima - como escrever código C / C ++ confiável para sistemas embarcados ".
  2. O PVS-Studio é um analisador de código estático .
  3. Colaboração PVS-Studio e KEIL 5 .



Se você deseja compartilhar este artigo com um público que fala inglês, use o link para a tradução: George Gribkov. O que é o MISRA e como cozinhá-lo .

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


All Articles