Safer Systems Software Without a Full Rewrite
Introduction: The Memory Safety Problem in C++
- The Scale of the Problem
- Why C++ Gets Memory Safety Wrong
- The Full Rewrite Fallacy
- What This Book Will Give You
Chapter 1: How Memory Safety Failures Happen
- The C++ Memory Model in Practice
- Pointers, References, and Their Promises
- Object Lifetimes and Aliasing
- Undefined Behavior as the Root Cause
- From Bug to Exploit
Chapter 2: Buffer Overflows and Out-of-Bounds Access
- Mechanics of Buffer Overruns
- Stack and Heap Smashing
- Off-by-One and Off-by-Many Errors
- Modern C++ Bounds-Safe Patterns
- Refactoring C-Style Arrays and Pointers
Chapter 3: Use-After-Free and Dangling References
- How Use-After-Free Occurs
- Exploitation: Heap Feng Shui and Function Pointer Overwrite
- Dangling References and Iterators
- RAII as the Foundation
- Smart Pointer Semantics and Ownership
Chapter 4: Double Free and Memory Leaks
- The Double Free Mechanism
- Exploiting Double Free for Arbitrary Write
- Memory Leaks: Not Just a Performance Problem
- Allocators and Lifetime Guarantees
Chapter 5: Uninitialized Memory and Data Leaks
- Stack and Heap Uninitialized Memory
- Information Leaks Through Uninitialized Buffers
- Aggregate Initialization and Value Initialization
- Modern Defaults: Constructors and std::optional
- Zero-Cost Safety Guarantees
Chapter 6: Iterator Invalidation and Container Safety
- How Iterator Invalidation Occurs
- Consequences Across Standard Containers
- Safe Patterns and Range-Based Alternatives
- C++20 Ranges for Safer Algorithms
- Real-World Refactoring Examples
Chapter 7: Type Confusion and Variant Safety
- Polymorphic Type Confusion
- Union-Based Type Confusion in C-Style APIs
- std::variant and std::any for Type-Safe Unions
- Virtual Tables and Their Assumptions
- Safe Casting: dynamic_cast and Alternatives
Chapter 8: Concurrency-Related Memory Errors
- Data Races Are Undefined Behavior
- False Sharing and Memory Ordering Pitfalls
- std::atomic and Correct Concurrent Programming
- Threading Primitives and Memory Guarantees
- Lock-Free Data Structures and Their Dangers
Chapter 9: The RAII Idiom in Depth
- RAII Origins and Philosophy
- Resource Scope and Deterministic Cleanup
- RAII for Non-Memory Resources
- Exception Safety and RAII Guarantees
- RAII Wrappers for Legacy C APIs
Chapter 10: Ownership, Move Semantics, and Value Semantics
- Unique Ownership and std::unique_ptr
- Shared Ownership and std::shared_ptr
- Move Semantics for Efficient Ownership Transfer
- Value Semantics for Safer APIs
- Ownership Documentation and Contracts
Chapter 11: Bounds-Safe Interfaces and std::span
- The Problem with (pointer, size) Pairs
- std::span as a View Type
- Migrating C APIs to Span-Based Interfaces
- std::string_view for String Handling
- Performance Characteristics and ABI Implications
Chapter 12: Modern Containers and Allocators
- Container Choice and Safety Implications
- Custom Allocators for Control
- Memory Pools for Performance and Safety
- Container Growth and Invalidation Guarantees
- Safe Interoperability with C Allocators
Chapter 13: Exception Safety and Its Role in Memory Safety
- Exception Safety Levels and Memory Leaks
- Strong and Basic Guarantees in Practice
- RAII Under Exceptions
- Nothrow Operations and Performance-Critical Code
- Handling Exceptions in C-API Boundaries
Chapter 14: Assessing Your Legacy Codebase
- Establishing a Security Baseline
- Static Risk Indicators in Code
- Runtime Profiling for Dangerous Patterns
- Prioritization Frameworks
- Mapping Dependencies and Blast Radius
Chapter 15: Incremental Modernization Strategies
- The Facade Pattern for Gradual Modernization
- Building Safe Envelopes Around Unsafe Code
- Header-Only Modernization Libraries
- ABI Compatibility and Versioning
- Managing Technical Debt and Scope
Chapter 16: Refactoring Patterns for Safer C++
- Migrating from Raw Pointers to Smart Pointers
- Eliminating C-Style String APIs
- Safe Memory Copy Patterns
- Refactoring Callbacks and Function Pointers
- Real-World Before-and-After Case Studies
Chapter 17: Compiler Diagnostics and Warnings
- GCC, Clang, and MSVC Warning Flags
- Enforcing Warnings as Errors
- Compiler-Specific Diagnostics for Memory Safety
- Incremental Warning Adoption
- Suppression Strategies That Do Not Harm
Chapter 18: Sanitizers for Development and Testing
- AddressSanitizer Configuration and Interpretation
- UndefinedBehaviorSanitizer for Pre-Exploit Detection
- MemorySanitizer for Uninitialized Memory
- ThreadSanitizer for Data Race Detection
- Performance Overhead and Practical Usage
Chapter 19: Static Analysis for Large Codebases
- clang-tidy and Its Safety Checks
- Cppcheck and Other Static Analyzers
- Integrating Analysis into CI Pipelines
- Tuning for Signal Over Noise
- Understanding False Positives and False Negatives
Chapter 20: Fuzzing and Dynamic Testing
- LibFuzzer for C++ Codebases
- AFL++ and Other Fuzzing Frameworks
- Designing Fuzz Targets for Existing APIs
- Integrating Fuzzing with Sanitizers
- From Bug Discovery to Remediation
Chapter 21: Runtime Mitigations and Hardened Deployments
- ASLR, Stack Canaries, and NX Bits
- Control-Flow Integrity Mechanisms
- Hardened Standard Library Implementations
- Containerization and Namespace Isolation
- Limitations and Defense-in-Depth
Chapter 22: Automated Refactoring and Tool-Assisted Migration
- Clang-Tidy’s Modernization Checks
- Automated Smart Pointer Migration
- Coccinelle and Semantic Patching
- Refactoring Large Teams and Codebases
- Validating Automated Changes
Chapter 23: Measuring Progress and Continuous Improvement
- Safety Metrics That Matter
- Baseline and Trend Measurement
- Security Testing in CI/CD
- Regression Prevention
- Building a Safety Culture
Chapter 24: Case Study: Modernizing a Network Server
- Legacy Codebase and Risk Profile
- Initial Assessment and Tooling Setup
- Phased Refactoring Plan
- Measuring the Safety Improvements
- Lessons and Generalizations
Chapter 25: Case Study: Storage Engine Safety
- Memory Safety Challenges in Storage Systems
- Lifetime Management in B-Tree Structures
- Concurrent Access and Iterator Safety
- Allocator Design for Safety and Performance
- Validation and Deployment
Conclusion: The Road Ahead
- What We Have Learned
- Emerging C++ Safety Features
- The Economics of Incremental Modernization
- Final Recommendations