-
Notifications
You must be signed in to change notification settings - Fork 2
Bug search and fix patterns
Padrões usados para descobrir defeitos em código.
- Reprodução do cenário em que o erro ocorre.
- Depuração via debugger.
- Log
- Código sonda
- Isolamento de trechos suspeitos.
- Regressão para versões antigas, onde o erro não ocorria.
Um código fazia uma requisição HTTP e parou de funcionar. Alguma coisa de alguma forma afetou o componente de fazer requisições HTTP. Crio o menor código possível com uma requisição HTTP e o coloco no ponto mais inicial da execução da aplicação. Se a requisição funciona, vou colocando ela em pontos mais tardios da execução da aplicação, no momento que ele não funciona, significa que o defeito está em um ponto anterior. Sempre colocando o código no meio dos métodos, então na metade da metade, e assim por diante, se aprofundando nos submétodos até chegar no defeito. Descobri que era um código que descarregava a DLL de socket.
procedure TesteIdHTTP;
var
lRequest :TStringStream;
lResponse : TStringStream;
AIdHTTP: TIdHTTP;
begin
AIdHTTP := TIdHTTP.Create(nil);
lRequest := TStringStream.Create('');
lResponse := TStringStream.Create('');
try
AIdHTTP.Request.CustomHeaders.Clear;
AIdHTTP.Request.CustomHeaders.Add('Authorization:Basic UEc6Q2JCYkYybjRGbzlD');
AIdHTTP.Post('http://172.21.4.13:8080/uas/oauth/token?grant_type=password&username=FULANO&password=abc123', lRequest, lResponse);
finally
lRequest.Free();
lResponse.Free();
AIdHTTP.Free;
end;
end;As vezes pode ocorrer de um objeto "A" ser destruído, mas ainda ser mantido em algum outro ponto do sistema, um ponteiro "pA" para esse objeto que não existe mais. Pode ocorrer do endereço de memória do valor desse ponteiro ser usado por algum outro objeto "B", e se for executada alguma operação no ponteiro "pA", esse valor desse endereço pode acabar sendo alterado, corrompendo alguma propriedade do objeto "B", o que pode gerar um erro instantaneamente ou após algumas operações serem feitas com "B" e tentarem acessar essas propriedades corrompidas.
Ao se deparar com esse cenário o programador focará instintivamente no objeto "B" e nas operações feitas com ele, pois é nele que ocorre o erro, mas não encontrará nenhuma evidência que justifique o erro, pois não há nada de errado com "B". No máximo ele encontrará que até determinado ponto alguma propriedade de "B" tinha um valor, mas misteriosamente após algum evento, ela possui outro valor, na maioria das vezes inválido.
Para descobrir o que gera essa alteração das propriedades pode-se usar data breakpoints, que são breakpoints que monitoram um endereço de memória específico, que quando alterado, são disparados, mostrando a callstack do que está gerando essa alteração. Esses breakpoints só podem ser criados em tempo de execução, quando sabe-se qual o endereço de memória que a propriedade ocupará. Usa-se um breakpoint normal para parar a execução em algum ponto que aloque o endereço de memória, vê-se o endereço da propriedade (no Delphi Ctrl+F7 e por exemplo: Pointer(aObjeto.Nome)) e cria-se o data breakpoint apontando para esse entereço.
Um procedimento apresenta lentidão e não se quer usar um profiler. Códigos suspeitos de causar a lentidão são comentados e se verifica se o procedimento ficou sem a lentidão. Se ficou rápido, um a um os códigos vão sendo descomentados, até ficar lento novamente. O último código descomentado é o causador do problema. Se há submétodos, reinicia-se o processo dentro do método.
É uma espécie de código sonda util em memory leaks. É uma espécie de exclusão de código suspeito também. Um memory leak acontece após um código. Adiciono um comando que interrompe o método no meio, se ocorreu o memory leak, ele está antes da interrupção, se não está depois. Vai se refinando a posição da interrupção metade a metade, até encontrar o método problemático. Se ele tem submétodos, aprofunda-se neste, repetindo-se a operação.
- Acidentais - Fáceis de resolver. Resolvidos por manutenção.
- Problema de modelagem - Difíceis, mas são os mais recompensadores de se resolver. Suas soluções amadurecem o código. Resolvidos por evolução.