5.1.18 · D5C Programming
Question bank — Common memory errors — null dereference, buffer overflow, use-after-free, double free, memory leak
This bank leans on the same vocabulary you built earlier: Pointers in C, malloc and free, Stack vs Heap Memory, Undefined Behaviour, and Strings in C and the null terminator. If a term below feels unfamiliar, that link is where it lives.
First, two counting ideas we will lean on
Before the trap questions, let me nail down two tiny pieces of vocabulary that the answers use, so no letter appears un-earned.
True or false — justify
free(p) sets p to NULL.
False.
free receives a copy of the address (pass-by-value from Pointers in C); your variable p is untouched and now dangles at the old address.Calling free(NULL) is a bug that crashes.
False. The C standard guarantees
free(NULL) does nothing — this is exactly why nulling after free is a safe universal habit.A memory leak is undefined behaviour.
False. A leak is well-defined and legal; it just wastes memory. Contrast with use-after-free and double free, which are true Undefined Behaviour.
Every malloc must be matched by exactly one free before the program exits.
True for correctness/leak-freedom. By the conservation law (allocations equal frees) with each block freed once; the OS reclaims everything at exit, but long-running processes must free themselves.
A dangling pointer is one that equals NULL.
False. A dangling pointer holds a once-valid address to freed/expired memory. A
NULL pointer is the opposite problem — it points nowhere valid on purpose.Stack arrays can also overflow their bounds.
True. A buffer overflow is any out-of-bounds access; on the stack it can clobber saved return addresses (see Buffer Overflow Exploits), not just heap blocks.
char buf[8] can safely hold the 7-character string "welcome".
True. With bytes of buffer and visible characters, , so the string plus its
\0 fits exactly with no room to spare.Reading (not writing) through a freed pointer is harmless.
False. A read use-after-free is still Undefined Behaviour; the allocator may have reused the block, so you read a stranger's live data or metadata.
If a program appears to work, its memory usage was correct.
False. Undefined Behaviour is allowed to look correct today and corrupt data tomorrow — "it ran fine" proves nothing.
Spot the error
int *p = malloc(sizeof *p); *p = 5; free(p); free(p);
Double free. The second
free(p) corrupts the allocator's free-list metadata; fix by setting p = NULL; after the first free. (Note sizeof *p is portable — never hard-code a byte count like 4, since sizeof(int) is not 4 everywhere.)char s[5]; strcpy(s, "hello");
Buffer overflow.
"hello" is 6 bytes (5 chars + \0) but s holds 5; the \0 is written one byte past the end.int *p = malloc(sizeof *p); *p = 9; (no NULL check).
Potential null dereference. If
malloc failed it returned NULL, and *p = 9 writes to address 0 → trap. Guard with if (!p).p = malloc(100); p = malloc(200); free(p);
Leak of the first block. Overwriting
p discarded the only handle to the 100-byte block; only the 200-byte block gets freed.for (int i = 0; i <= n; i++) a[i] = 0; for int a[n].
Off-by-one overflow. Valid indices are ;
i == n writes one element past the array. Use i < n.free(p); printf("%d", *p);
Use-after-free. The block is no longer owned after
free; reading *p is Undefined Behaviour. Null p right after freeing.char *p = malloc(10); ... return; // never freed in a loop.
Memory leak. Each iteration allocates without freeing, so (allocations outrun frees) and heap grows unbounded — fatal in a server.
int a[5]; a[5] = 0;
Buffer overflow (off-by-one). Index 5 is out of the valid range ; even a single write past the end is Undefined Behaviour.
Why questions
Why does nulling a pointer after free kill both use-after-free and double free?
A later
*p becomes a detectable null deref instead of silent corruption, and free(NULL) is a guaranteed no-op, so a repeated free harmlessly does nothing.Why can't C bounds-check arrays automatically like Python?
A C array has no stored length — a pointer is just a raw address, so the runtime has no size to compare against; that's the price of zero supervision.
Why is a leak often more dangerous in a server than a crash?
A crash is loud and immediate; a slow leak silently grows memory over days until the OOM-killer strikes, making it hard to diagnose and long-lived.
Why does free(p) leave p dangling instead of clearing it?
free gets a copy of the address value; it returns the block to the allocator but cannot reach back and modify your variable.Why is buffer overflow the classic security exploit?
Writing past a stack buffer can overwrite the saved return address, letting an attacker redirect execution (see Buffer Overflow Exploits).
Why does malloc returning NULL cause a crash rather than garbage?
The OS leaves page 0 unmapped, so the CPU traps on any access to address 0 — a clean segfault instead of silent corruption.
Why is "the OS will clean it up" a bad excuse for not freeing?
True only at process exit; a long-running program never reaches exit, so its leaked memory accumulates the whole time it runs.
Why does copying 12 bytes into char buf[8] overflow by exactly 4?
Here the string length is ("hello world"), so it needs bytes; the buffer is , and bytes land past the buffer's end.
Edge cases
Is free(NULL) safe?
Yes — the standard defines it as a no-op, which is why the null-after-free habit is unconditionally safe.
What happens if you malloc(0)?
Implementation-defined: it may return
NULL or a unique non-null pointer you may not dereference; either way you must still free it if non-null.Is dereferencing a pointer that is one past the end of an array legal?
No — forming the one-past-end pointer is legal for comparison, but dereferencing it is Undefined Behaviour.
If malloc fails and returns NULL, does the earlier successful memory leak?
No — the failed call allocated nothing; only blocks you obtained and then lost the handle to are leaked.
Does a buffer that is exactly full (, string bytes equal buffer size) overflow?
No — that's the tight legal case: characters plus the
\0 fit precisely, with zero spare bytes.After free(p); p = NULL;, is if (p) *p = 5; safe?
Yes — the guard sees
p == NULL (false) and skips the write, so the null-after-free habit turns a landmine into a no-op.Is a leaked block still Undefined Behaviour to access if you kept a copy of the pointer?
No — if you still hold a valid pointer it isn't leaked or freed; it's just live memory you forgot to free. Leak means the last handle was lost.
Recall One-line summary of every trap
free doesn't touch your variable; arrays don't know their size ( must hold); free(NULL) is safe; leaks are and legal-but-lethal; and "it worked" never proves memory correctness. Tools like Valgrind and AddressSanitizer catch what your eyes miss.