$ clang -g -O0 15_invalid_free.c -o bin/15_invalid_free
$ ./bin/15_invalid_free ; echo "exit=$?"
free(): invalid pointer
Aborted (core dumped)
exit=134$ clang -g -O0 15_invalid_free.c -o bin/15_invalid_free
$ ./bin/15_invalid_free ; echo "exit=$?"
free(): invalid pointer
Aborted (core dumped)
exit=134$ gdb -q -batch -ex 'set debuginfod enabled off' -ex run -ex bt \
./bin/15_invalid_free
free(): invalid pointer
Program received signal SIGABRT, Aborted.
...
#6 0x0000000000400497 in main () at 15_invalid_free.c:73
How to read it: bottom-up, frame #6 is YOUR code — main at line 73, the
bad free(). The frames above are glibc's abort path (free -> malloc_printerr
-> abort -> raise), same shape as the double-free (#07). gdb hands you the
exact offending free.$ valgrind -q ./bin/15_invalid_free
==NNNNN== Invalid free() / delete / delete[] / realloc()
==NNNNN== at 0x........: free (vg_replace_malloc.c:...)
==NNNNN== by 0x........: main (15_invalid_free.c:73)
==NNNNN== Address 0x........ is on thread 1's stack
==NNNNN== in frame #1, created by main (15_invalid_free.c:70)
How to read it — valgrind is the clearest of all here:
"Invalid free()" at main (...:73) -> the bad free call.
"Address ... is on thread 1's stack" -> it spells out that you
freed a STACK address, not a heap block. That one line names the bug.$ clang -g -O0 -fsanitize=address 15_invalid_free.c -o bin/15_invalid_free.asan
$ ./bin/15_invalid_free.asan
==NNNNN==ERROR: AddressSanitizer: attempting free on address which was not
malloc()-ed: 0x.... in thread T0
#0 0x... in free
#1 0x... in main .../15_invalid_free.c:73
ASan states it literally: "free on address which was not malloc()-ed".ROOT CAUSE vs CRASH SITE: The crash is inside glibc's free, but the bug is the free() of a pointer that never came from malloc (line 73). Root cause: confusing automatic (stack) storage with heap ownership. Only free() what malloc() gave you.
heap error
2 ------------------------------------------------------------
`p` points at a STACK variable (`&x`), then `free(p)` is called. free() may only be given a pointer returned by malloc/calloc/realloc (or NULL). Passing a stack address corrupts the allocator. Buggy line: `free(p);`.
glibc DETECTS it: "free(): invalid pointer", SIGABRT, exit 134. Deterministic on glibc.
Don't free stack/global/interior pointers. Free exactly the pointers malloc returned. Here: just delete the `free(p);` — `x` is automatic and is reclaimed when main returns.
Make `p` point one past a real heap block: `char*h=malloc(8); free(h+1);`. Now valgrind/ASan say "not 0 bytes inside" / freeing an interior pointer — another flavor of invalid free. ============================================================
#include <stdlib.h>
int main(void) {
int x = 42;
int *p = &x; /* p points at a STACK variable */
free(p); /* <-- THE BUG: free() of a non-heap ptr */
return 0;
}A lab is done when you can say what it showed on your machine — not when you have read it.
It decides which problems come first, which drills open, which labs you see and how the Learn surface is organised. Change it any time from the switch in the top bar, or press Escape to look around first.