Project 7: Bounds-Checking Array Library
A bounds-checked dynamic array type for C that prevents buffer overflows, includes length tracking, and provides safe accessor functions.
Quick Reference
| Attribute | Value |
|---|---|
| Primary Language | C |
| Alternative Languages | C++ (has std::vector), Rust (has slice bounds) |
| Difficulty | Level 2: Intermediate |
| Time Estimate | 1-2 weeks |
| Knowledge Area | Secure Coding / Memory Safety |
| Tooling | AddressSanitizer, Valgrind |
| Prerequisites | Project 1 (safe strings), dynamic memory |
What You Will Build
A bounds-checked dynamic array type for C that prevents buffer overflows, includes length tracking, and provides safe accessor functions.
Why It Matters
This project builds core skills that appear repeatedly in real-world systems and tooling.
Core Challenges
- Storing length with data → maps to struct design, “fat pointers”
- Bounds checking overhead → maps to performance vs safety tradeoffs
- API design → maps to making safe defaults easy
- Memory management → maps to preventing leaks, ownership
Key Concepts
- Fat Pointers: “The Rust Programming Language” Ch. 4
- Defensive Programming: “Code Complete” Ch. 8
- API Design: “C Interfaces and Implementations” Introduction
Real-World Outcome
$ ./test_safe_array
Creating array...
✓ array_new(10, sizeof(int)) created with capacity 10
Testing bounds checking...
✓ array_get(arr, 5) returns element at index 5
✓ array_get(arr, 15) returns NULL (out of bounds!)
✓ array_set(arr, 100, &val) returns false (out of bounds!)
Testing dynamic growth...
✓ array_push grows array automatically
✓ Capacity doubled: 10 -> 20 -> 40
Testing iteration...
✓ array_foreach provides safe iteration
Testing security...
✓ Cannot access beyond length, even within capacity
✓ Integer overflow in size calculation prevented
Memory test with Valgrind:
No memory leaks detected
No invalid reads/writes
Implementation Guide
- Reproduce the simplest happy-path scenario.
- Build the smallest working version of the core feature.
- Add input validation and error handling.
- Add instrumentation/logging to confirm behavior.
- Refactor into clean modules with tests.
Milestones
- Milestone 1: Minimal working program that runs end-to-end.
- Milestone 2: Correct outputs for typical inputs.
- Milestone 3: Robust handling of edge cases.
- Milestone 4: Clean structure and documented usage.
Validation Checklist
- Output matches the real-world outcome example
- Handles invalid inputs safely
- Provides clear errors and exit codes
- Repeatable results across runs
References
- Main guide:
LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md - “C Interfaces and Implementations” by David R. Hanson