Safe C++
Course objectives
By the end of the course participants will be able to:
- Apply modern C++ language features and idioms that reduce vulnarabilities
- Use static and dynamic analysis tools, sanitizers, and fuzzers to find and fix defects
- Design APIs and modules with clear ownership, lifetime, and concurrency contracts
- Migrate selected components toward safer patterns with minimal disruption
- Perform secure code reviews and write tests that exercise safety boundaries
- Use C++26 features that enhance safety in C++ codebases
Course syllabus
Core Concepts of Safety
- Memory safety vs type safety
- Undefined behavior (UB) taxonomy
- Common exploit primitives (use‑after‑free, buffer overflow, integer overflow)
- Recognize unsafe idioms and map them to real‑world vulnerabilities
Modern C++ Patterns for Safety
- Object lifetimes, aliasing rules, relocation and move semantics, avoiding dangling references, safe container usage
- RAII and deterministic destruction; smart pointers and ownership models
- Value semantics in modern C++ (move semantics, perfect forwarding)
std::optional,std::variant,std::span- Replace raw pointers and manual memory management with safer abstractions
- Design APIs that express ownership
constexprandnoexceptfor correctness- Apply patterns that prevent use‑after‑free and dangling references
Concurrency Safety
- Data races detection - TSan
- Explicit locking -
std::mutexand lock strategies - Atomic operations:
std::atomicand C++11 memory model - Thread‑safe APIs, avoiding UB in concurrent contexts
- Design thread‑safe modules
Undefined Behavior and Defensive Coding
- Common UB sources - signed integer overflow, out‑of‑bounds access, invalid casts
- Defensive checks, contract programming, assertions, and sanitizer‑friendly code
- Detect and eliminate UB
Tooling and Automated Analysis
- Static analyzers (clang‑tidy, Cppcheck)
- Compiler warnings and hardening flags
- Sanitizers (ASan, UBSan, MSan, TSan)
- Address/Undefined/Memory/Thread sanitizers
- Integrating tools into CI
Fuzzing and Dynamic Testing
- Fuzzing fundamentals: concepts, types (dumb vs coverage-guided), and goals
- Coverage-guided fuzzers: libFuzzer and AFL, and their integration
- Writing fuzz harnesses
- Designing inputs, isolating components, and instrumentation
- Corpus management - seed inputs, minimization, and mutation strategies
- Crash triage: analyzing fuzz failures, reproducing bugs, and reporting
- Dynamic testing techniques complementing fuzzing: sanitizers, runtime checks
Secure API and Library Design
- APIs that reduce misuse and make unsafe states unrepresentable
- Contracts
- wide contracts vs. narrow contracts
- Conctracts in C++26
- Explicit ownership transfer
- Error handling strategies
- Safe defaults in C++
- Versioning and ABI considerations
Migration Strategies and Interop
- Incremental hardening of legacy code
- Wrappers and adapters
- Using safer subsets of C++ in hot paths
Code Review and Threat Modeling
- Secure code review checklist
- Threat modeling for memory corruption
- Post‑mortems of real vulnerabilities
Prerequisites
Comfortable with C++ fundamentals (types, classes, RAII, templates, basic STL).