O Apollo Guidance Computer é um dos conjuntos de código mais estudados da história.
Muitos desenvolvedores já o leram, acadêmicos publicaram trabalhos sobre sua confiabilidade e emuladores o executam instrução a instrução.
No entanto, encontramos um defeito no código de controle dos giroscópios que passou despercebido por cinquenta e sete anos: um bloqueio de recurso que vaza em um caminho de erro e que pode desabilitar silenciosamente a capacidade de realinhamento da plataforma de navegação.
Para chegar a isso usamos ferramentas modernas: um modelo de linguagem comportamental chamado Allium e um assistente de linguagem para ajudar a destilar o código.
Transformamos cerca de 130 mil linhas de assembly do AGC em aproximadamente 12,5 mil linhas de especificações comportamentais derivadas do próprio código, e esse processo indicou diretamente o defeito.
O código-fonte do AGC foi transcrito manualmente a partir de listagens impressas e está disponível publicamente há anos.
Os programas do AGC eram gravados numa memória física chamada core rope, tecida à mão por mulheres que ficaram conhecidas internamente como “Little Old Ladies”.
O programa estava literalmente tecido no hardware, e projetos de emulação confirmaram as transcrições byte a byte contra os dumps originais da memória.
A fiscalização sobre esse software foi profunda, mas concentrou-se em ler o código, emular o comportamento e verificar a transcrição.
Nós abordamos o problema de forma diferente: extraímos especificações comportamentais da sub-subsistema IMU, a unidade de medição inercial que usa giroscópios para indicar a orientação da nave.
As especificações modelam o ciclo de vida de cada recurso compartilhado: quando ele é adquirido, quando precisa ser liberado e em quais caminhos isso deve ocorrer.
Foi essa modelagem de ciclo de vida que revelou uma falha que leitura e emulação tinham deixado passar.
No AGC, o acesso aos giroscópios é protegido por um bloqueio chamado LGYRO.
Quando o computador precisa aplicar pulsos de torque aos giroscópios para corrigir deriva ou alinhar por estrelas, ele adquire LGYRO no início da operação e deve liberá-lo assim que os três eixos forem corrigidos.
Esse bloqueio evita que duas rotinas disputem o hardware dos giroscópios ao mesmo tempo.
Normalmente o bloqueio é adquirido na entrada da rotina e liberado na sua saída, mas existe uma terceira possibilidade que não libera o bloqueio: o evento de “cage”.
O caging é uma medida de emergência que trava mecanicamente os gimbals da IMU para proteger os giroscópios de danos, acionável pela tripulação por meio de um interruptor protegido.
Quando a rotina de torque termina normalmente, ela sai por um caminho que limpa LGYRO; porém, se o IMU for caged durante a operação, o código salta para uma rotina de término geral que não limpa esse bloqueio específico.
Faltam instruções que colocariam zero no registro do bloqueio e o liberariam, e esse passo ausente mantém LGYRO preso.
Com LGYRO preso, qualquer tentativa subsequente de aplicar torque encontra o bloqueio mantido, faz a tarefa entrar em espera por um sinal que nunca chega e fica pendurada.
Alinhamento fino, compensação de deriva e torque manual dos giroscópios deixam de funcionar.
Imagine a situação histórica: enquanto Neil Armstrong e Buzz Aldrin caminhavam na Lua, Michael Collins orbitava sozinho na cápsula.
Em cada passagem atrás da Lua ele ficava sem contato por alguns minutos e rodava o Programa 52, uma rotina de alinhamento por estrelas que mantinha a plataforma de navegação apontada corretamente.
Se a plataforma derivasse, o impulso de encontro poderia apontar na direção errada.
Como o bug poderia se manifestar na prática: Collins completa suas observações de estrela e comanda o torque; ao se mover pela cabine, um cotovelo pode acidentalmente acionar o interruptor de caging.
O código detecta o cage, abandona a operação de torque e sinaliza a falha da rotina de alinhamento como esperado.
Ele então uncages a IMU e volta para tentar um novo alinhamento — mas na segunda tentativa o programa pode simplesmente travar sem aviso.
A interface DSKY aceita comandos, mas as operações de giroscópio não respondem; o comando manual de torque também não funciona; todo o restante do computador continua operando normalmente.
O primeiro incidente pareceu normal e havia um procedimento conhecido de recuperação, então nada no comportamento apontaria para a necessidade de reinicializar o computador.
Estando fora de contato atrás da Lua, com Armstrong e Aldrin dependendo de uma queima correta para o encontro, uma IMU que não pode ser realinhada seria exatamente a situação que Michael Collins descreveu como seu maior temor.
Uma reinicialização completa teria limpado o bloqueio, mas reiniciar iria apagar o estado de memória que muitas vezes era preservado e, além disso, a tripulação já vinha lidando com alarmes durante a descida lunar.
Margaret Hamilton e sua equipe aprovaram os programas finais antes da gravação na memória e introduziram muitos conceitos hoje comuns, como escalonamento por prioridade, multitarefa assíncrona e proteção contra reinicializações.
O escalonamento por prioridade salvou o pouso do Apollo 11 quando alarmes de sobrecarga descartaram tarefas de baixa prioridade conforme projetado.
Muitos dos problemas sérios que surgiram eram erros de especificação em vez de meros erros de codificação, e o defeito que encontramos tem essa mesma natureza estrutural.
A rotina de término geral lidava corretamente com recursos compartilhados que eram de escopo amplo, mas deixou de tratar um bloqueio específico dos giroscópios que só é adquirido por uma peça concreta do código.
O AGC foi escrito de forma defensiva, e a lógica de reinicialização completa também limpava o bloqueio como efeito colateral, de modo que muitos testes que desencadeavam uma reinicialização ocultavam o problema.
Essa defesa escondia a falha, mas não a eliminava: um evento de cage sem reinicialização deixaria os giroscópios bloqueados.
Encontramos o defeito ao especificar o comportamento do subsistema com Allium, modelando recursos como entidades com estados adquiridos, ocupados e liberados.
Ao expressar a obrigação de que, se os giroscópios são marcados como ocupados, algum caminho de execução deve restaurar esse estado, o rastreamento automático mostrou que o caminho de erro não fazia essa limpeza.
Testes verificam o código tal como ele está; uma especificação comportamental pergunta explicitamente para que serve o código e destaca caminhos que os testes não cobrem.
Hoje, linguagens e construções modernas tentam tornar vazamentos de bloqueio estruturalmente impossíveis com mecanismos como defer, try-with-resources, with e sistemas de propriedade, mas padrões de falta de liberação de recursos ainda aparecem em muitos contextos.
O MITRE classifica esse padrão como CWE-772, “Missing Release of Resource after Effective Lifetime”, e considera alta a probabilidade de exploração desse tipo de falha.
Nem todos os recursos têm gerenciamento automático: conexões de banco, locks distribuídos, descritores de arquivo em scripts e infraestruturas temporárias continuam dependentes da limpeza manual do programador.
O código do Apollo carregou essas rotinas adiante em outras missões, e o defeito nunca chegou a ser detectado ou corrigido.
Um bug com cinquenta e sete anos de idade ficou escondido em assembly de voo comprovado; isso nos leva a perguntar o que mais pode estar oculto no seu próprio código.