Session 03: Memory Operations — Full Contents¶
This directory holds the complete version of session 03: reference solutions, full explanations, and the reference output of every command the exercises ask for.
Use it after the live session for a full view of the solutions and the reasoning behind them.
The corresponding directory used during the session, with skeletons and task descriptions, is 03-memory-ops-live/.
Learning objectives¶
By the end of this session you should be able to:
- Copy data through a static global buffer, a local buffer on the stack, a heap buffer (
malloc/free) and an anonymous mapping (mmap/munmap), and explain what each one costs and when it is the right choice. - Free every heap allocation on every code path, including early returns and error paths.
- Build a growable in-memory data structure using
mallocandreallocwith a chunked growth strategy. - Use
realloccorrectly, including what happens to your data when it fails. - Shrink a dynamic array safely when its usage drops, without invalidating live data.
- Obtain a buffer sized at run time from the kernel with
mmap, and say what that buys overmalloc. - Measure what
mallocasks of the kernel, and change it withmalloptandGLIBC_TUNABLES. - Use Valgrind to prove that a program leaks nothing.
Prerequisites and required tools¶
- Session 01 and 02 concepts: the software stack, and system calls.
- Comfort with C pointers,
structs, and file I/O. - A Linux environment with
gcc,make,valgrindandstraceinstalled.
Contents¶
| Task | Type | Objective |
|---|---|---|
demo-copy-file |
Demo | One file-copy program, four ways of obtaining the buffer: global, local, heap, mapped. |
01-xor-encrypt |
Core | A fixed-size problem: static buffers only, and why no malloc is needed. |
02-products |
Core | A static array of structs, with each name malloc'd to a length known only at run time. |
03-in-memory-db |
Core | A growable heap array, and the realloc idiom. |
04-reverse-lines |
Core | One buffer as large as the input, once: mmap instead of malloc. |
bonus-in-mem-database |
Bonus | Deletion, shrinking, and the hysteresis rule. |
bonus-malloc-tuning |
Bonus | malloc as a policy: five times faster with two settings, and the bug that shows up when it is. |
The demo's four variants share one FURTHER.md and one INSTRUCTOR.md, at demo-copy-file/, since the point of the demo is the comparison between them.
Each task directory contains:
README.md— the tutorial: goal, background, how to build and run, and what the results mean.FURTHER.md— optional extensions and discussion points, with answers.INSTRUCTOR.md— notes for whoever runs the session.prompt.txt— where there is one, the note the exercise was written from.
The through-line of the session¶
The session is about where a piece of memory comes from, who owns it, and when it is released.
demo-copy-fileasks the same question four ways, changing one line each time. Global: the compiler decides the size, the loader provides the memory, nobody cleans up. Local: the same, per call, on the stack — and the stack is small. Heap: you decide the size at run time and you clean up, on every path. Mapped: the kernel provides the memory directly, which is whatmallocdoes for large blocks anyway, and you clean up, on every path.01-xor-encryptis the baseline case where the question does not arise. Every size is fixed at compile time, so the key and buffers are static, nothing is owned, and nothing can leak — which is exactly what makes the contrast with the next exercise sharp.02-productsintroduces the first real owner. The array of products is still static, but each name's length is decided by the input, so each name ismalloc'd (orstrdup'd) to fit and must be freed — one allocation, one owner, one free, on every path.03-in-memory-dbmakes ownership dynamic. Thereallocidiom exists because a failed reallocation leaves the old block alive — and the obvious one-line version of the call throws it away.04-reverse-linesgoes past the allocator. One block as large as the input, needed once: the case for asking the kernel withmmapand giving it straight back withmunmap.bonus-in-mem-databasemakes ownership symmetric, and introduces hysteresis: grow at one threshold, shrink at another, or thrash.bonus-malloc-tuningopensmallocup. It is a policy on top ofbrkandmmap, with settings; two of them make a program five times faster, and the speed-up exposes a program that only worked because fresh memory happens to be zero.
The recurring practical point is that the happy path proves nothing.
Every bug in this session lives on a path that a casual test never executes, or in a property of the memory that the default configuration happens to provide, which is why Valgrind is a required tool rather than an optional one, and why strace sits next to it.