Depuração de código C++: 8 técnicas que vão poupar seus nervos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Depuração de código C++: como parar de ter medo de segmentation fault e amar o GDB



Você já passou três horas procurando um bug que no final era um break esquecido em um switch ou um ; extra depois de um if? Se sim — bem-vindo ao clube. A depuração de C++ é uma arte que beira o masoquismo. Mas, como qualquer arte, pode ser dominada.



Neste artigo, vamos abordar não apenas "como executar o GDB", mas técnicas reais que transformam a depuração de um jogo de adivinhação em um trabalho de detetive digno de Sherlock Holmes. Falaremos sobre sanitizers modernos, depuração reversiva e até mesmo como capturar um bug que só aparece "na sexta-feira à tarde".



1. Clássico do gênero: GDB e LLDB



Vamos começar pelo fundamento. O GNU Debugger (GDB) e seu concorrente LLDB são os canivetes suíços do depurador. Mas a maioria os usa com apenas 10% de suas capacidades. Vamos corrigir isso.



Pontos de parada com condições



Você coloca um ponto de parada em um loop de 10.000 iterações e aperta continue 9.999 vezes? Pare com isso. Use breakpoints condicionais:



(gdb) break main.cpp:42 if i == 5000


Isso vai economizar horas de vida. No LLDB, a sintaxe é semelhante:



(lldb) breakpoint set --file main.cpp --line 42 --condition 'i == 5000'


Watchpoints — capturando a mudança de uma variável



Imagine: você tem uma variável que muda em algum lugar desconhecido. Coloque um watchpoint:



(gdb) watch my_variable(gdb) rwatch my_variable   # dispara na leitura(gdb) awatch my_variable   # dispara tanto na leitura quanto na escrita


Agora o programa vai parar exatamente no momento em que alguém tocar na sua variável. Mágico, não é?



2. Reverse Debugging: viagem no tempo



O pior pesadelo de um programador: o programa travou, mas você não sabe como ele chegou a esse estado. A depuração reversiva (reverse debugging) permite "rebobinar" a execução.



No GDB, você precisa do suporte a record:



(gdb) record(gdb) continue... o programa travou ...(gdb) reverse-step   # volta um passo(gdb) reverse-continue # continua no sentido inverso


Em ferramentas comerciais (como UndoDB ou rr da Mozilla), isso funciona ainda melhor. O rr (Record and Replay) é uma ferramenta gratuita que grava a execução do programa e depois permite reproduzi-la várias vezes:



$ rr record ./my_program$ rr replay(gdb) continue... encontrou o local da falha ...(gdb) reverse-step


Dica: use o rr para encontrar condições de corrida (data races) — ele reproduz deterministicamente cada execução.



3. Sanitizers: vacina contra undefined behavior



O C++ moderno (a partir do Clang e GCC 4.8+) possui ferramentas integradas que nossos pais nem sonhavam. O AddressSanitizer (ASan), o UndefinedBehaviorSanitizer (UBSan) e o ThreadSanitizer (TSan) são itens obrigatórios.



Exemplo: capturando vazamento de memória



// compile com: g++ -fsanitize=address -g main.cpp -o main#include <iostream>

void leak() { int* p = new int(42); // esqueceu o delete}

int main() { leak(); return 0;}


Ao executar, vemos:



==12345==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4 byte(s) in 1 object(s) allocated from: #0 0x7f... in operator new(unsigned long) #1 0x400... in leak() main.cpp:5 #2 0x400... in main main.cpp:10


O ASan mostrará a pilha de chamadas exata, incluindo o número da linha onde a alocação ocorreu. Chega de "a memória está vazando em algum lugar".



UBSan contra comportamento indefinido



// compile com: g++ -fsanitize=undefined -g main.cppint main() {    int x = INT_M                

Blogs

Book Recommendations