Pointers & Memory · intermediate · ~20 min

Memory safety — the whole bug class

Name and prevent every common memory-corruption bug class in C.

Overview

Memory safety is the property that a program only ever reads or writes memory that it logically owns and that has been initialised. The C language gives you no automatic check; the defence is a small set of disciplined habits.

Why it matters

About 70% of historically-tracked critical CVEs in C/C++ trace back to memory-safety bugs (Microsoft and Google have both published the figure). The defences are well-known; the discipline of applying them universally is the hard part.

Core concepts

The bug list. Buffer overflow (stack and heap), use-after-free, double-free, null-deref, uninitialised read, integer overflow into allocation, type confusion.

The defence list. Bounded copies (snprintf, strlcpy); validate before deref; free(p); p = NULL;; calloc instead of malloc when zeroing matters; integer-overflow pre-checks; address sanitizer in CI; stack canaries and NX in production.

Pentester mindset. When auditing C, look for each bug in turn: any unbounded copy, any pointer dereferenced without a null check, any malloc whose size came from untrusted multiplication.

Defensive coding habit. Always compile tests with -fsanitize=address,undefined. Always set freed pointers to NULL. Always use the realloc-with-temp pattern.

Syntax notes

/* The defensive 5-line malloc/free */
T *p = malloc(sizeof *p);
if (!p) { /* handle OOM */ return -1; }
/* ... use p ... */
free(p);
p = NULL;

Lesson

'Memory safety' is the umbrella term for a family of bugs that all cost attackers nothing and defenders everything: buffer overflow, use-after-free, double-free, null deref, uninitialised read, integer overflow leading to under- allocation. Modern C development means knowing each by name and the standard defence.

Code examples

/* always init pointers, always free exactly once, always cap copies */
char *p = NULL;
p = malloc(64);
if (!p) { /* OOM */ }
snprintf(p, 64, "%s", input);
free(p);
p = NULL;

Line by line

/* realloc-with-temp — never lose the original on OOM */
void *tmp = realloc(buf, new_size);
if (!tmp) { /* original still valid */ return -1; }
buf = tmp;

Common mistakes

  • Treating each bug as a separate problem. They share defences.

Debugging tips

Run every test under ASan + UBSan. Both produce file:line-precise diagnostics for every memory bug class.

Memory safety

This entire lesson IS the memory safety note. Pair with notes/asan-cheatsheet.md.

Real-world uses

Every defensive C program. Every CVE patch. Every code review.

Practice tasks

  1. Take a buggy C program; identify which memory-safety bug class it has; fix it. 2. Build with ASan; trigger each bug; read the diagnostic. 3. Audit the standard library headers for unbounded calls and forbid them in your linter.

Summary

Bug list + defence list = the curriculum. Compile with sanitizers in CI; live by the discipline in production.

Practice with these exercises