---
title: "Allocator Invalid Free — Como Resolver em Zig"
url: "https://ziglang.com.br/erros/allocator-invalid-free-como-resolver-em-zig/"
markdown_url: "https://ziglang.com.br/erros/allocator-invalid-free-como-resolver-em-zig.MD"
description: "Entenda o erro de free inválido em Zig, que ocorre ao tentar liberar memória com ponteiro incorreto ou alocador errado. Veja como diagnosticar e corrigir."
date: "2026-02-21"
author: "Zig Brasil"
---

# Allocator Invalid Free — Como Resolver em Zig

Entenda o erro de free inválido em Zig, que ocorre ao tentar liberar memória com ponteiro incorreto ou alocador errado. Veja como diagnosticar e corrigir.


# Allocator Invalid Free — Como Resolver em Zig

## O Que Este Erro Significa

O erro de free inválido ocorre quando o programa tenta liberar memória usando um ponteiro que não foi retornado por uma alocação válida, ou quando usa o alocador errado para liberar a memória. O `GeneralPurposeAllocator` do Zig detecta esses problemas em modo Debug e emite um panic com informações detalhadas.

Mensagens típicas:

```
thread 1 panic: Invalid free
```

```
error(gpa): Allocation does not belong to this allocator
```

```
error(gpa): freeing memory not allocated by this allocator
```

Este erro indica corrupção de memória potencial — liberar um ponteiro inválido pode destruir as estruturas internas do alocador e causar falhas cascata.

## Causas Comuns

### 1. Liberar Ponteiro Modificado

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const buffer = try allocator.alloc(u8, 100);
    const ptr_modificado = buffer[10..]; // Slice no meio do buffer

    // PANIC: ptr_modificado não é o ponteiro original retornado por alloc
    allocator.free(ptr_modificado);
}
```

### 2. Liberar com Alocador Diferente

```zig
const std = @import("std");

pub fn main() !void {
    var gpa1 = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa1.deinit();

    var gpa2 = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa2.deinit();

    const buffer = try gpa1.allocator().alloc(u8, 100);
    // PANIC: alocado por gpa1, tentando liberar por gpa2
    gpa2.allocator().free(buffer);
}
```

### 3. Liberar Ponteiro da Stack

```zig
const std = @import("std");

pub fn main() void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var local: [100]u8 = undefined;
    const slice: []u8 = &local;

    // PANIC: slice aponta para memória da stack, não do heap
    allocator.free(slice);
}
```

### 4. Liberar Literal de String

```zig
const std = @import("std");

pub fn main() void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const texto: []const u8 = "olá mundo";
    // PANIC: string literal está no segmento de dados, não no heap
    allocator.free(@constCast(texto));
}
```

### 5. Liberar com Tamanho Incorreto

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const buffer = try allocator.alloc(u8, 100);

    // Criar slice com tamanho diferente do alocado
    const errado = buffer[0..50]; // Apenas 50 bytes do original de 100
    // Dependendo do alocador, free com tamanho errado é inválido
    allocator.free(errado);
}
```

## Como Corrigir

### Solucao 1: Sempre Liberar o Ponteiro Original

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const buffer = try allocator.alloc(u8, 100);
    defer allocator.free(buffer); // O slice ORIGINAL

    // Trabalhe com sub-slices sem liberar
    const parte = buffer[10..50];
    parte[0] = 42;
    // buffer é liberado pelo defer — correto
}
```

### Solucao 2: Manter Referência ao Alocador Correto

```zig
const std = @import("std");

const Recurso = struct {
    dados: []u8,
    allocator: std.mem.Allocator, // Guarda referência ao alocador

    fn init(allocator: std.mem.Allocator, tamanho: usize) !Recurso {
        return .{
            .dados = try allocator.alloc(u8, tamanho),
            .allocator = allocator,
        };
    }

    fn deinit(self: *Recurso) void {
        self.allocator.free(self.dados); // Usa o alocador correto
    }
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    var recurso = try Recurso.init(gpa.allocator(), 100);
    defer recurso.deinit();
}
```

### Solucao 3: Distinguir Memória Alocada de Estática

```zig
const std = @import("std");

const Texto = struct {
    conteudo: []const u8,
    alocado: bool,
    allocator: ?std.mem.Allocator,

    fn deTextoEstatico(texto: []const u8) Texto {
        return .{
            .conteudo = texto,
            .alocado = false,
            .allocator = null,
        };
    }

    fn deTextoDinamico(allocator: std.mem.Allocator, texto: []const u8) !Texto {
        const copia = try allocator.dupe(u8, texto);
        return .{
            .conteudo = copia,
            .alocado = true,
            .allocator = allocator,
        };
    }

    fn deinit(self: *Texto) void {
        if (self.alocado) {
            if (self.allocator) |alloc| {
                alloc.free(@constCast(self.conteudo));
            }
        }
    }
};
```

### Solucao 4: Usar ArenaAllocator para Evitar Free Individual

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    var arena = std.heap.ArenaAllocator.init(gpa.allocator());
    defer arena.deinit(); // Único free — libera tudo

    const allocator = arena.allocator();

    // Sem necessidade de free individual — sem risco de invalid free
    const a = try allocator.alloc(u8, 100);
    const b = try allocator.alloc(u8, 200);
    _ = a;
    _ = b;
}
```

### Solucao 5: Usar defer Imediatamente

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Padrão: alloc seguido imediatamente de defer free
    const dados = try allocator.alloc(u8, 100);
    defer allocator.free(dados);

    // Use dados livremente — defer garante o free correto
    @memset(dados, 0);
    dados[0] = 42;
}
```

## Diagnóstico

### Habilitar Log Detalhado do GPA

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{
        .verbose_log = true,        // Loga alocações e frees
        .safety = true,             // Verificações extras
    }){};
    defer _ = gpa.deinit();

    // O GPA agora imprime cada alocação e free com endereços
}
```

### Regras de Free Válido

Um `free` é válido somente quando:

1. O ponteiro é exatamente o que foi retornado por `alloc`/`realloc`
2. O alocador usado para `free` é o mesmo que fez o `alloc`
3. O `free` é chamado apenas uma vez para cada `alloc`
4. O slice passado tem o mesmo tamanho que o alocado originalmente

## Erros Relacionados

- [Double free](/erros/erro-double-free/) — Liberar memória duas vezes
- [Use after free](/erros/erro-use-after-free/) — Usar memória após liberação
- [OutOfMemory](/erros/erro-out-of-memory/) — Memória insuficiente
- [Memory leak detected](/erros/erro-allocator-leak-detected/) — Vazamento de memória

## Links Úteis

- [Documentação oficial do Zig — Allocators](https://ziglang.org/documentation/master/#Choosing-an-Allocator)
- [Receitas de gerenciamento de memória](/receitas/)
- [Tutorial sobre alocadores](/tutoriais/)
