Phase 0 Projects¶
Two deliverables. Both small, both sharpen the toolchain reflexes this phase is about. Do them in weeks 2-4 of M1 after Day 7 of the first-week reset. Push both to a Git repo (public or private, doesn’t matter); the point is you can show them and re-read your own writeups in six months.
Project 1: utils — A Multi-file Static Library¶
Goal: build a small utility library as a Makefile-driven multi-file C project, with a driver program that exercises it, all compiling clean under the strict flag set.
Structure¶
utils/
├── Makefile
├── include/
│ └── utils.h
├── src/
│ ├── str.c # string helpers
│ ├── vec.c # int vector (dynamic array of int)
│ └── file.c # file I/O helpers
├── tests/
│ └── driver.c # exercises every function, prints PASS/FAIL
└── README.md
Required Functions¶
utils.h declares at minimum:
#ifndef UTILS_H
#define UTILS_H
#include <stddef.h>
#include <stdio.h>
/* str.c */
size_t util_strlen(const char *s);
char *util_strdup(const char *s); // heap-allocated copy; caller frees
int util_streq(const char *a, const char *b);
/* vec.c */
typedef struct { int *data; size_t len; size_t cap; } vec_int;
void vec_init(vec_int *v);
void vec_push(vec_int *v, int x);
void vec_free(vec_int *v);
/* file.c */
char *util_read_file(const char *path, size_t *out_len); // caller frees
#endif
Acceptance Criteria (all must pass)¶
make clean && makeproducesbuild/driverwith zero warnings under-std=c17 -Wall -Wextra -Wpedantic -Werror -Wshadow -Wstrict-prototypes -g -O0 -fsanitize=address,undefined../build/driverprints test results and exits 0 on success.Editing any file in
include/triggers rebuild of the.cfiles that include it (proves-MMD -MPworks).make releaseproduces a-O2 -DNDEBUGbinary with no sanitizers, still zero warnings.compile_commands.jsonis generated (viabear -- make) and committed or gitignored deliberately; clangd works on the project in your editor.README.mddocuments: what the library does, how to build (debug + release), how to run tests, the flag rationale in one paragraph.No use of
strcpy,strcat,sprintf, orgets. Usesnprintf, explicit bounds,strncpywith manual null-termination, or your own helpers.Every function that allocates memory has a matching free path in the driver, and the driver exits ASan-clean (
==0==ERRORnever appears).
Stretch (only if you finish early)¶
Add a
libutils.atarget that produces a real static library archive:ar rcs build/libutils.a $(OBJ), and have the driver link against it (cc build/driver.o -Lbuild -lutils).Add a trivial
util_strjoinandutil_strsplitso you get a taste of the string type you’ll build in Phase 1.
Time Estimate¶
8-12 hours across ~1 week. The functions are tiny; the point is the scaffolding (Makefile, headers, tests) and clean sanitizer output.
Project 2: The Segfault Zoo¶
Goal: reproduce five classic C crashes deliberately, capture the debugger and sanitizer output, and write a paragraph on each explaining what triggered it, what the tools showed, and how you’d prevent it in real code. This teaches you the tool-vs-bug mapping better than any book.
Structure¶
segfault_zoo/
├── Makefile
├── 01_null_deref/
│ ├── crash.c
│ ├── lldb_output.txt
│ ├── asan_output.txt
│ └── NOTES.md
├── 02_use_after_free/
│ ├── crash.c
│ └── ... (same layout)
├── 03_heap_oob_write/
│ ├── ...
├── 04_double_free/
│ ├── ...
├── 05_stack_overflow/ # infinite recursion
│ ├── ...
└── README.md
The Five Bugs (exact list)¶
# |
Bug |
Minimum repro |
Signal / detector |
|---|---|---|---|
1 |
Null pointer dereference |
|
SIGSEGV; ASan reports |
2 |
Use-after-free |
|
ASan reports |
3 |
Heap out-of-bounds write |
|
ASan reports |
4 |
Double free |
|
ASan reports |
5 |
Stack overflow via infinite recursion |
|
SIGSEGV (stack guard page); lldb bt shows thousands of frames |
Acceptance Criteria¶
Each subdirectory builds with
makefrom the top-level Makefile, intobuild/01_null_deref,build/02_use_after_free, etc.Each
crash.ccompiles clean under-Wall -Wextra -Wpedantic -Werror— the bugs are runtime, not compile-time. This is important: it teaches you that a warning-free build is not a bug-free build.Each folder has
lldb_output.txtcapturing abtandframe variablefrom an lldb session on the non-sanitizer build.Each folder has
asan_output.txtcapturing the ASan report from the sanitized build.Each folder has
NOTES.md(~10 lines): what triggers it, what lldb showed, what ASan showed, how you’d prevent it in real code (e.g., pointer nulling after free, bounds-checked wrappers,assertsentinels).Top-level
README.mdsummarizes the five bugs and links to each folder.
Time Estimate¶
6-10 hours. This one is high-signal-per-hour — you learn more per line typed here than almost anywhere else in Phase 0.
What Most People Get Wrong About This Project¶
They skip the writeup, thinking “I got the crash, I understand it.” You don’t, yet. Forcing yourself to write the five-line NOTES.md — in your own words, six months from now readable — is what converts seeing the crash into understanding it. Every senior C engineer has a mental map of bug type → tool that catches it fastest. This project builds yours.
Definition of Done for Phase 0¶
Project 1’s driver exits 0, ASan-clean, with committed
README.md.Project 2 has all five subfolders populated with crash, outputs, and NOTES.
You can create a new C project from scratch in <5 minutes: directory layout, Makefile from your template, first
main.c,bear -- make, clangd working in editor, first commit.You know, from reflex, when to reach for ASan (bad memory), UBSan (bad arithmetic/casts), TSan (races — Phase 4), lldb/gdb (logic bug), or
leaks(macOS quick leak check).
When those are true, close Phase 0. Move to Phase 1.
Return to README.md · Next: ../02_c_language_deep/README.md