| name | memory-safety |
| description | Memory safety theory and practice, language-agnostic: spatial/temporal violation classes (buffer overflow, use-after-free, double-free, dangling pointers, uninitialized reads, type confusion), ownership and lifetime models (RAII, borrow checking, reference counting, GC, exclusivity), sanitizers (ASan/TSan/UBSan/MSan), and hardware mitigations (ASLR, W^X, stack canaries, PAC, MTE, CHERI). Use when reviewing unsafe/low-level code, diagnosing memory corruption or crashes (segfault, heap corruption, UAF), choosing ownership strategies, or hardening builds. For C bounds annotations use c-bounds-safety; for Xcode hardening settings use audit-xcode-security-settings.
|
| allowed-tools | ["Read","Glob","Grep","Bash"] |
Memory Safety
IRON LAW: UNSAFE CODE IS GUILTY UNTIL PROVEN SAFE. EVERY unsafe/raw-pointer
BLOCK NEEDS A STATED INVARIANT: WHO OWNS IT, HOW LONG IT LIVES, WHAT BOUNDS IT.
Violation Classes (know what you're looking at)
| Class | Kind | Typical symptom | CWE |
|---|
| Out-of-bounds read/write | Spatial | Corruption "far away", crash in unrelated code | CWE-125/787 |
| Use-after-free | Temporal | Works in debug, crashes in release; heap corruption | CWE-416 |
| Double free | Temporal | Allocator abort, exploitable heap state | CWE-415 |
| Dangling stack pointer | Temporal | Garbage values after return | CWE-562 |
| Uninitialized read | Initialization | Nondeterministic behavior, info leaks | CWE-457 |
| Type confusion | Type | "Impossible" values, vtable crashes | CWE-843 |
| Data race on shared memory | Concurrency | Heisenbugs; UB in C/C++/Swift | CWE-362 |
Memory corruption is the classic root of exploitable bugs (historically cited
as ~70% of severe CVEs in large C/C++ codebases — the motivation for
memory-safe-by-default languages).
Ownership & Lifetime Models (choose deliberately)
| Model | Guarantees | Costs / hazards |
|---|
| Manual (C) | None — discipline only | All classes above |
| RAII + smart pointers (C++) | Scoped lifetime | UAF via raw this/views; iterator invalidation |
| Borrow checking (Rust-style) | Compile-time spatial+temporal | Learning curve; unsafe escape hatches |
| Reference counting (ARC/shared_ptr) | Temporal (while referenced) | Cycles leak — need weak refs; count traffic |
| Tracing GC | Temporal | Pauses/footprint; finalizer hazards |
| Exclusivity enforcement (Swift) | No overlapping read/write access | Runtime traps reveal aliasing bugs |
Rules that hold in every model:
- One owner per allocation; everything else borrows. Document which is which
at API boundaries (who frees? may the callee retain?).
- Never return/store a pointer or view (slice, span, string_view, buffer
pointer) that can outlive its backing storage.
- Bounds travel WITH pointers (pointer+count as one unit — see
c-bounds-safety for compiler-enforced annotations).
Sanitizers (run them; they're cheap insurance)
| Tool | Catches | Notes |
|---|
| ASan (AddressSanitizer) | OOB, UAF, double-free | ~2x slowdown; run unit tests under it in CI |
| TSan (ThreadSanitizer) | Data races | Mutually exclusive with ASan — separate CI job |
| UBSan | UB: overflow, misalignment, bad casts | Cheap; combine with ASan |
| MSan | Uninitialized reads | Clang, non-Darwin mostly; needs full rebuild |
| Fuzzing (libFuzzer/AFL) + ASan | Parser/decoder corruption | Pair with testing skill's fuzz guidance |
Debug-only checks (allocator guard malloc, debug iterators) catch less than
sanitizers — don't substitute one for the other.
Hardware & Platform Mitigations (defense in depth, not a fix)
- ASLR + W^X (DEP/NX): baseline everywhere; don't defeat with predictable
mappings or RWX pages (JITs need careful design).
- Stack canaries / shadow stacks: detect return-address smashing.
- PAC (ARM pointer authentication, arm64e): signs return addresses and
function pointers — see
audit-xcode-security-settings
(pointer-authentication reference).
- MTE (ARM Memory Tagging): probabilistic spatial+temporal detection via
tagged pointers — see
audit-xcode-security-settings
(hardware-memory-tagging reference).
- CHERI capabilities: research/early deployment — pointers carry bounds
and permissions in hardware.
Mitigations raise exploitation cost; the bug is still a bug. Fix root cause.
Language Notes
- Swift: memory-safe by default. The unsafe surface is explicit and
greppable:
Unsafe*Pointer, unsafeBitCast, unowned(unsafe),
withUnsafe*, .assumingMemoryBound, C interop. Review checklist: bounds
proven, lifetime pinned (withExtendedLifetime where needed), no escaping
of withUnsafe* pointers from the closure, alignment respected. Exclusivity
violations trap at runtime — they're real aliasing bugs, never "disable the
check". Data races: Swift 6 strict concurrency makes them compile-time
errors — see swift (concurrency).
- C/C++: prefer
-fbounds-safety (see c-bounds-safety), hardened
libc++, smart pointers, span types; ban naked new/malloc in new code.
- Kotlin/JVM: memory-safe runtime; the unsafe surface is JNI/native
interop and
sun.misc.Unsafe — apply the C rules there.
Review Workflow
- Grep the unsafe surface (per language above) — inventory before reading.
- For each unsafe site: state owner, lifetime, bounds invariant. Can't state
it → finding.
- Check error/early-return paths for cleanup (leaks, double-free) — the
sad path is where temporal bugs live.
- Confirm sanitizer coverage exists for the code path; recommend the missing
CI job if not.
Related Skills
| Need | Skill |
|---|
C -fbounds-safety adoption | c-bounds-safety |
| PAC/MTE/Enhanced Security build settings | audit-xcode-security-settings |
| Exploit-relevant security review | secure-coding, apple-secure-coding |
| Cache/layout performance of memory | hardware-runtime |
| Swift ownership & layout specifics | swift (memory-layout-performance) |