Programação confiável por idioma - revisão noob. Parte 1

Mais uma vez, levei dois dias para escrever e depurar apenas quatrocentas linhas de código da biblioteca do sistema, surgiu a idéia - "como se fosse bom se os programas fossem escritos de uma maneira menos dolorosa".

E antes de tudo, como a depuração leva muito mais tempo do que escrever código - você precisa de proteção contra o tolo (inclusive você) no estágio de escrita. E gostaria de recebê-lo da linguagem de programação usada (YP).

Obviamente, precisamos inventar um novo e melhor YaP!
Não, primeiro tentaremos expressar nossos desejos e ver o que já inventamos.

Então, o que eu gostaria de receber:

  • Resistência a erros humanos, eliminação de ambiguidades durante a compilação
  • Resistência de entrada
  • Resistência a danos ao programa ou dados - falha na mídia, hackers
  • Ao mesmo tempo, todos têm sintaxe e funcionalidade mais ou menos toleráveis

As áreas de aplicação são máquinas, transporte, sistemas de controle industrial, Internet das coisas, incluindo telefones.

Dificilmente é necessário para a Web, ela é construída (por enquanto) sobre o princípio de "encerrar e reiniciar" (acionar e esquecer).

Rapidamente, você pode concluir que o idioma deve ser compilado (pelo menos Pi-compilado) para que todas as verificações sejam executadas ao máximo no estágio de compilação sem o VS (versus, a seguir, a oposição negativa) "oh, esse objeto não tem essa propriedade" em tempo de execução. Até o script das descrições da interface já torna obrigatório cobrir totalmente esses scripts com testes.

Pessoalmente, não quero pagar com meus recursos (incluindo dinheiro para hardware mais rápido e mais caro) pela interpretação; portanto, é aconselhável ter uma compilação JIT mínima.

Então, os requisitos.

Tolerância a erro humano


Tendo folheado diligentemente os Talmuds do PVS-Studio, descobri que os erros mais comuns são erros de digitação e copiar e colar não corrigidos.

Também adicionarei alguns incidentes da minha experiência e os encontrei em várias publicações, como exemplos negativos. Além disso, as regras MISRA C foram atualizadas na memória.

Depois de pensar um pouco, cheguei à conclusão de que os linters aplicados ex-facto sofrem de um "erro de sobrevivente", já que em projetos antigos erros graves já foram corrigidos.

a) Livre-se de nomes semelhantes

- Uma verificação rigorosa deve ser feita na visibilidade de variáveis ​​e funções. Depois de selado, você pode usar um identificador de um escopo mais geral, em vez do desejado
- Use nomes que não diferenciam maiúsculas de minúsculas. (VS) "Vamos chamar a função como variável, apenas no Camelcase" e depois comparar com algo - em C isso pode ser feito (obtemos o endereço da função, que é um número bastante grande)
- Nomes com uma diferença de 1 letra devem causar um aviso (sem dúvida, você pode destacar no IDE), mas um erro muito comum de copiar e colar .x, .y, .w, .h.
- não permitimos o mesmo nome para entidades diferentes - se houver uma constante com esse nome, não deverá haver uma variável com o mesmo nome ou nome do tipo
- é altamente desejável verificar a nomeação de todos os módulos do projeto - é fácil confundir, especialmente se pessoas diferentes escrevem módulos diferentes

b) Uma vez mencionado - deve haver modularidade e, de preferência, hierárquica - um projeto do VS de 12.000 arquivos em um diretório é um inferno para as pesquisas.
Ainda é necessária modularidade para descrever estruturas de troca de dados entre diferentes partes (módulos, programas) de um projeto. VS Eu encontrei um erro devido ao alinhamento diferente de números na estrutura de troca no receptor e no transmissor.

- Para excluir a possibilidade de ligação duplicada (layout).

c) Ambiguidades
- Deve haver uma ordem específica de chamadas de função. Ao escrever X = funcA () + fB () ou Fn (funcA (), fB (), callC ()) - você precisa entender que a pessoa espera receber os cálculos na ordem escrita (VS) e não como o otimizador pensou.
- Excluir operadores semelhantes. E não como em C: + ++, <<<, | ||, & &&, = ==
- É aconselhável ter alguns operadores compreensíveis e com uma prioridade óbvia. Olá do operador ternário.
- Substituir operadores é bastante prejudicial. Você escreve i: = 2, mas (VS) na verdade causa uma criação implícita de um objeto para o qual não há memória suficiente, e o disco trava ao trocar e o satélite trava em Marte :-(

De fato, por experiência pessoal, observei uma falha na linha ConnectionString = "DSN", que acabou sendo um levantador que abriu o banco de dados (e o servidor não estava visível na rede).

- Precisamos inicializar todas as variáveis ​​com valores padrão.
- Além disso, a abordagem OOP evita do esquecimento a reatribuição de todos os campos no objeto em alguma nova função centésima.
- O sistema de tipos deve ser seguro - você precisa de controle sobre as dimensões dos objetos atribuídos - proteção contra substituição de memória, estouro aritmético do tipo 65535 + 1, perda de precisão e significância ao converter, excluindo comparação de itens incomparáveis ​​- porque o número 2 não é igual a 2,0 no caso geral.

E mesmo uma divisão típica por 0 pode fornecer um + INF muito definido, em vez de um erro, é necessária uma definição exata do resultado.

Resistência de entrada


- O programa deve funcionar com qualquer dado de entrada e, de preferência, aproximadamente ao mesmo tempo. (VS) Olá para Android, com uma reação ao botão do telefone móvel de 0,2s a 5s; é bom que o Android não esteja dirigindo ABS automotivo.

Por exemplo, um programa deve processar corretamente 1 KB de dados e 1 TB sem esgotar os recursos do sistema.

- É muito desejável ter um tratamento de erros confiável e inequívoco no RAII que não leve a efeitos colaterais (vazamentos de recursos, por exemplo). (VS) Uma coisa muito engraçada é o vazamento de alças, que pode se manifestar após muitos meses.
- Seria bom se proteger do estouro de pilha - desabilitar a recursão.
- O problema de exceder o volume disponível com a memória necessária, crescimento descontrolado do consumo devido à fragmentação durante a alocação / desalocação dinâmica. Se o idioma tiver um tempo de execução dependente de heap, é provável que o problema seja ruim - olá STL e Phobos. (VS) Havia uma história com um antigo C-time da Microsoft, que devolvia inadequadamente a memória ao sistema, devido ao qual o msbackup travava em grandes volumes (durante esse tempo).
- Precisamos de um trabalho bom e seguro com strings - não limitado por recursos. É altamente dependente da implementação (matrizes imutáveis, COW, R / W)
- Exceder o tempo de reação do sistema, independente do programador. Esse é um problema típico do coletor de lixo. Embora eles salvem de alguns erros de programação - outros trazem - mal diagnosticados.
- Em uma certa classe de tarefas, você pode ficar sem memória dinâmica ou selecionando-a uma vez na inicialização.
- Para controlar a saída além dos limites da matriz, e é perfeitamente aceitável escrever um aviso de tempo de execução e ignorá-lo. Muitas vezes, esses são erros não críticos.
- Tenha proteção contra acessos a uma seção de memória que não foi inicializada pelo programa, incluindo a região nula e o espaço de endereço de outra pessoa.
- Intérpretes, JIT - camadas extras reduzem a confiabilidade, há problemas com a coleta de lixo (um subsistema muito complexo - ele cometerá erros) e com tempo de resposta garantido. Nós o excluímos, mas, em princípio, existe o Java Micro Edition (onde tanto é cortado do Java que apenas eu permaneço, houve um artigo interessante de dernasherbrezon (desculpe, tiro) e o .NET Micro Framework com C #.

No entanto, por consideração, essas opções desapareceram:

  • O .NET Micro acabou sendo um intérprete comum (riscado pela velocidade);
  • O Java Micro é adequado apenas para aplicativos incorporados, pois é muito castrado pela API, e você precisará mudar para pelo menos o SE Embedded para desenvolvimento, que já foi fechado ou Java normal, que é monstruoso e imprevisível em resposta.
    No entanto, ainda existem opções e, embora isso não pareça um espaço em branco para uma base viável, ele pode ser comparado com outros idiomas, mesmo desatualizados ou com certas desvantagens.


- Resistência ao trabalho multithread - proteção de dados privados de um fluxo e mecanismos para troca garantida entre fluxos. Um programa com 200 threads pode não funcionar como em dois.
- A programação de contratos e os testes de unidade incorporados também ajudam a dormir em paz.

Resistência a danos ao programa ou dados - falha na mídia, hackers


- O programa deve estar totalmente carregado na memória - sem carregar os módulos, principalmente remotamente.
- Limpar a memória após o lançamento (e não apenas a alocação)
- Monitoramento de estouro de pilha, áreas variáveis, especialmente cadeias.
- Reinicie após uma falha.

A propósito, a abordagem em que o tempo de execução tem seu próprio registro em log, e não apenas mostra que a raposa do norte e o stackrace estão muito impressionados.

Tabela de idiomas e conformidade


À primeira vista, para análise, adotamos PLs seguros especialmente projetados:

  1. Oberon ativo
  2. Ada
  3. BetterC (subconjunto dlang)
  4. IEC 61131-3 ST
  5. Safe-c

E passar por eles em termos dos critérios acima.

Mas este já é o volume do artigo de continuação, se o karma permitir.

Com os fatores mencionados acima destacados na tabela, bem, talvez algo mais sensato seja recolhido nos comentários.

Quanto a outras linguagens interessantes - C ++, Crystal, Go, Delphi, Nim, Red, Rust, Zig (adicione a gosto), então deixarei para aqueles que desejam preencher a tabela de correspondência.

Isenções de responsabilidade:

  • Em princípio, se um programa, digamos em Python, consome 30 MB e os requisitos de reação são segundos, e o microcomputador possui 600 MB de memória livre e 600 MHz por cento, por que não? Somente um programa desse tipo será confiável com alguma probabilidade (embora 96%), não mais.
  • Além disso, o idioma deve tentar ser conveniente para o programador - caso contrário, ninguém o usará. Tais artigos "Eu criei a linguagem de programação ideal para que fosse conveniente escrever" também não são incomuns em Habré, mas isso é sobre outra coisa.

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


All Articles