Glossary / Unsafe code

Unsafe code

Unsafe code allows C# programs to use pointers and perform operations that bypass some managed type and memory safety checks. It is useful for interop and specialized performance work, but increases the risk of memory corruption, security defects, and runtime crashes; enabling unsafe compilation does not make all code in a project unsafe.

Context and pointer operations

Unsafe operations appear in unsafe blocks or members, and the project must enable unsafe compilation. Pointer types use *, address-of &, and dereference *; fixed pins movable managed data while a pointer is used. stackalloc can allocate a bounded region on the stack, and Unsafe/MemoryMarshal APIs may expose similar low-level operations without pointer syntax.

The GC may move objects, so raw pointers into managed objects cannot be retained across collection unless pinned. Pinning too much or too long harms GC compaction. Pointer arithmetic must stay within valid memory and alignment rules; the runtime may not detect out-of-bounds accesses. Native memory ownership and cleanup are explicit responsibilities.

Engineering guidance

Keep unsafe code in small reviewed boundaries with safe wrappers. Document invariants, lifetime, alignment, ownership, and pinning. Prefer spans, SafeHandle, and generated interop where possible. Benchmark before accepting safety cost and test under sanitizers/diagnostic tooling where available.

Interview questions

  1. What does unsafe enable? Pointer operations and memory access beyond normal managed safety checks.
  2. Does unsafe disable GC for all objects? No; pinning is needed only while pointers into movable managed objects are used.
  3. Why is long pinning costly? It can impede heap compaction and increase fragmentation.
  4. What safer alternatives exist? Span/Memory, SafeHandle, source-generated interop, and bounded wrappers.
  5. What must be reviewed? Bounds, lifetime, ownership, alignment, pinning, and error cleanup.

References