Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial Internet of Things >> Integrado

Desenvolva novos hábitos de codificação para reduzir erros em software embarcado


O tamanho e a complexidade do aplicativo aumentaram significativamente na última década. Veja o setor automotivo como exemplo. De acordo com o The New York Times , 20 anos atrás, o carro médio tinha um milhão de linhas de código, mas 10 anos depois, o Chevrolet Volt 2010 da General Motors tinha cerca de 10 milhões de linhas de código - mais do que um caça a jato F-35. Hoje, um carro médio tem mais de 100 milhões de linhas de código.

A mudança para processadores de 32 bits e superiores com muita memória e potência permitiu que as empresas incluíssem muito mais recursos e capacidades de valor agregado em projetos; esse é o lado bom. A desvantagem é que a quantidade de código e sua complexidade geralmente resultam em falhas que afetam a segurança e a proteção do aplicativo.

É hora de uma abordagem melhor. Dois tipos principais de erros podem ser encontrados no software e resolvidos usando ferramentas que evitam a introdução de erros:

Resolva esses erros e os engenheiros de design estarão muito longe no caminho para um código mais seguro e protegido.

Um pouco de prevenção por meio da verificação de código

Erros no código acontecem tão facilmente quanto erros no e-mail e mensagens instantâneas. Esses são os erros simples que acontecem porque os engenheiros estão com pressa e não revisam. Mas com a complexidade vem uma gama de erros de design que criam enormes desafios. A complexidade gera a necessidade de um nível totalmente novo de compreensão de como o sistema funciona, como os dados são transmitidos e como os valores são definidos. Sejam erros causados ​​por complexidade ou algum tipo de problema humano, eles podem resultar em uma parte do código tentando acessar um valor fora dos limites de um array. E um padrão de codificação capta isso.

Você também pode estar interessado nestes artigos relacionados de Embedded:

Construa sistemas embarcados seguros e confiáveis ​​com MISRA C / C ++

Uso de análise estática para detectar erros de codificação em aplicativos de servidor de código aberto essenciais para a segurança

Como evitar esses erros? Não os coloque lá em primeiro lugar. Embora pareça óbvio - e quase impossível -, esse é exatamente o valor que um padrão de codificação traz para a mesa.

No mundo C e C ++, 80% dos defeitos de software são causados ​​pelo uso incorreto ou imprudente de cerca de 20% da linguagem. O padrão de codificação cria restrições nas partes da linguagem conhecidas por serem problemáticas. Resultado:os defeitos são evitados e a qualidade do software aumenta muito. Vamos dar uma olhada em alguns exemplos.

A maioria dos erros de programação C e C ++ são causados ​​por comportamentos indefinidos, definidos pela implementação e não especificados que são inerentes a cada linguagem, que levam a bugs de software e problemas de segurança. Este comportamento definido pela implementação propaga um bit de alta ordem quando um inteiro assinado é deslocado para a direita. Dependendo do uso dos engenheiros do compilador, o resultado pode ser 0x40000000 ou 0xC0000000, pois C não especifica a ordem em que os argumentos para uma função são avaliados.


Figura 1. O comportamento de algumas construções C e C ++ depende do compilador usado. Fonte:LDRA

Na Figura 2 - onde o rollDice () função simplesmente lê o próximo valor de um buffer circular contendo os valores “1,2,3 e 4” - o valor retornado esperado seria 1234. Mas não há garantia disso. Pelo menos um compilador gera código que retorna o valor 3412.


Figura 2. O comportamento de algumas construções C e C ++ não é especificado pelas linguagens. Fonte:LDRA

Existem muitas outras armadilhas na linguagem C / C ++:uso de construções como goto ou malloc ; misturas de valores com e sem sinal; ou código “inteligente” que pode ser altamente eficiente e compacto, mas é tão enigmático e complexo que outras pessoas lutam para entendê-lo. Qualquer um desses problemas pode levar a defeitos, estouros de valor que repentinamente se tornam negativos ou simplesmente impossibilitar a manutenção do código.

Os padrões de codificação fornecem a onça de prevenção para esses males. Eles podem impedir o uso dessas construções problemáticas e impedir que os desenvolvedores criem código não documentado e excessivamente complexo, bem como verificar a consistência do estilo. Mesmo coisas como verificar se o caractere de tabulação não é usado ou se os parênteses estão posicionados em uma posição específica podem ser monitorados. Embora pareça trivial, seguir o estilo ajuda tremendamente a revisão manual do código e evita confusões causadas por um tamanho de guia diferente quando o código é visualizado em outro editor - todas as distrações que impedem um revisor de se concentrar no código.

MISRA para o resgate

Os padrões de programação mais conhecidos são as diretrizes MISRA, publicadas pela primeira vez em 1998 para a indústria automotiva e agora comumente adotadas por muitos compiladores incorporados que oferecem algum nível de verificação MISRA. MISRA enfoca as construções e práticas problemáticas dentro das linguagens C e C ++, recomendando o uso de características estilísticas consistentes, mas não chega a sugerir nenhuma.

As diretrizes da MISRA fornecem explicações úteis sobre por que cada regra existe, junto com detalhes das várias exceções a essa regra e exemplos de comportamento indefinido, não especificado e definido pela implementação. A Figura 3 ilustra o nível de orientação.


Figura 3. Essas referências MISRA C pertencem ao comportamento indefinido, não especificado e definido pela implementação. Fonte:LDRA

A maioria das diretrizes da MISRA são “Decidíveis”, o que significa que a ferramenta pode identificar se há uma violação; mas alguns são "Indecidíveis", o que significa que nem sempre é possível para a ferramenta deduzir se há uma violação.

Uma variável não inicializada passada para uma função do sistema que deve inicializá-la pode não ser registrada como um erro se a ferramenta de análise estática não tiver acesso ao código-fonte para a função do sistema. Existe o potencial para um falso negativo ou um falso positivo.

Em 2016, 14 diretrizes foram adicionadas ao MISRA para fornecer verificação de código de segurança crítica, não apenas segurança. A Figura 4 ilustra como uma das novas diretrizes - Diretiva 4.14 - resolve esse problema e ajuda a prevenir as armadilhas devido a comportamento indefinido.


Figura 4. A Diretiva MISRA 4.14 ajuda a prevenir as armadilhas causadas por comportamento indefinido. Fonte:LDRA

Os rigores dos padrões de codificação eram tradicionalmente associados a software funcionalmente seguro para aplicativos essenciais, como carros, aviões e dispositivos médicos. No entanto, a complexidade do código, a criticidade da segurança e a importância comercial de criar um código robusto e de alta qualidade que seja fácil de manter e atualizar tornam os padrões de codificação cruciais em todas as operações de desenvolvimento.

Para garantir que os erros não sejam introduzidos no código em primeiro lugar, as equipes de desenvolvimento devem:


A verificação de código oferece uma caixa de ferramentas com enormes benefícios potenciais.

Meio quilo de cura com ferramentas de teste

Embora a verificação de código resolva muitos problemas, os bugs do aplicativo só podem ser encontrados testando se o produto faz o que deve fazer, e isso significa ter requisitos. Para evitar bugs de aplicativo, é necessário projetar o produto certo e projetar o produto da maneira certa.

Projetar o produto certo significa estabelecer os requisitos antecipadamente e garantir a rastreabilidade bidirecional entre os requisitos e o código-fonte, de forma que cada requisito seja implementado e cada função de software seja rastreada até um requisito. Qualquer funcionalidade ausente ou desnecessária - que não atende a um requisito - é um bug do aplicativo. Projetar o produto certo é o processo de confirmação de que o código do sistema desenvolvido atende aos requisitos do projeto. Você consegue isso realizando testes baseados em requisitos.

A Figura 5 mostra um exemplo de rastreabilidade bidirecional. A única função selecionada rastreia o fluxo ascendente da função para um requisito de baixo nível, depois para um requisito de alto nível e, finalmente, para um requisito de nível de sistema.


Figura 5. Este é um exemplo de rastreabilidade bidirecional com uma única função selecionada. Fonte:LDRA

A Figura 6 mostra como a seleção de um requisito de alto nível exibe a rastreabilidade upstream para um requisito de nível de sistema e downstream para requisitos de baixo nível e funções de código-fonte.


Figura 6. Este é um exemplo de rastreabilidade bidirecional com requisitos selecionados. Fonte:LDRA

Essa capacidade de visualizar a rastreabilidade pode levar à detecção de bugs de aplicativo no início do ciclo de vida.

Testar a funcionalidade do código exige uma consciência do que ele deve fazer, e isso significa ter requisitos de baixo nível que definem o que cada função faz. A Figura 7 mostra um exemplo de requisito de baixo nível, que, neste caso, descreve totalmente uma única função.


Figura 7. Este é um exemplo de um requisito de baixo nível que descreve uma única função. Fonte:LDRA

Os casos de teste são derivados de requisitos de baixo nível, conforme ilustrado na Figura 8.


Figura 8. Os casos de teste são derivados de requisitos de baixo nível. Fonte:LDRA

Usando uma ferramenta de teste de unidade, esses casos de teste podem ser executados no host ou no destino para garantir que o código se comporte da maneira que o requisito diz que deveria. A Figura 9 mostra que todos os casos de teste foram regredidos e aprovados.


Figura 9. É assim que uma ferramenta realiza testes de unidade. Fonte:LDRA

Após a execução dos casos de teste, a cobertura estrutural deve ser medida para garantir que todo o código foi executado. Se a cobertura não for de 100 por cento, é possível que mais casos de teste sejam necessários ou códigos supérfluos sejam removidos.

Novos hábitos de codificação

Não há dúvida sobre isso, a complexidade do software - e seus erros - cresceram com conectividade, memória mais rápida, plataformas de hardware ricas e demandas específicas do cliente. A adoção de um padrão de codificação de última geração, a medição de métricas no código, o rastreamento de requisitos e a implementação de testes baseados em requisitos fornecem às equipes de desenvolvimento a oportunidade de criar código de alta qualidade e reduzir a responsabilidade.

Até que ponto uma equipe adota esses novos hábitos, quando nenhum padrão exige conformidade, depende do reconhecimento corporativo da mudança de jogo que eles trazem. A adoção dessas práticas, seja um produto essencial para a proteção ou para a segurança, pode fazer uma diferença noite e dia na manutenção e robustez do código. O código limpo simplifica a adição de novos recursos, facilita a manutenção do produto e mantém os custos e a programação ao mínimo - todas as características que melhoram o ROI da sua empresa.

Quer um produto seja crítico para a segurança ou não, esse é certamente um resultado que só pode ser benéfico para a equipe de desenvolvimento.

>> Este artigo foi publicado originalmente em nosso site irmão, EDN.



Integrado

  1. As strings de texto são uma vulnerabilidade no software incorporado?
  2. Arquitetura SOAFEE para borda incorporada permite carros definidos por software
  3. Pixus:novas placas frontais grossas e robustas para placas incorporadas
  4. Kontron:novo padrão de computação incorporado COM HPC
  5. GE Digital lança novo software de gerenciamento de ativos
  6. Como não ser péssimo em ensinar um novo software
  7. Riscos de software:Protegendo código aberto em IoT
  8. Três etapas para proteger as cadeias de suprimentos de software
  9. Saelig lança novo PC embutido feito pela Amplicon
  10. Usando DevOps para enfrentar desafios de software incorporado