Skip to content
UnderDunn Courses

The Heap and Data Lifetime

How Programs WorkLesson 6 of 760 minutesLab included

Where data lives is only half the question

Section titled “Where data lives is only half the question”

Researchers often ask whether data is “on the stack” or “on the heap.” The next question should be: how long is that storage valid? A pointer can retain an address after the object at that address has ceased to exist. The number still looks convincing while the right to use it has vanished.

Three useful C storage categories are:

Storage Typical lifetime
Automatic local storage Until execution leaves its enclosing block or function
Dynamically allocated storage From successful allocation until it is released
Static storage For the lifetime of the process

Scope concerns where a name can be used in source code. Lifetime concerns when the referenced object exists. They often align, but they are not the same concept.

Create lifetime.c:

#include <stdio.h>
#include <stdlib.h>
int main(void) {
int local = 7;
int *dynamic = malloc(sizeof(*dynamic));
if (dynamic == NULL) {
return 1;
}
*dynamic = 42;
printf("local=%d dynamic=%d\n", local, *dynamic);
free(dynamic);
dynamic = NULL;
return 0;
}

Compile and run it:

Terminal window
gcc -Wall -Wextra -O0 -g -o lifetime lifetime.c
./lifetime

malloc requests storage and returns its address, or NULL if the request fails. Dereferencing dynamic with *dynamic accesses the allocated integer. free ends the allocation’s lifetime. Assigning NULL afterward does not repair other copies of the pointer, but it prevents this variable from continuing to advertise the old address as usable.

Knowledge check

Question 1 of 2

When does dynamically allocated storage stop being valid?

  • A memory leak loses the ability or intention to free an allocation that is no longer needed.
  • A use-after-free accesses storage after it has been released.
  • A double-free attempts to release the same live allocation twice without a new allocation in between.

These are not interchangeable “heap bugs.” They represent different broken claims about ownership and lifetime. Later tools will help us observe them; for now, make the claim explicit: who owns this allocation, and at which instruction does that ownership end?

Pause the program before free by temporarily adding getchar(); after printf, then recompile and run it. In another terminal, find its PID and inspect:

Terminal window
pgrep -n lifetime
grep '\[heap\]' "/proc/$(pgrep -n lifetime)/maps"

Press Enter in the first terminal to let it finish. Small allocations may be served from an existing heap mapping; larger allocations can use separate anonymous mappings. An allocator is a runtime manager layered on top of memory supplied by Linux, not the heap itself.

You can now discuss memory bugs in terms of object lifetime and ownership rather than treating every pointer as valid because it contains a nonzero number. The final concept lesson follows programs across the boundary into the kernel.