Como podemos ter certeza de que os componentes inferiores da programação de computadores, como compiladores, montadores, instruções de máquina, etc., são perfeitos?

58

Como estamos cada vez mais dependentes da computação, incluindo tarefas muito importantes do dia-a-dia, fiquei imaginando como esses componentes vitais são testados.

Mais tecnicamente, como os compiladores e montadores são testados? (Eu suponho que isso se relacione com o problema da parada !!)

    
por Sudip Bhandari 29.12.2015 / 16:38
fonte

8 respostas

105

Você não pode ter certeza, mas você apenas assume que eles são, até descobrir que eles não são. Houve muitos bugs em compiladores e hardware ao longo dos anos.

A maneira como estes são testados, por exemplo, um compilador, é que eles são definidos de forma muito restrita e rígida, cuidadosamente redigidos e testados com um conjunto de testes enorme para verificar a correção. Acrescente a isso a ampla base de usuários de um compilador, e mais bugs serão detectados e reportados. Um aplicativo de agendamento de consultas com o dentista, comparativamente, tem muito menos usuários e menos ainda que são capazes de detectar defeitos.

O SQLite consiste em cerca de 73 mil linhas de código, enquanto o seu conjunto de testes consiste em cerca de 91378 mil linhas de código, mais de 1250 vezes o do próprio SQLite. Espero que compiladores e outras ferramentas principais tenham proporções semelhantes. Atualmente, os processadores são projetados essencialmente com software, usando linguagens de descrição de hardware como Verilog ou VHDL, e aqueles que possuem testes de software também são executados, bem como pinos IO especializados para executar autotestes no ponto de fabricação.

Em última análise, é um jogo de probabilidade, e testes repetidos e abrangentes de cobertura permitem que você reduza a probabilidade de defeitos a um nível aceitavelmente baixo, o mesmo que em outro projeto de software.

    
por 29.12.2015 / 20:07
fonte
46

Em termos leigos:

  1. Você não pode.
  2. Compiladores e intérpretes são testados em unidades como qualquer outro software (profissional).
  3. Um teste bem-sucedido não significa que um programa esteja livre de bugs, apenas significa que nenhum bug foi detectado.
  4. Uma ampla base de usuários usando o compilador durante um longo período de tempo é um bom indicador de que ele tem muito poucos bugs, porque os usuários geralmente testam casos em que os designers não pensaram.
  5. Ser open source também é um bom indicador. "Com olhos suficientes, todos os bugs são superficiais ... Dada uma base suficiente de beta-testers e co-desenvolvedores, quase todos os problemas será caracterizado rapidamente e a correção será óbvia para alguém. ". Um compilador de código fechado pode ter bugs que surgem em momentos muito específicos ou que geram código de máquina inferior ao ótimo e a empresa por trás dele simplesmente não pode divulgar sua existência e dar uma prioridade muito baixa no roteiro do produto. li>

Linha de base:

Eu diria ir para OOP ( O ld, O caneta e P opular). Acabei de inventar esse acrônimo.

    
por 29.12.2015 / 20:01
fonte
24

São tartarugas até o fim.

Nada é certo. Você não tem escolha a não ser estabelecer classificações de confiança.

Você pode pensar nisso como uma pilha: Matemática > Física > Hardware > Firmware > Sistema Operacional > Assembler / Compiler / etc

Em cada nível, você tem testes que você pode realizar para melhorar suas classificações de confiança. Alguns desses testes têm a qualidade de provas formais, alguns deles são baseados em observação, a maioria é uma combinação de ambos.

A parte complicada é desvendar a recursão em alguns desses testes, porque usamos programas para fazer provas e análises observacionais agora, onde ficou muito difícil fazer isso manualmente.

Em última análise, a resposta é que você tenta tudo o que pode imaginar. Análise estática, fuzzing, simulação, execução com entradas ou entradas aleatórias propositadamente selecionadas, executando / mapeando cada caminho de controle, provas formais, etc. Basicamente, seu objetivo no teste deve ser sempre fazer todo o possível para provar que seu produto chip / programa) não funciona como pretendido. Se você fizer um esforço genuíno e ainda falhar, poderá melhorar sua classificação de confiança na exatidão do seu produto.

O teste é, na melhor das hipóteses, um processo de semidecisão, o que significa que, se houver um bug, você eventualmente o encontrará, mas nunca poderá ter certeza de que encontrou todos eles. Mesmo com o software formalmente verificado, você ainda está confiando na física, nas ferramentas usadas para fazer as provas formais, e que a coisa que você provou é necessária e suficiente para o seu programa fazer o que é (freqüentemente subjetivamente) "intencional". Isso não é para mencionar todos os outros componentes que você está usando que não têm provas formais.

    
por 30.12.2015 / 05:55
fonte
17

Esta é uma pergunta "perigosa" para novos desenvolvedores, pois eles começarão a culpar suas ferramentas em vez de seu código (já foi feito, visto que muitos o fizeram). Embora existam erros em compiladores, ambientes de tempo de execução, SO, etc., os desenvolvedores devem ser realistas e lembrar que, até que haja evidências e testes de unidade demonstrando o contrário, o erro está no seu código .

Em mais de 25 anos de programação, principalmente em C, C ++ e Java, descobri:

  • dois bugs devido a um bug do compilador (gcc e SunOS C)
  • cerca de uma vez a cada ano ou dois um bug devido a um problema Java JVM (geralmente relacionado ao consumo de memória / coleta de lixo)
  • cerca de uma vez a cada mês ou dois um bug em uma biblioteca, que freqüentemente é corrigido usando a versão mais recente ou revertendo para a versão anterior da biblioteca

Todos os outros bugs estão diretamente relacionados a um bug ou, mais freqüentemente, à falta de compreensão de como funciona uma biblioteca. Às vezes, o que parece ser um bug é devido a uma incompatibilidade, por exemplo, como a estrutura de classe Java mudou e quebrou algumas bibliotecas AOP.

    
por 30.12.2015 / 20:05
fonte
8

Acho que um ponto interessante aqui é que a grande maioria das licenças de software comercial (e de fato software de código aberto) especifica especificamente que você não pode confiar no software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

Do contrato de licença do Microsoft Word

. Except for the Limited Warranty and to the maximum extent permitted by applicable law, Microsoft and its suppliers provide the Software and support services (if any) AS IS AND WITH ALL FAULTS, and hereby disclaim all other warranties and conditions, whether express, implied or statutory, including, but not limited to, any (if any) implied warranties, duties or conditions of merchantability, of fitness for a particular purpose, of reliability or availability, of accuracy or completeness of responses, of results, of workmanlike effort, of lack of viruses, and of lack of negligence, all with regard to the Software, and the provision of or failure to provide support or other services, information, software, and related content through the Software or otherwise arising out of the use of the Software.

Em essência, esta sentença na licença em quase todos os softwares que você usa especificamente lhe diz que você não pode confiar no software e muito menos no compilador usado.

O software é como uma teoria científica, considera-se que funciona como especificado até que não o faça.

    
por 30.12.2015 / 11:24
fonte
2

Como redatora de compiladores para uma linguagem matemática *, pela minha experiência, posso dizer que, em teoria, você não pode. E alguns dos erros só dão resultados errados como (da minha lista de vergonha) calculando 6/3*2 do 6/(3*2) correto e gerando 1 sem falhar ou dando erros de compilação sem sentido.

Mas IMHO muitos compiladores não têm tantos bugs quanto outros softwares porque:

  • Escrever testes de unidade é fácil. Cada declaração é uma unidade e você pode escrever testes tão simples quanto: test_unit("2+(-2)*(-2+1)*3+1",9);
  • Um programa é uma combinação de instruções e para qualquer programa gerar o resultado correto, cada declaração individual deve fornecer o resultado correto (principalmente). Portanto, é muito improvável que haja erros enquanto o programa fornece o resultado correto.
  • À medida que o tamanho e o número de programas escritos aumentam, a probabilidade de detectar bugs aumenta drasticamente.

Para montadores, instruções de máquina, etc., os itens acima também são válidos; por outro lado, a verificação e a validação no design e na produção de chips têm processos muito mais rigorosos, já que é um grande negócio: Automação de design eletrônico .

Antes de começar a produção, cada processador deve ser testado rigorosamente, pois cada bug custa cerca de dois milhões de dólares: há enormes custos de produção não recorrentes na produção de chips. Assim, as empresas gastam muito dinheiro e escrevem um monte de códigos de simulação para o projeto antes de irem para a produção, embora isso não dê uma garantia de 100% - por exemplo: o bug do Pentium FDIV.

Em suma, é pouco provável que haja erros graves em compiladores, códigos de máquina, etc.

Minha humilde linguagem matemática *

    
por 30.12.2015 / 10:39
fonte
0

Impecável? Eles não são. Instalei recentemente algumas "atualizações", e foram meses (e várias seções de código reprogramadas) mais tarde, antes que meu site ASP.NET estivesse funcionando corretamente novamente, devido a mudanças inexplicáveis na forma como várias coisas básicas funcionaram ou falharam.

No entanto, eles são testados e usados por muitas pessoas muito inteligentes e voltadas para detalhes, que tendem a perceber e reportar e consertar a maioria das coisas. O Stack Exchange é um ótimo exemplo (e melhora em como) todas as pessoas que usam essas ferramentas ajudam a testar e analisar como essas ferramentas incrivelmente complexas e de baixo nível funcionam, pelo menos até o uso prático.

Mas sem falhas, não. Embora você também possa ver pessoas no Stack Exchange obtendo informações impressionantes sobre detalhes de desempenho e conformidade e peculiaridades de padrões, sempre há falhas e imperfeições, especialmente quando pessoas diferentes têm opiniões diferentes sobre o que é uma falha.

    
por 30.12.2015 / 07:03
fonte
-1

Para mostrar que os sistemas subjacentes são perfeitos, você também

a) Precisa provar que eles são perfeitos

  1. Prova matemática
  2. Apenas realisticamente possível para programas triviais

b) Faça um teste exaustivo

  1. Apenas possível para programas triviais e alguns programas simples
  2. Assim que um elemento de temporização entra no teste, não é possível fazer uma teste exaustivo como o tempo pode ser dividido indefinidamente.
  3. Além dos programas triviais, as possíveis opções de execução explodem exponencialmente.

No teste de software, o teste exaustivo é usado apenas em testes unitários de algumas funções simples.

Exemplo: Você quer testar uma entrada de 8 caracteres utf-8 para algum campo, você faz a escolha de cortar a entrada em 8 vezes o comprimento máximo 6 de utf-8 em bytes, o que dá 8 * 6 = 48 bytes para realmente ter uma quantidade finita de possibilidades.

Agora você pode pensar que só precisa testar os 1.112.064 pontos de código válidos de cada um dos 8 caracteres, ie. 1,112,064 ^ 8 (digamos 10 ^ 48) testes (o que já é improvável ser possível), mas você realmente tem que testar cada valor de cada um dos 48 bytes ou 256 ^ 48, que é em torno de 10 ^ 120, que é a mesma complexidade que < href="https://en.wikipedia.org/wiki/Shannon_number"> xadrez em comparação com o número total de átomos no universo de aproximadamente 10 ^ 80.

Em vez disso, você pode usar, em ordem crescente de esforço, e cada teste deve cobrir todas as anteriores:

a) teste uma boa e uma amostra ruim.

b) cobertura de código, ou seja. Tente testar cada linha de código, que é relativamente simples para a maioria dos códigos. Agora você pode se perguntar qual o último 1% do código que você não pode testar está lá ... bugs, código morto, exceções de hardware, etc.

c) cobertura do caminho, todos os resultados de todos os ramos em todas as combinações são testados. Agora você sabe por que o departamento de teste o detesta quando suas funções contêm mais de 10 condições. Você também se pergunta por que os últimos 1% não podem ser testados ... alguns ramos dependem dos ramos anteriores.

d) teste de dados, teste um número de amostra com valor de borda, valores problemáticos comuns e números mágicos, zero, -1, 1, min +/- 1, max +/- 1, 42, valores de rnd. Se isso não lhe der cobertura de caminho, você sabe que não captou todos os valores em sua análise.

Se você já fizer isso, você deve estar pronto para o exame de fundação do ISTQB.

    
por 31.12.2015 / 15:30
fonte