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

  1. Reproduce the simplest happy-path scenario.
  2. Build the smallest working version of the core feature.
  3. Add input validation and error handling.
  4. Add instrumentation/logging to confirm behavior.
  5. 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