Ferramentas de Debug em Zig — Depuração e Análise de Erros
O Zig foi projetado com depuração de primeira classe em mente. O compilador inclui verificações de segurança em tempo de execução que detectam bugs comuns como acesso fora de limites, uso de ponteiros inválidos e overflow de inteiros. Combinado com suporte nativo a GDB/LLDB e stack traces detalhados, o Zig oferece uma experiência de debugging superior a C e C++.
Safety Checks Integrados
Em builds de debug (o padrão), o Zig ativa verificações automáticas:
pub fn main() void {
// Detecção de overflow
var x: u8 = 255;
x += 1; // Panic em debug: integer overflow
// Acesso fora de limites
var arr = [_]u8{ 1, 2, 3 };
_ = arr[5]; // Panic em debug: index out of bounds
// Ponteiro nulo
var ptr: ?*u32 = null;
_ = ptr.?; // Panic em debug: attempt to use null value
// Unreachable
unreachable; // Panic em debug: reached unreachable code
}
Modos de Build e Safety
| Modo | Safety Checks | Otimização | Uso |
|---|---|---|---|
| Debug | Todos ativos | Nenhuma | Desenvolvimento |
| ReleaseSafe | Todos ativos | Otimizado | Produção segura |
| ReleaseFast | Desativados | Máxima | Performance máxima |
| ReleaseSmall | Desativados | Tamanho mínimo | Embarcados |
Stack Traces Detalhados
O Zig gera stack traces informativos automaticamente em panics:
fn funcaoA() !void {
try funcaoB();
}
fn funcaoB() !void {
try funcaoC();
}
fn funcaoC() !void {
return error.AlgoErrado;
}
pub fn main() !void {
try funcaoA();
}
// Saída em caso de erro não tratado:
// error: AlgoErrado
// src/main.zig:10:5: funcaoC
// src/main.zig:6:5: funcaoB
// src/main.zig:2:5: funcaoA
// src/main.zig:14:5: main
std.debug para Informações de Runtime
const std = @import("std");
pub fn debugInfo() void {
// Imprimir stack trace atual
std.debug.dumpCurrentStackTrace();
// Informações do return address
const addr = @returnAddress();
std.debug.print("Return address: 0x{x}\n", .{addr});
// Assert com mensagem
std.debug.assert(1 + 1 == 2);
// Print formatado para debug
std.debug.print("Valor: {}, Tipo: {s}\n", .{ 42, @typeName(u32) });
}
GDB com Zig
O Zig gera informações de debug DWARF completas, compatíveis com GDB:
# Compilar em modo debug
zig build
# Iniciar GDB
gdb ./zig-out/bin/minha-app
# Comandos úteis no GDB
(gdb) break main # Breakpoint na main
(gdb) break src/utils.zig:42 # Breakpoint na linha 42
(gdb) run # Executar
(gdb) next # Próxima linha
(gdb) step # Entrar na função
(gdb) print variavel # Imprimir variável
(gdb) print @as(u32, valor) # Print com tipo Zig
(gdb) backtrace # Stack trace
(gdb) info locals # Variáveis locais
(gdb) watch variavel # Watchpoint
(gdb) continue # Continuar execução
Configuração do GDB para Zig
Crie um .gdbinit para melhor experiência:
# .gdbinit
set print pretty on
set pagination off
set confirm off
# Zig-specific
define zig-slice
print {ptr = $arg0.ptr, len = $arg0.len}
end
define zig-optional
if $arg0 == 0
printf "null\n"
else
print *$arg0
end
end
LLDB com Zig
O LLDB também funciona bem com Zig:
# Iniciar LLDB
lldb ./zig-out/bin/minha-app
# Comandos LLDB
(lldb) breakpoint set --file main.zig --line 10
(lldb) run
(lldb) thread step-over # next
(lldb) thread step-in # step
(lldb) frame variable # locals
(lldb) expression variavel # print
(lldb) thread backtrace # backtrace
Debug no VS Code
Configure o VS Code para debug com o ZLS:
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Zig",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/zig-out/bin/minha-app",
"args": [],
"cwd": "${workspaceFolder}",
"preLaunchTask": "zig build",
"sourceLanguages": ["zig"]
},
{
"name": "Debug Testes",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/zig-out/bin/test",
"args": [],
"cwd": "${workspaceFolder}",
"preLaunchTask": "zig build test"
}
]
}
Técnicas de Debug Avançadas
Comptime Debug
// Mensagens de erro em tempo de compilação
fn validarTipo(comptime T: type) void {
const info = @typeInfo(T);
if (info != .Struct) {
@compileError("Esperado struct, recebido " ++ @typeName(T));
}
// Log em comptime
@compileLog("Analisando tipo:", @typeName(T));
@compileLog("Número de campos:", info.Struct.fields.len);
}
Sanitizers
O Zig integra sanitizers do LLVM:
# Address Sanitizer (detecta uso após free, buffer overflow)
zig build -Dsanitize-address
# Undefined Behavior Sanitizer
zig build -Dsanitize-undefined
# Thread Sanitizer (detecta data races)
zig build -Dsanitize-thread
Debug Allocator
Use o GeneralPurposeAllocator com todas as verificações:
var gpa = std.heap.GeneralPurposeAllocator(.{
.safety = true,
.stack_trace_frames = 16, // Stack traces detalhados
.enable_memory_limit = true, // Limite de memória
.requested_memory_limit = 1024 * 1024 * 100, // 100MB
}){};
// No deinit, reportar leaks
defer {
const check = gpa.deinit();
if (check == .leak) {
@panic("Memory leak detectado!");
}
}
Panic Handler Customizado
pub const panic = struct {
pub fn call(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
// Log customizado
const stderr = std.io.getStdErr().writer();
stderr.print("\n=== PANIC ===\n{s}\n", .{msg}) catch {};
if (error_return_trace) |trace| {
std.debug.dumpStackTrace(trace.*);
}
// Gerar core dump ou enviar telemetria
std.posix.abort();
}
}.call;
Ferramentas Externas
Valgrind
# Executar com Valgrind para detecção de memória
valgrind --leak-check=full ./zig-out/bin/minha-app
# Cachegrind para análise de cache
valgrind --tool=cachegrind ./zig-out/bin/minha-app
strace
# Rastrear chamadas de sistema
strace -f ./zig-out/bin/minha-app
# Apenas I/O
strace -e trace=read,write,open,close ./zig-out/bin/minha-app
Boas Práticas
- Desenvolva em modo Debug: As verificações de segurança encontram bugs cedo
- Use ReleaseSafe em produção: Mantém verificações com otimização
- Teste com FailingAllocator: Garanta tratamento de OutOfMemory
- Configure GDB/LLDB no IDE: Debug visual é mais produtivo
- Implemente panic handlers: Para logging e telemetria em produção
Próximos Passos
Explore as ferramentas de profiling para otimização, os frameworks de teste para prevenção de bugs, e os alocadores customizados para diagnóstico de memória. Consulte nossos tutoriais para práticas de debugging.