Fundamentals 29 min read

Understanding glibc Heap Memory Management: Architecture, Mechanisms, and Exploitation

This article provides a comprehensive overview of glibc's heap memory management, explaining the role of brk and mmap, the organization of arenas, heaps, chunks, bin structures, allocation and deallocation strategies, and how these concepts are applied in security research and exploit development.

Deepin Linux
Deepin Linux
Deepin Linux
Understanding glibc Heap Memory Management: Architecture, Mechanisms, and Exploitation

glibc (GNU C Library) implements an efficient heap memory management system using the brk and mmap system calls, reducing syscall frequency and improving memory utilization. The heap is organized hierarchically into arenas, heaps, and chunks, with each thread typically owning its own arena.

1. Why glibc Heap Management Matters

Memory leaks, fragmentation, and crashes are common problems in long‑running programs; glibc’s allocator acts as the backstage director that controls allocation and release, directly affecting program stability and performance.

2. glibc Heap Basics

2.1 Process Memory Layout

In a 32‑bit process the address space is divided into stack, heap, data, BSS, and code segments. The stack grows downward, while the heap grows upward and is managed by malloc / free . In 64‑bit systems the layout is similar but allows much larger regions.

2.2 Key System Calls: brk and mmap

brk expands or contracts the program’s data segment, providing contiguous memory suitable for small, frequent allocations. mmap creates large, possibly anonymous mappings and can map files directly into the address space, making it ideal for big allocations.

#include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);

glibc’s malloc chooses brk for requests below ~128 KB and mmap for larger ones.

3. Core Mechanisms of glibc Heap Management

3.1 Arena

An arena is a memory region obtained via sbrk (main arena) or mmap (sub‑arenas). The main arena is created at program start and is shared by all threads; sub‑arenas are limited by CPU core count (2 on 32‑bit, 8 on 64‑bit). When a thread calls malloc , it first tries its private arena; if locked, it searches a circular list of arenas, creating a new one if necessary.

struct malloc_state {
  mutex_t mutex;               // arena lock
  int flags;
  mfastbinptr fastbinsY[NFASTBINS];
  mchunkptr top;               // topmost free chunk
  mchunkptr last_remainder;
  mchunkptr bins[NBINS * 2 - 2];
  unsigned int binmap[BINMAPSIZE];
  struct malloc_state *next;   // linked list of arenas
  struct malloc_state *next_free;
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
};

3.2 Heap Types

The main arena’s heap is grown with brk and is a single contiguous region. Sub‑arenas allocate one or more heaps via mmap ; each heap can be extended or released independently. When a sub‑arena’s heap is exhausted, a new mmap‑ed heap is linked to the existing list.

3.3 Chunk Organization

Chunks are the basic allocation units. In 64‑bit glibc a chunk contains:

struct malloc_chunk {
  INTERNAL_SIZE_T prev_size; // size of previous free chunk
  INTERNAL_SIZE_T size;      // size + flags
  struct malloc_chunk *fd;    // next free chunk (if free)
  struct malloc_chunk *bk;    // previous free chunk (if free)
  struct malloc_chunk *fd_nextsize; // for large bins
  struct malloc_chunk *bk_nextsize;
};

Allocation proceeds through fast bins, small bins, large bins, and finally the top chunk. If no suitable free chunk exists, malloc expands the top chunk via brk or creates a new mmap region.

Deallocation marks a chunk free, possibly merges it with adjacent free chunks, and places it into the appropriate bin (fast, unsorted, small, or large) to reduce fragmentation.

4. Allocation and Deallocation Functions

4.1 malloc

Prototype: void *malloc(size_t size); The function searches the thread’s arena bins, applies a “first‑fit / best‑fit” strategy, splits larger chunks when necessary, and falls back to the top chunk or a new mmap region for large requests.

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr = (int *)malloc(10 * sizeof(int));
    if (!arr) return 1;
    for (int i = 0; i < 10; ++i) arr[i] = i + 1;
    for (int i = 0; i < 10; ++i) printf("%d ", arr[i]);
    printf("\n");
    free(arr);
    return 0;
}

4.2 free

Prototype: void free(void *ptr); The function retrieves the chunk header, marks it as free, merges with neighboring free chunks, and inserts it into the appropriate bin. Setting the original pointer to NULL after freeing prevents dangling‑pointer bugs.

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr = (int *)malloc(10 * sizeof(int));
    if (!arr) return 1;
    /* use arr */
    free(arr);
    arr = NULL;
    return 0;
}

5. Case Study: "GlibC Malloc for Exploiters" Project

The open‑source project provides an in‑depth reverse‑engineering of glibc’s allocator, offering practical demonstrations, exploit techniques, and video presentations from security conferences. It helps researchers understand heap‑related vulnerabilities such as use‑after‑free, double free, and heap‑overflow, and guides the development of both offensive exploits and defensive mitigations.

By exposing the inner workings of bins, fast‑bin attacks, and top‑chunk manipulation, the project serves as a valuable resource for CTF participants, penetration testers, and anyone performing memory‑corruption analysis on Linux systems.

Memory ManagementC++mallocglibcfreeheap memory
Deepin Linux
Written by

Deepin Linux

Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.