# Memory Leaks

### **📋 Índice**

1. Fundamentos de Memória e Alocação
2. O que são Memory Leaks
3. Mecanismos de Criação
4. Tipos de Memory Leaks
5. Impacto e Consequências
6. Técnicas de Detecção
7. Ferramentas de Análise
8. Exploração de Memory Leaks
9. Prevenção e Boas Práticas
10. Checklists de Segurança

***

### 🔍 **Fundamentos de Memória e Alocação**

#### **Gerenciamento de Memória em C/C++**

```mermaid
graph TD
    subgraph "Tipos de Alocação"
        A[Alocação Estática] --> A1[Variáveis Globais]
        A --> A2[Variáveis Static]
        A --> A3[Compile-time]
        
        B[Alocação Automática] --> B1[Stack]
        B --> B2[Variáveis Locais]
        B --> B3[Parâmetros de Função]
        
        C[Alocação Dinâmica] --> C1[Heap]
        C --> C2[malloc/calloc/realloc]
        C --> C3[new/delete]
    end
    
    subgraph "Memory Leak"
        C1 --> D[Memória alocada]
        D --> E[Ponteiro perdido]
        E --> F[Memória não liberada]
        F --> G[Vazamento]
    end
    
    style A fill:#99cc99
    style B fill:#99ccff
    style C fill:#ffcc99
    style G fill:#ff6666
```

#### **Funções de Alocação Dinâmica**

```python
#!/usr/bin/env python3
# allocation_functions.py - Funções de alocação

class AllocationFunctions:
    """Análise das funções de alocação de memória"""
    
    @staticmethod
    def malloc_family():
        """Família malloc"""
        print("📦 Família malloc")
        print("=" * 60)
        
        functions = {
            "malloc(size)": "Aloca 'size' bytes, conteúdo não inicializado",
            "calloc(count, size)": "Aloca 'count * size' bytes, inicializa com zero",
            "realloc(ptr, size)": "Redimensiona bloco alocado anteriormente",
            "free(ptr)": "Libera memória alocada"
        }
        
        for func, desc in functions.items():
            print(f"   • {func}: {desc}")
        
        print("\n⚠️ Responsabilidade do programador:")
        print("   • Todo malloc deve ter um free correspondente")
        print("   • Todo calloc deve ter um free correspondente")
        print("   • realloc pode retornar novo ponteiro")
    
    @staticmethod
    def new_delete_family():
        """Família new/delete (C++)"""
        print("\n📦 Família new/delete (C++)")
        print("=" * 60)
        
        functions = {
            "new": "Aloca e constrói objeto",
            "delete": "Destrói e desaloca objeto",
            "new[]": "Aloca array de objetos",
            "delete[]": "Desaloca array de objetos",
            "placement new": "Constrói objeto em memória pré-alocada"
        }
        
        for func, desc in functions.items():
            print(f"   • {func}: {desc}")
        
        print("\n⚠️ Regras importantes:")
        print("   • new deve ser pareado com delete")
        print("   • new[] deve ser pareado com delete[]")
        print("   • Misturar new com free é undefined behavior")
    
    @staticmethod
    def allocation_tracking():
        """Rastreamento de alocações"""
        print("\n📊 Rastreamento de Alocações")
        print("=" * 60)
        
        print("""
Cada alocação deve ser rastreada:
  • Endereço de início
  • Tamanho
  • Localização (arquivo/linha)
  • Tempo de alocação

Exemplo de tracking manual:
  typedef struct {
      void *ptr;
      size_t size;
      const char *file;
      int line;
  } allocation_record;
  
  allocation_record allocations[MAX_ALLOCATIONS];
  
  void *tracked_malloc(size_t size, const char *file, int line) {
      void *ptr = malloc(size);
      if (ptr) {
          record_allocation(ptr, size, file, line);
      }
      return ptr;
  }
""")

# Executar
AllocationFunctions.malloc_family()
AllocationFunctions.new_delete_family()
AllocationFunctions.allocation_tracking()
```

***

### 💧 **O que são Memory Leaks**

#### **Definição**

**Memory leak** (vazamento de memória) ocorre quando um programa aloca memória dinamicamente, mas não a libera após o uso, mesmo quando não há mais referências a ela. Isso resulta em consumo crescente de memória ao longo do tempo, podendo levar à degradação de performance, crashes ou DoS (Denial of Service).

#### **Visualização do Problema**

```mermaid
sequenceDiagram
    participant P as Programa
    participant H as Heap

    Note over P,H: 1. Alocação inicial
    P->>H: malloc(100)
    H-->>P: ptr = 0x1000
    
    Note over P,H: 2. Uso normal
    P->>H: escreve em 0x1000
    
    Note over P,H: 3. Perda do ponteiro
    P->>P: ptr = 0x2000 (novo)
    Note over P: Ponteiro original perdido!
    
    Note over P,H: 4. Vazamento
    Note over H: Memória em 0x1000 nunca liberada
    H->>H: Memória inacessível
    
    Note over P,H: 5. Alocações repetidas
    loop cada operação
        P->>H: malloc(100)
        H-->>P: novo ponteiro
        P->>P: perde ponteiro antigo
    end
    
    Note over H: Memória cresce infinitamente
```

#### **Exemplo Clássico**

```c
// memory_leak_example.c - Exemplos de memory leaks

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 1. Leak básico: perder o ponteiro
void basic_leak() {
    char *ptr = (char *)malloc(100);
    // Usar ptr...
    // 🔴 Esqueceu de free(ptr)
    // Quando função retorna, ptr é perdido - MEMORY LEAK!
}

// 2. Leak por reatribuição
void reassignment_leak() {
    char *ptr = (char *)malloc(100);
    // 🔴 Nova alocação sem liberar anterior
    ptr = (char *)malloc(200);  // Memória original vazou!
    free(ptr);  // Apenas a segunda alocação é liberada
}

// 3. Leak em estrutura de dados
struct node {
    int data;
    struct node *next;
};

void linked_list_leak() {
    struct node *head = (struct node *)malloc(sizeof(struct node));
    head->data = 1;
    head->next = (struct node *)malloc(sizeof(struct node));
    head->next->data = 2;
    head->next->next = NULL;
    
    // 🔴 Libera apenas o head, o next vaza!
    free(head);
}

// 4. Leak em caminho de erro
void error_path_leak() {
    char *buffer = (char *)malloc(1024);
    char *data = (char *)malloc(512);
    
    if (!buffer || !data) {
        // 🔴 Se uma alocação falha, a outra vaza
        return;
    }
    
    // Uso normal...
    free(buffer);
    free(data);
}

// 5. Leak em loop
void loop_leak() {
    for (int i = 0; i < 1000000; i++) {
        char *ptr = (char *)malloc(1024);
        // 🔴 Esqueceu de free dentro do loop
        // Memória acumula a cada iteração!
    }
}

// 6. Leak por retorno antecipado
int early_return_leak(int condition) {
    char *buffer = (char *)malloc(1024);
    
    if (condition) {
        // 🔴 Retorno antecipado sem liberar buffer
        return -1;
    }
    
    free(buffer);
    return 0;
}
```

***

### ⚙️ **Mecanismos de Criação**

#### **Causas Comuns de Memory Leaks**

```python
#!/usr/bin/env python3
# leak_causes.py - Causas de memory leaks

class LeakCauses:
    """Análise das causas de memory leaks"""
    
    @staticmethod
    def lost_pointer():
        """Ponteiro perdido"""
        print("🔴 Lost Pointer")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr = malloc(100);
  ptr = malloc(200);  // Ponteiro original perdido
  // Memória original (100 bytes) vazou

Correto:
  char *ptr = malloc(100);
  // usar ptr...
  free(ptr);
  ptr = malloc(200);
  // usar novo ptr...
  free(ptr);
""")
    
    @staticmethod
    def missing_free():
        """Free ausente"""
        print("\n🔴 Missing Free")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr = malloc(100);
  // usar ptr...
  // 🔴 Esqueceu de free(ptr)

Correto:
  char *ptr = malloc(100);
  // usar ptr...
  free(ptr);
  ptr = NULL;
""")
    
    @staticmethod
    def exception_path():
        """Caminho de exceção não tratado"""
        print("\n🔴 Exception Path")
        print("=" * 60)
        
        print("""
Código vulnerável:
  char *ptr = malloc(100);
  if (error_condition) {
      return -1;  // 🔴 Retorno sem free
  }
  free(ptr);

Correto (C com goto):
  char *ptr = malloc(100);
  if (error_condition) {
      goto cleanup;
  }
  free(ptr);
  return 0;
  
cleanup:
  free(ptr);
  return -1;
""")
    
    @staticmethod
    def circular_reference():
        """Referência circular (C++)"""
        print("\n🔴 Circular Reference (C++)")
        print("=" * 60)
        
        print("""
Código vulnerável:
  class Node {
      std::shared_ptr<Node> next;
  };
  
  auto a = std::make_shared<Node>();
  auto b = std::make_shared<Node>();
  a->next = b;
  b->next = a;  // 🔴 Referência circular!
  // a e b nunca serão destruídos

Correto (C++):
  class Node {
      std::weak_ptr<Node> next;  // Usar weak_ptr
  };
""")
    
    @staticmethod
    def container_leak():
        """Container sem liberação"""
        print("\n🔴 Container Leak")
        print("=" * 60)
        
        print("""
Código vulnerável:
  void add_to_list(Node **head, int value) {
      Node *new_node = malloc(sizeof(Node));
      new_node->data = value;
      new_node->next = *head;
      *head = new_node;
      // 🔴 Se a lista nunca for liberada, tudo vaza
  }

Correto:
  void free_list(Node *head) {
      while (head) {
          Node *temp = head;
          head = head->next;
          free(temp);
      }
  }
""")

# Executar
LeakCauses.lost_pointer()
LeakCauses.missing_free()
LeakCauses.exception_path()
LeakCauses.circular_reference()
LeakCauses.container_leak()
```

#### **Exemplo Complexo: Biblioteca com Leak**

```c
// library_leak.c - Biblioteca com memory leak

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Estrutura de configuração
typedef struct {
    char *name;
    char *value;
    int flags;
} config_entry;

typedef struct {
    config_entry **entries;
    int count;
    int capacity;
} config_manager;

// Inicializar gerenciador
config_manager* config_init() {
    config_manager *mgr = (config_manager *)malloc(sizeof(config_manager));
    if (!mgr) return NULL;
    
    mgr->capacity = 10;
    mgr->count = 0;
    mgr->entries = (config_entry **)calloc(mgr->capacity, sizeof(config_entry *));
    
    if (!mgr->entries) {
        free(mgr);
        return NULL;
    }
    
    return mgr;
}

// Adicionar entrada
int config_add(config_manager *mgr, const char *name, const char *value) {
    if (!mgr || !name || !value) return -1;
    
    if (mgr->count >= mgr->capacity) {
        size_t new_capacity = mgr->capacity * 2;
        config_entry **new_entries = (config_entry **)realloc(mgr->entries, 
                                        new_capacity * sizeof(config_entry *));
        if (!new_entries) return -1;
        
        mgr->entries = new_entries;
        mgr->capacity = new_capacity;
    }
    
    config_entry *entry = (config_entry *)malloc(sizeof(config_entry));
    if (!entry) return -1;
    
    entry->name = strdup(name);
    entry->value = strdup(value);
    entry->flags = 0;
    
    if (!entry->name || !entry->value) {
        free(entry->name);
        free(entry->value);
        free(entry);
        return -1;
    }
    
    mgr->entries[mgr->count++] = entry;
    return 0;
}

// 🔴 Função de cleanup incompleta - vaza memória!
void config_cleanup_incomplete(config_manager *mgr) {
    if (!mgr) return;
    
    // Libera apenas as entradas, mas não os nomes/valores!
    for (int i = 0; i < mgr->count; i++) {
        free(mgr->entries[i]);  // 🔴 name e value vazam!
    }
    free(mgr->entries);
    free(mgr);
}

// ✅ Função de cleanup correta
void config_cleanup_correct(config_manager *mgr) {
    if (!mgr) return;
    
    for (int i = 0; i < mgr->count; i++) {
        config_entry *entry = mgr->entries[i];
        if (entry) {
            free(entry->name);
            free(entry->value);
            free(entry);
        }
    }
    free(mgr->entries);
    free(mgr);
}

int main() {
    config_manager *mgr = config_init();
    
    config_add(mgr, "server", "localhost");
    config_add(mgr, "port", "8080");
    config_add(mgr, "database", "users.db");
    
    // Usar configurações...
    
    // 🔴 Limpeza incorreta - memory leak!
    config_cleanup_incomplete(mgr);
    
    // ✅ Correto:
    // config_cleanup_correct(mgr);
    
    return 0;
}
```

***

### 📊 **Tipos de Memory Leaks**

#### **Classificação de Leaks**

```python
#!/usr/bin/env python3
# leak_types.py - Tipos de memory leaks

class LeakTypes:
    """Classificação de memory leaks"""
    
    @staticmethod
    def classification():
        """Classificação de leaks"""
        print("📊 Classificação de Memory Leaks")
        print("=" * 60)
        
        types = {
            "1. Leak Direto": {
                "descricao": "Ponteiro perdido sem free",
                "exemplo": "ptr = malloc(100); ptr = NULL;",
                "severidade": "Alta",
                "detecção": "Fácil (Valgrind)"
            },
            "2. Leak Indireto": {
                "descricao": "Estrutura de dados não liberada",
                "exemplo": "Lista encadeada perdida",
                "severidade": "Média",
                "detecção": "Média"
            },
            "3. Leak por Ciclo": {
                "descricao": "Referências circulares (C++)",
                "exemplo": "shared_ptr cíclicos",
                "severidade": "Média",
                "detecção": "Difícil"
            },
            "4. Leak Oculto": {
                "descricao": "Alocações em bibliotecas",
                "exemplo": "dlopen sem dlclose",
                "severidade": "Variável",
                "detecção": "Difícil"
            },
            "5. Leak Discreto": {
                "descricao": "Pequenas alocações frequentes",
                "exemplo": "Leak em loop",
                "severidade": "Alta (acumulativo)",
                "detecção": "Média"
            }
        }
        
        for name, info in types.items():
            print(f"\n📁 {name}")
            for key, value in info.items():
                print(f"   {key}: {value}")
    
    @staticmethod
    def leak_patterns():
        """Padrões comuns de leaks"""
        print("\n🎯 Padrões Comuns de Leaks")
        print("=" * 60)
        
        patterns = {
            "Memory Leak em API": {
                "descricao": "Função aloca, mas documentação não menciona responsabilidade",
                "exemplo": "char *result = get_data(); // Quem libera?"
            },
            "Leak em C++ Exceptions": {
                "descricao": "Exceção lançada antes do delete",
                "exemplo": "try { ptr = new int; throw exception(); delete ptr; }"
            },
            "Leak em Realocação": {
                "descricao": "realloc falha e ponteiro original é perdido",
                "exemplo": "ptr = realloc(ptr, new_size); // Se falhar, ptr original perdido"
            },
            "Leak em Fork": {
                "descricao": "Memória alocada antes do fork nunca é liberada no filho",
                "exemplo": "ptr = malloc(100); fork(); // Memória duplicada no filho"
            }
        }
        
        for name, info in patterns.items():
            print(f"\n🔴 {name}")
            print(f"   {info['descricao']}")
            print(f"   Exemplo: {info['exemplo']}")

# Executar
LeakTypes.classification()
LeakTypes.leak_patterns()
```

***

### 💥 **Impacto e Consequências**

#### **Consequências de Memory Leaks**

```mermaid
graph TD
    A[Memory Leak] --> B[Consumo crescente de memória]
    
    B --> C[Slow Degradation]
    B --> D[Crash por OOM]
    B --> E[DoS Attack]
    
    C --> C1[Performance degradada]
    C --> C2[Tempo de resposta aumenta]
    
    D --> D1[Programa termina]
    D --> D2[Serviço indisponível]
    
    E --> E1[Servidor inalcançável]
    E --> E2[Negação de serviço]
    
    A --> F[Security Implications]
    F --> F1[Informação sensível em memória]
    F --> F2[Exploração de Use-After-Free]
    
    style A fill:#ffcc99
    style D fill:#ff6666
    style E fill:#ff3333
```

#### **Matriz de Impacto**

```yaml
Impacto de Memory Leaks:

  🔴 Denial of Service (DoS):
    - Servidor esgota memória
    - Processo é morto pelo OOM Killer
    - Serviço fica indisponível

  🔴 Degradação de Performance:
    - Uso de swap (thrashing)
    - Garbage collection frequente (Java/Go)
    - Latência aumenta com o tempo

  🟠 Vazamento de Informações:
    - Dados sensíveis permanecem na memória
    - Outros processos podem ler (em certos cenários)
    - Páginas não liberadas podem conter segredos

  🟡 Exploração de UAF:
    - Memória liberada parcialmente
    - Dangling pointers podem ser reutilizados
    - Corrupção de memória controlada

  🟢 Instabilidade:
    - Crashes aleatórios
    - Comportamento imprevisível
    - Corrupção de dados
```

***

### 🔍 **Técnicas de Detecção**

#### **Métodos de Detecção**

```python
#!/usr/bin/env python3
# leak_detection.py - Técnicas de detecção

class LeakDetection:
    """Métodos para detectar memory leaks"""
    
    @staticmethod
    def static_analysis():
        """Análise estática"""
        print("📝 Análise Estática")
        print("=" * 60)
        
        print("""
Ferramentas:
  • Clang Static Analyzer: scan-build
  • GCC -fanalyzer (desde GCC 10)
  • Cppcheck
  • Coverity
  • PVS-Studio

Exemplo:
  $ scan-build gcc -c program.c
  $ cppcheck --enable=leak --inconclusive program.c

Limitações:
  • Falsos positivos
  • Não detecta leaks em runtime
  • Depende de análise de fluxo
""")
    
    @staticmethod
    def dynamic_analysis():
        """Análise dinâmica"""
        print("\n⚡ Análise Dinâmica")
        print("=" * 60)
        
        print("""
Ferramentas:
  • Valgrind (Memcheck)
  • AddressSanitizer (ASAN)
  • LeakSanitizer (LSAN)
  • Dr. Memory
  • Intel Inspector

Exemplo:
  $ valgrind --leak-check=full ./program
  $ gcc -fsanitize=address -g program.c
  $ ./program

Vantagens:
  • Detecta leaks reais em runtime
  • Stack trace da alocação
  • Informações detalhadas
""")
    
    @staticmethod
    def instrumentation():
        """Instrumentação manual"""
        print("\n🔧 Instrumentação Manual")
        print("=" * 60)
        
        print("""
Técnicas:
  • Sobrescrever malloc/free
  • Registrar alocações
  • Contadores de referência

Exemplo:
  #define malloc(size) debug_malloc(size, __FILE__, __LINE__)
  #define free(ptr) debug_free(ptr, __FILE__, __LINE__)
  
  void *debug_malloc(size_t size, const char *file, int line) {
      void *ptr = malloc(size);
      fprintf(stderr, "ALLOC %p %zu %s:%d\n", ptr, size, file, line);
      return ptr;
  }
  
  void debug_free(void *ptr, const char *file, int line) {
      fprintf(stderr, "FREE %p %s:%d\n", ptr, file, line);
      free(ptr);
  }
""")

# Executar
LeakDetection.static_analysis()
LeakDetection.dynamic_analysis()
LeakDetection.instrumentation()
```

#### **Script de Detecção com Valgrind**

```bash
#!/bin/bash
# valgrind_leak_detection.sh - Detecção de leaks com Valgrind

# 1. Detecção básica
echo "[*] Detecção básica de leaks"
valgrind --leak-check=full ./program

# 2. Com stack trace detalhado
echo "\n[*] Com stack trace detalhado"
valgrind --leak-check=full --track-origins=yes ./program

# 3. Mostrar reachable leaks
echo "\n[*] Mostrar leaks reachable"
valgrind --leak-check=full --show-reachable=yes ./program

# 4. Salvar saída para análise
echo "\n[*] Salvando saída"
valgrind --leak-check=full --log-file=valgrind_output.txt ./program

# 5. Suprimir leaks conhecidos
echo "\n[*] Suprimindo leaks conhecidos"
valgrind --leak-check=full --suppressions=suppress.txt ./program

# 6. Para servidores (longa duração)
echo "\n[*] Monitoramento de servidor"
valgrind --leak-check=full --error-limit=no ./server

# 7. Com child processes
echo "\n[*] Rastreando processos filhos"
valgrind --leak-check=full --trace-children=yes ./program
```

#### **Script de Detecção com ASAN**

```bash
#!/bin/bash
# asan_leak_detection.sh - Detecção com AddressSanitizer

# 1. Compilar com ASAN
echo "[*] Compilando com ASAN"
gcc -fsanitize=address -g -O0 -o program program.c

# 2. Executar com detecção de leaks
echo "\n[*] Executando com detecção de leaks"
ASAN_OPTIONS=detect_leaks=1 ./program

# 3. Com stack trace detalhado
echo "\n[*] Stack trace detalhado"
ASAN_OPTIONS=detect_leaks=1:verbosity=1 ./program

# 4. Salvar relatório
echo "\n[*] Salvando relatório"
ASAN_OPTIONS=detect_leaks=1:log_path=asan.log ./program

# 5. Suprimir leaks
echo "\n[*] Suprimindo leaks"
ASAN_OPTIONS=detect_leaks=1:suppressions=suppress.txt ./program

# 6. Para C++
echo "\n[*] Compilação C++"
g++ -fsanitize=address -g -O0 -o program program.cpp
```

***

### 🛠️ **Ferramentas de Análise**

#### **Valgrind - Guia Prático**

```c
// valgrind_demo.c - Programa para testar Valgrind

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void leak_example() {
    char *ptr = (char *)malloc(100);
    strcpy(ptr, "Leaked memory");
    // 🔴 free(ptr) ausente
}

void invalid_read_example() {
    char *ptr = (char *)malloc(100);
    char c = ptr[100];  // 🔴 Leitura fora dos limites
    free(ptr);
}

void invalid_write_example() {
    char *ptr = (char *)malloc(100);
    ptr[100] = 'A';  // 🔴 Escrita fora dos limites
    free(ptr);
}

void uninitialized_example() {
    char *ptr = (char *)malloc(100);
    if (ptr[0] == 'X') {  // 🔴 Uso de valor não inicializado
        printf("Found X\n");
    }
    free(ptr);
}

int main() {
    leak_example();
    invalid_read_example();
    invalid_write_example();
    uninitialized_example();
    return 0;
}
```

```bash
#!/bin/bash
# valgrind_analysis.sh - Análise com Valgrind

# Compilar com debug symbols
gcc -g -O0 -o valgrind_demo valgrind_demo.c

# Executar Valgrind
valgrind --leak-check=full \
         --show-leak-kinds=all \
         --track-origins=yes \
         --verbose \
         --log-file=valgrind_output.txt \
         ./valgrind_demo

# Analisar resultados
echo "\n=== Leaks Summary ==="
grep "definitely lost" valgrind_output.txt
grep "indirectly lost" valgrind_output.txt
grep "possibly lost" valgrind_output.txt

echo "\n=== Invalid Reads ==="
grep "Invalid read" valgrind_output.txt

echo "\n=== Invalid Writes ==="
grep "Invalid write" valgrind_output.txt

echo "\n=== Uninitialized Values ==="
grep "Uninitialised" valgrind_output.txt
```

#### **Script de Instrumentação**

```c
// debug_malloc.c - Instrumentação de malloc/free

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ALLOCATIONS 10000

typedef struct {
    void *ptr;
    size_t size;
    const char *file;
    int line;
    int freed;
} allocation_record;

static allocation_record allocations[MAX_ALLOCATIONS];
static int allocation_count = 0;

void* debug_malloc(size_t size, const char *file, int line) {
    void *ptr = malloc(size);
    
    if (ptr && allocation_count < MAX_ALLOCATIONS) {
        allocations[allocation_count].ptr = ptr;
        allocations[allocation_count].size = size;
        allocations[allocation_count].file = file;
        allocations[allocation_count].line = line;
        allocations[allocation_count].freed = 0;
        allocation_count++;
        
        fprintf(stderr, "ALLOC: %p (%zu bytes) at %s:%d\n", 
                ptr, size, file, line);
    }
    
    return ptr;
}

void debug_free(void *ptr, const char *file, int line) {
    for (int i = 0; i < allocation_count; i++) {
        if (allocations[i].ptr == ptr && !allocations[i].freed) {
            allocations[i].freed = 1;
            fprintf(stderr, "FREE: %p at %s:%d\n", ptr, file, line);
            break;
        }
    }
    
    free(ptr);
}

void print_leak_report() {
    int leaks = 0;
    size_t total_leaked = 0;
    
    fprintf(stderr, "\n=== LEAK REPORT ===\n");
    
    for (int i = 0; i < allocation_count; i++) {
        if (!allocations[i].freed) {
            leaks++;
            total_leaked += allocations[i].size;
            fprintf(stderr, "LEAK: %p (%zu bytes) allocated at %s:%d\n",
                    allocations[i].ptr, allocations[i].size,
                    allocations[i].file, allocations[i].line);
        }
    }
    
    fprintf(stderr, "\nTotal leaks: %d, Total bytes: %zu\n", 
            leaks, total_leaked);
}

#define malloc(size) debug_malloc(size, __FILE__, __LINE__)
#define free(ptr) debug_free(ptr, __FILE__, __LINE__)

// Programa de teste
int main() {
    char *p1 = (char *)malloc(100);
    char *p2 = (char *)malloc(200);
    
    free(p1);
    // p2 não é liberado - leak!
    
    print_leak_report();
    
    return 0;
}
```

***

### 🛡️ **Prevenção e Boas Práticas**

#### **Técnicas de Prevenção**

```c
// prevention_techniques.c - Técnicas de prevenção

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

// 1. RAII em C com cleanup attribute
__attribute__((cleanup(cleanup_string)))
char *create_string() {
    char *str = malloc(100);
    return str;
}

void cleanup_string(char **str) {
    if (*str) {
        free(*str);
        *str = NULL;
    }
}

// 2. Gerenciamento com goto
int safe_function() {
    char *buf1 = NULL;
    char *buf2 = NULL;
    int ret = -1;
    
    buf1 = malloc(1024);
    if (!buf1) goto cleanup;
    
    buf2 = malloc(512);
    if (!buf2) goto cleanup;
    
    // Operações...
    ret = 0;
    
cleanup:
    free(buf1);
    free(buf2);
    return ret;
}

// 3. Pool de memória
typedef struct {
    void *pool;
    size_t pool_size;
    size_t used;
} memory_pool;

memory_pool* pool_create(size_t size) {
    memory_pool *pool = malloc(sizeof(memory_pool));
    if (!pool) return NULL;
    
    pool->pool = malloc(size);
    if (!pool->pool) {
        free(pool);
        return NULL;
    }
    
    pool->pool_size = size;
    pool->used = 0;
    return pool;
}

void* pool_alloc(memory_pool *pool, size_t size) {
    if (pool->used + size > pool->pool_size) {
        return NULL;
    }
    
    void *ptr = (char *)pool->pool + pool->used;
    pool->used += size;
    return ptr;
}

void pool_destroy(memory_pool *pool) {
    if (pool) {
        free(pool->pool);
        free(pool);
    }
}

// 4. Smart pointers em C (simplificado)
typedef struct {
    void *ptr;
    int *ref_count;
} shared_ptr;

shared_ptr shared_ptr_create(void *ptr) {
    shared_ptr sp;
    sp.ptr = ptr;
    sp.ref_count = malloc(sizeof(int));
    *sp.ref_count = 1;
    return sp;
}

void shared_ptr_copy(shared_ptr *dest, shared_ptr *src) {
    *dest = *src;
    (*dest.ref_count)++;
}

void shared_ptr_destroy(shared_ptr *sp) {
    if (sp->ref_count) {
        (*sp.ref_count)--;
        if (*sp.ref_count == 0) {
            free(sp->ptr);
            free(sp->ref_count);
        }
    }
}
```

#### **Boas Práticas**

```yaml
Boas Práticas para Prevenir Memory Leaks:

  ✅ RAII (Resource Acquisition Is Initialization):
    - Alocar recursos em construtores
    - Liberar em destrutores
    - Automático em C++

  ✅ Smart Pointers (C++):
    - unique_ptr para propriedade única
    - shared_ptr para propriedade compartilhada
    - weak_ptr para evitar ciclos

  ✅ Cleanup Functions (GCC):
    - __attribute__((cleanup))
    - Liberação automática ao sair do escopo

  ✅ Pool de Memória:
    - Alocar em bloco único
    - Liberar tudo de uma vez
    - Reduz fragmentação

  ✅ Validação de Alocações:
    - Sempre verificar retorno de malloc
    - Tratar erros adequadamente
    - Não ignorar falhas

  ✅ Ferramentas Automáticas:
    - Valgrind em testes
    - ASAN em desenvolvimento
    - Análise estática contínua
```

***

### 📋 **Checklists de Segurança**

#### **Checklist para Desenvolvedores**

* [ ] Todo malloc/calloc tem free correspondente
* [ ] Todo new tem delete correspondente
* [ ] Verificar alocações em caminhos de erro
* [ ] Liberar recursos em ordem reversa da alocação
* [ ] Usar smart pointers em C++
* [ ] Implementar RAII para recursos
* [ ] Testar com Valgrind/ASAN
* [ ] Revisar alocações em loops

#### **Checklist para Revisão de Código**

* [ ] Verificar funções que retornam ponteiros alocados
* [ ] Documentar responsabilidade de liberação
* [ ] Verificar alocações em estruturas de dados
* [ ] Analisar vazamentos em bibliotecas
* [ ] Verificar inicialização de ponteiros
* [ ] Confirmar liberação em todos os caminhos

***

### 📊 **Conclusão**

```yaml
Memory Leaks:

  🔴 Principais Causas:
    - Ponteiros perdidos
    - Free ausente
    - Caminhos de erro
    - Referências circulares (C++)
    - Alocações em loops

  🛡️ Mitigações Essenciais:
    - RAII
    - Smart pointers (C++)
    - Valgrind/ASAN
    - Pool de memória
    - Análise estática

  🎯 Prioridade:
    - CRÍTICA: Leaks em servidores
    - ALTA: Leaks em loops
    - MÉDIA: Leaks em programas curtos
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/tecnicas/linguagens-de-programacao/low-level/memory-leaks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
