How the allocator sees memory: chunks

image.png

Most general-purpose allocators manage the heap as a sequence of chunks. Each chunk is a header (metadata the allocator trusts) plus the user area you get back from malloc. Free chunks also carry links for size‑segregated free lists.

Address grows --->

+---------------------------+-------------------------------------+
|        chunk header       |             user area               |
|  size | flags | (fd,bk)*  |                                     |
+---------------------------+-------------------------------------+
 ^                           ^
 |                           └─ pointer returned by malloc()  (p)
 └─ allocator metadata (not corrupt)
* fd/bk only present/used when the chunk is on a free list.

Adjacent chunks let the allocator coalesce on free:

... [chunk A][chunk B][chunk C] ...
          ^ free(B) merges with neighbors if A/B/C are free-adjacent

Because metadata sits next to user data, overflows from one user area can hit the next chunk’s header.


Initialization errors

Reading fields of a freshly malloc’d object before writing them. Heap memory is uninitialized by malloc and contains stale bytes.

typedef struct { int len; char *buf; } Msg;
Msg *m = malloc(sizeof *m);      // not zeroed
if (!m) return;
printf("%d\\\\n", m->len);          // X UB: reading garbage
alloc --> init fields --> use    //good
alloc --(skip init)--> use      //bad

Not checking malloc return codes

Assuming allocations always succeed and dereferencing NULL on pressure or limits.

char *p = malloc(n);
memcpy(p, src, n);               // (x) crash if p == NULL

Dereferencing null or invalid pointers