Lesson 14 of 15

Safety & Build Modes

Safety Checks and Build Modes

Zig's design philosophy is "detectable illegal behavior." The compiler and runtime work together to catch bugs early, and you control how aggressively they do so through build modes. Understanding these modes is essential for writing production Zig code.

The Four Build Modes

Zig provides four optimization modes, each with different trade-offs between safety, performance, and binary size:

Debug (default)

  • No optimizations applied
  • Runtime safety checks enabled: integer overflow detection, out-of-bounds indexing, null pointer dereference on optionals, and unreachable code detection
  • Full stack traces on panic
  • Best for development and debugging

ReleaseSafe

  • Optimizations enabled (like -O2 in C)
  • Runtime safety checks still enabled
  • Best for production code where correctness matters more than peak performance
  • This is what most server software should use

ReleaseFast

  • Aggressive optimizations (like -O3 in C)
  • All runtime safety checks removed
  • Best for performance-critical inner loops, games, or code that has been thoroughly tested
  • Undefined behavior is possible if your code has bugs

ReleaseSmall

  • Optimized for binary size
  • Safety checks removed
  • Best for embedded systems or WebAssembly where code size is constrained

You select the mode when building:

zig build -Doptimize=Debug
zig build -Doptimize=ReleaseSafe
zig build -Doptimize=ReleaseFast
zig build -Doptimize=ReleaseSmall

Runtime Safety Checks

In Debug and ReleaseSafe modes, Zig performs several checks at runtime:

Integer overflow: Arithmetic that overflows panics instead of silently wrapping:

var x: u8 = 255;
x += 1; // PANIC in Debug/ReleaseSafe, wraps to 0 in ReleaseFast

If you intentionally want wrapping arithmetic, use the wrapping operators:

var x: u8 = 255;
x +%= 1; // Always wraps: x is now 0

Out-of-bounds: Indexing past the end of an array or slice panics:

const arr = [_]i32{ 1, 2, 3 };
const val = arr[5]; // PANIC: index out of bounds

Unreachable: The unreachable keyword tells the compiler that a code path should never execute. In safe modes, reaching it panics. In fast modes, it is undefined behavior:

fn classify(n: u8) []const u8 {
    if (n < 128) return "low";
    if (n >= 128) return "high";
    unreachable; // Safe modes: panic. Fast modes: UB.
}

@setRuntimeSafety

You can override the build mode's safety setting for a specific scope using @setRuntimeSafety:

fn fastUncheckedAdd(a: u32, b: u32) u32 {
    @setRuntimeSafety(false);
    return a + b; // No overflow check even in Debug mode
}

fn alwaysSafeAdd(a: u32, b: u32) u32 {
    @setRuntimeSafety(true);
    return a + b; // Overflow check even in ReleaseFast mode
}

This is useful when:

  • A hot inner loop needs to skip bounds checks after you have proven correctness
  • A critical function should always be checked regardless of build mode

Wrapping vs Saturating Arithmetic

Zig provides explicit operators for non-standard arithmetic:

OperatorMeaningExample
+Checked add (panics on overflow)200 + 200 panics for u8
+%Wrapping add255 +% 1 = 0 for u8
`+`Saturating add

The same variants exist for subtraction (-, -%, -|) and multiplication (*, *%, *|).

"Safety protocols engaged, Captain." In Debug mode, Zig's shields are at maximum --- every out-of-bounds access, every overflow is caught. In ReleaseFast mode, the shields are down: you gain speed but lose protection.

Your Task

Write three functions that demonstrate different arithmetic behaviors:

  • checkedAdd(a: u8, b: u8) ?u16 --- adds a and b and returns the result as a u16. If the sum would exceed 255, return null. Otherwise, return the sum. (This simulates what a safety check does, but as a function you control.)
  • wrappingAdd(a: u8, b: u8) u8 --- adds a and b using wrapping arithmetic (+%). Always succeeds, wraps on overflow.
  • saturatingAdd(a: u8, b: u8) u8 --- adds a and b using saturating arithmetic (+|). Clamps to 255 instead of overflowing.
Zig runtime loading...
Loading...
Click "Run" to execute your code.