Ler Stack Traces em Zig — Interpretar Rastros de Execução

Ler Stack Traces em Zig — Interpretar Rastros de Execução

Stack traces são a ferramenta principal para diagnosticar crashes e erros em Zig. Aprender a lê-los corretamente acelera drasticamente o debugging. Este guia ensina a interpretar cada parte de um stack trace.

Anatomia de um Stack Trace

Quando um panic ocorre em modo Debug, Zig gera um stack trace como este:

thread 28435 panic: index out of bounds
/home/user/projeto/src/parser.zig:142:25: 0x1064ab3 in parse (parser)
        const token = tokens[pos];
                        ^~~~~~~~~
/home/user/projeto/src/main.zig:58:9: 0x1063f21 in processar (main)
    try parser.parse(dados);
        ^~~~~~~~~~~~~~~~~~~
/home/user/projeto/src/main.zig:23:5: 0x1063c10 in main (main)
    try processar(entrada);
    ^~~~~~~~~~~~~~~~~~~~~~

Lendo de Cima para Baixo

  1. Linha 1: Tipo do panic

    • thread 28435 panic: index out of bounds
    • Qual thread, qual tipo de erro
  2. Linha 2-3: Local exato do erro

    • /home/user/projeto/src/parser.zig:142:25 = arquivo:linha:coluna
    • 0x1064ab3 = endereço de memória da instrução
    • in parse (parser) = nome da função e do módulo
    • A seta ^~~~~~~~~ aponta exatamente para a expressão problemática
  3. Linhas seguintes: Cadeia de chamadas

    • Quem chamou a função onde o erro ocorreu
    • De baixo para cima: main -> processar -> parse

Tipos Comuns de Panic

index out of bounds

panic: index out of bounds

Tentou acessar um índice fora do array/slice. Olhe o tamanho do array e o índice usado.

integer overflow

panic: integer overflow

Operação aritmética excedeu o range do tipo. Verifique os valores e considere tipo maior ou wrapping arithmetic.

reached unreachable code

panic: reached unreachable code

Execução atingiu um unreachable. O switch/if não cobriu todos os casos.

attempt to unwrap null

panic: attempt to cast away optionality on null value

Usou .? em um optional que era null. Use orelse ou if para verificar.

attempt to use null pointer

panic: attempt to use null value

Dereferenciou um ponteiro null. Verifique se o ponteiro é válido antes de usar.

Stack Trace sem Símbolos

Em modo Release, o stack trace pode mostrar apenas endereços:

0x1064ab3 in ??? (???)
0x1063f21 in ??? (???)
0x1063c10 in ??? (???)

Soluções:

# 1. Recompilar em Debug para obter stack trace completo
zig build  # Debug mode padrão

# 2. Usar addr2line para traduzir endereços
addr2line -e zig-out/bin/meu-app 0x1064ab3

# 3. Em ReleaseSafe, stack traces ainda são disponíveis
zig build -Doptimize=ReleaseSafe  # Mantém informações de debug

Stack Trace em Testes

Test [3/5] test "processar dados"... FAIL
/home/user/projeto/src/lib.zig:89:15: 0x20a3b1 in test "processar dados"
    try expect(resultado == 42);
              ^~~~~~~~~~~~~~~~~
error: 'test "processar dados"' failed

Em testes, o stack trace mostra qual asserção falhou e em qual linha. Use std.testing.expectEqual para mensagens mais descritivas.

Stack Trace com Threads

thread 28436 panic: index out of bounds

O número da thread ajuda a identificar qual thread teve o problema. Para debugging multi-thread:

// Identifique threads com prints
fn worker(id: usize) void {
    std.debug.print("Thread {d} iniciando\n", .{id});
    // ...
}

Usando GDB/LLDB com Stack Traces

# GDB
gdb ./zig-out/bin/meu-app
(gdb) run
# Quando crashar:
(gdb) bt          # backtrace completo
(gdb) bt full     # backtrace com variáveis locais
(gdb) frame 2     # ir para frame específico
(gdb) print var   # imprimir variável
(gdb) info locals # ver todas as variáveis locais

# LLDB (macOS)
lldb ./zig-out/bin/meu-app
(lldb) run
(lldb) bt
(lldb) frame select 2
(lldb) p variavel

Capturando Stack Traces Programaticamente

const std = @import("std");

fn registrar_stack_trace() void {
    const trace = @returnAddress();
    std.debug.print("Chamado de: 0x{x}\n", .{trace});
}

// Para debug mais detalhado
fn debug_aqui() void {
    var buf: [4096]u8 = undefined;
    var fba = std.heap.FixedBufferAllocator.init(&buf);
    const allocator = fba.allocator();
    _ = allocator;

    const debug_info = std.debug.getSelfDebugInfo() catch return;
    _ = debug_info;
    // Usar para resolver endereços para nomes de funções
}

Dicas de Leitura Rápida

  1. Olhe a primeira linha — Tipo do panic (index, overflow, null, etc.)
  2. Olhe a segunda linha — Arquivo e linha exatos do erro
  3. Olhe a seta — Aponta para a expressão exata que falhou
  4. Leia de cima para baixo — Do erro até main, para entender o fluxo
  5. Compile em Debug — Sempre debug com modo Debug para máxima informação

Quando o Stack Trace Não Ajuda

Se o stack trace não é suficiente:

// Adicione prints estratégicos antes do crash
std.debug.print("ANTES: pos={d}, tokens.len={d}\n", .{ pos, tokens.len });

// Use breakpoints com GDB
// (gdb) break src/parser.zig:140
// (gdb) run

// Use @breakpoint() no código para parar o debugger
@breakpoint();

Veja Também

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.