Como depurar um programa ao qual você não tem acesso



Foto: Intricate Explorer, Unsplash



Hoje me lembrei de um dos meus "mitos da programação" favoritos, que pode muito bem ser uma lenda urbana, e minha própria versão da "caixa preta" que precisava ser depurada.



A lenda urbana fala sobre vagões radioativos da Ucrânia que causavam bugs no sistema de computador, você pode ler aqui .



Lidamos com as "caixas pretas" e com o que são hoje



Uma caixa preta é um conceito de programação popular que pressupõe que estamos fora de um sistema ou componente sem acesso direto ao código. Isso pode ser causado por vários fatores:



  • Você trabalha com software de terceiros cujos desenvolvedores simplesmente não divulgam o código.
  • Você está interagindo com uma API cuja lógica interna é abstraída.
  • Você não tem as permissões necessárias para acessar o repositório Git.
  • Mesmo um sistema com acesso total pode se tornar uma caixa preta de fato devido à sua complexidade.
  • Um funcionário que possuía todas as chaves e conhecimento irá de repente sair / desaparecer / morrer.
  • O sistema legado consiste em um .dll que "sempre funcionou" no servidor, e não estava conectado a um sistema de controle de versão. Para apenas olhar o código, você precisa descompilar, se possível, é claro.


Todos esses fatores se resumem ao fato de que temos um problema que não podemos consertar instantaneamente e não sabemos qual é o erro. Portanto, precisamos começar a trabalhar.



Nosso próprio problema era uma combinação de todos os itens acima



A lista de fatores listados acima provavelmente não cobre todas as situações, porque é uma lista direta de fatores que influenciaram nossa situação. Tínhamos acabado de demitir um desenvolvedor, um sistema complexo distribuído em vários servidores, com um núcleo .dll que “fazia seu trabalho”, embora ninguém soubesse por quê ou qual.



Chamava serviços de terceiros, praticamente não havia login e os únicos backups que tínhamos eram os storages no sistema de arquivos com esse .dll

e sem nenhum código. Como você pode entender, nada disso pôde ser mantido e eles planejaram reescrever o sistema no devido tempo, mas o erro era urgente e precisava ser eliminado.



Podemos dizer que na maioria das vezes o sistema estava quase totalmente dando conta do trabalho, e poderíamos tolerar soluções parciais para o problema se elas mostrassem consistência. No entanto, aproximadamente cada centésimo conjunto de dados apresentou resultados incorretos e a única coisa que podíamos fazer era depurá-los de fora (agora nos lembramos disso com um sorriso).



Este é um daqueles momentos em que me sinto grato pelo mundo caótico em que cresci, pois a maioria das empresas não enfrentará problemas tão graves, e não indicará um recém-formado para resolvê-los. Tive sorte nesse sentido, e ainda mais sorte, porque tive o apoio de desenvolvedores experientes que me ajudaram em todo o processo. Então essa foi a nossa solução.



Nós reproduzimos o erro (de preferência em vários casos de teste)



Depois de saber qual é o bug real, o problema está quase resolvido, mas pode ser extremamente difícil resolvê-lo se o bug ocorrer de forma irregular. Pense novamente no exemplo do trem - se não fosse possível identificar o padrão, a razão seria quase impossível de encontrar. Porque é isso que procuramos em tal situação - o padrão de quando ocorre um erro.



Em nosso caso, descobrimos que era relativamente simples: sabíamos o tipo de erro e ele ocorria repetidamente, mas tão raramente que demoramos muitas vezes para estreitar o espaço de busca de casos e revelar sua lógica.



Depois de identificar muitos casos de teste que regularmente levam a falhas, você pode começar a depurar a si mesmo. Aqui está um exemplo de outro processo no qual estreitamos a busca pela origem do problema combinando padrões: um dos sistemas travava toda quinta-feira à noite e não havia nada de estranho nos arquivos de log:



  • Sabíamos que nosso sistema não estava dando nenhuma mensagem de erro, mas travou.
  • Comparamos os casos até termos certeza de que o problema ocorreu na quinta-feira e em nenhum outro dia.
  • Verificamos se não há atualizações automáticas programadas para este horário, verificamos todas as tarefas automatizadas em execução no mesmo servidor - nada.
  • Vimos o que o sistema estava fazendo no nível meta e reduzimos a um tempo limite de disco compartilhado, que era acessado a cada duas semanas por uma tarefa de limpeza de disco em execução em um servidor completamente diferente enquanto nosso serviço estava em execução. Ninguém pensou que os dois começaram o lançamento às três horas da manhã.


Crie um ambiente de teste (mesmo se for de produção)



Depois de ter um conjunto de erros, você pode começar a trabalhar na verdadeira causa e solução, o que requer um sistema de teste.



Com isso, quero dizer que você precisa de duas constantes:



  • Os dados usados ​​não devem ser alterados por outros sistemas
  • Possíveis danos devem ser limitados o máximo possível


No nosso caso, não foi possível reproduzir os erros no servidor de teste, isso era óbvio, pois a biblioteca .dll estava em um estado completamente diferente em comparação com o servidor em produção. Reverter para esse antigo estado não funcionou porque quebrou outros elementos que eram tão importantes.



Então, nos reunimos e fizemos a pergunta: “Qual é a pior coisa que poderia acontecer se estragarmos tudo?” E então escrevemos um script de banco de dados que reescreveria todos os resultados em um estado de erro para que os sistemas subsequentes não os processassem.



Era possível, por exemplo, desconectar servidores e tarefas, retirar o próximo passo lógico do processo e assim por diante, mas a possibilidade disso depende da arquitetura de um determinado sistema.



Compare os dados de entrada para encontrar semelhanças e diferenças com conjuntos de dados de trabalho



Embora não possamos saber exatamente o que o código faz no caso de uma "caixa preta", foi possível realizar uma espécie de "engenharia reversa", muitas vezes dando um bom entendimento das causas dos problemas.



Em nosso caso, tivemos o luxo de arquivos JSON razoavelmente bem formatados do sistema anterior do qual nossa entrada dependia. Depois de ter tudo configurado, faltava começar literalmente a comparar alguns arquivos de texto no Notepad ++ até encontrarmos as semelhanças entre os arquivos que causavam os erros e, em seguida, as diferenças entre eles e os arquivos funcionando corretamente.



Tivemos sorte aqui - fomos capazes de descobrir rapidamente que o bug causou uma combinação específica de sinalizadores de cliente e imediatamente conseguimos contorná-los, porque este caso poderia ser "imitado" com sinalizadores semelhantes, mas diferentes. Portanto, como já sabíamos que o sistema seria reescrito (na verdade, não tínhamos escolha), optou-se por contornar esse bug ao invés de descompilar e consertar.



Modificar a entrada para garantir que nosso palpite leve aos resultados esperados (e limite qualquer dano)



Obviamente, é uma má ideia alterar dados ativos em um banco de dados em produção, esperando que tudo funcione sem testes reais, mas não tínhamos outra escolha.



Funcionou muito bem porque o número de casos era baixo e os primeiros testes que executamos manualmente acabaram sendo exatamente o que queríamos.



Então acabamos escrevendo outra tarefa automatizada para corrigir esses problemas antes que eles chegassem ao sistema, e então embarcamos em um projeto de três meses para reescrever este programa do zero, desta vez de forma transparente, com controle de versão e pipelines de construção.



Aqui está uma aventura.



Conclusão: você pode aprender muito sobre o sistema, mesmo se você simplesmente contorná-lo e cutucá-lo com um pedaço de pau



Estou encantado com essa forma de depurar e encontrar erros, adoro quando a programação é combinada com uma descarga de adrenalina.



Se você ainda não assistiu ao vídeo sobre injeção de SQL e engenharia reversa de banco de dados sobre mensagens de erro, recomendo muito assistir . As técnicas usadas neste vídeo são quase idênticas àquelas que podem ser usadas para depuração não maliciosa.






Propaganda



Encomende e trabalhe imediatamente! Criação de VDS de qualquer configuração em um minuto, incluindo servidores para armazenar grandes quantidades de dados de até 4000 GB. Épico :)



Inscreva-se no nosso chat no Telegram .






All Articles