Undefined Behavior

Zig has many instances of undefined behavior. If undefined behavior is detected at compile-time, Zig emits a compile error and refuses to continue. Most undefined behavior that cannot be detected at compile-time can be detected at runtime. In these cases, Zig has safety checks. Safety checks can be disabled on a per-block basis with @setRuntimeSafety. The ReleaseFast and ReleaseSmall build modes disable all safety checks (except where overridden by @setRuntimeSafety) in order to facilitate optimizations.

When a safety check fails, Zig crashes with a stack trace, like this:

test_undefined_behavior.zig

  1. test "safety check" {
  2. unreachable;
  3. }

Shell

  1. $ zig test test_undefined_behavior.zig
  2. 1/1 test.safety check... thread 2455728 panic: reached unreachable code
  3. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/test_undefined_behavior.zig:2:5: 0x224165 in test.safety check (test)
  4. unreachable;
  5. ^
  6. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/test_runner.zig:176:28: 0x22d379 in mainTerminal (test)
  7. } else test_fn.func();
  8. ^
  9. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/test_runner.zig:36:28: 0x2251ca in main (test)
  10. return mainTerminal();
  11. ^
  12. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x2246a2 in posixCallMainAndExit (test)
  13. root.main();
  14. ^
  15. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x2241f1 in _start (test)
  16. asm volatile (switch (native_arch) {
  17. ^
  18. ???:?:?: 0x0 in ??? (???)
  19. error: the following test command crashed:
  20. /home/ci/actions-runner/_work/zig-bootstrap/out/zig-local-cache/o/7d7f3a85be0a1deb3cb4c93f04df3dc5/test

Reaching Unreachable Code

At compile-time:

test_comptime_reaching_unreachable.zig

  1. comptime {
  2. assert(false);
  3. }
  4. fn assert(ok: bool) void {
  5. if (!ok) unreachable; // assertion failure
  6. }

Shell

  1. $ zig test test_comptime_reaching_unreachable.zig
  2. docgen_tmp/test_comptime_reaching_unreachable.zig:5:14: error: reached unreachable code
  3. if (!ok) unreachable; // assertion failure
  4. ^~~~~~~~~~~
  5. docgen_tmp/test_comptime_reaching_unreachable.zig:2:11: note: called from here
  6. assert(false);
  7. ~~~~~~^~~~~~~

At runtime:

runtime_reaching_unreachable.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. std.debug.assert(false);
  4. }

Shell

  1. $ zig build-exe runtime_reaching_unreachable.zig
  2. $ ./runtime_reaching_unreachable
  3. thread 2455768 panic: reached unreachable code
  4. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/debug.zig:343:14: 0x21fe12 in assert (runtime_reaching_unreachable)
  5. if (!ok) unreachable; // assertion failure
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_reaching_unreachable.zig:4:21: 0x21e64a in main (runtime_reaching_unreachable)
  8. std.debug.assert(false);
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21def2 in posixCallMainAndExit (runtime_reaching_unreachable)
  11. root.main();
  12. ^
  13. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21da41 in _start (runtime_reaching_unreachable)
  14. asm volatile (switch (native_arch) {
  15. ^
  16. ???:?:?: 0x0 in ??? (???)
  17. (process terminated by signal)

Index out of Bounds

At compile-time:

test_comptime_index_out_of_bounds.zig

  1. comptime {
  2. const array: [5]u8 = "hello".*;
  3. const garbage = array[5];
  4. _ = garbage;
  5. }

Shell

  1. $ zig test test_comptime_index_out_of_bounds.zig
  2. docgen_tmp/test_comptime_index_out_of_bounds.zig:3:27: error: index 5 outside array of length 5
  3. const garbage = array[5];
  4. ^

At runtime:

runtime_index_out_of_bounds.zig

  1. pub fn main() void {
  2. var x = foo("hello");
  3. _ = x;
  4. }
  5. fn foo(x: []const u8) u8 {
  6. return x[5];
  7. }

Shell

  1. $ zig build-exe runtime_index_out_of_bounds.zig
  2. $ ./runtime_index_out_of_bounds
  3. thread 2455808 panic: index out of bounds: index 5, len 5
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_index_out_of_bounds.zig:7:13: 0x2202b9 in foo (runtime_index_out_of_bounds)
  5. return x[5];
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_index_out_of_bounds.zig:2:16: 0x21e68b in main (runtime_index_out_of_bounds)
  8. var x = foo("hello");
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21df22 in posixCallMainAndExit (runtime_index_out_of_bounds)
  11. root.main();
  12. ^
  13. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21da71 in _start (runtime_index_out_of_bounds)
  14. asm volatile (switch (native_arch) {
  15. ^
  16. ???:?:?: 0x0 in ??? (???)
  17. (process terminated by signal)

Cast Negative Number to Unsigned Integer

At compile-time:

test_comptime_invalid_cast.zig

  1. comptime {
  2. var value: i32 = -1;
  3. const unsigned: u32 = @intCast(value);
  4. _ = unsigned;
  5. }

Shell

  1. $ zig test test_comptime_invalid_cast.zig
  2. docgen_tmp/test_comptime_invalid_cast.zig:3:36: error: type 'u32' cannot represent integer value '-1'
  3. const unsigned: u32 = @intCast(value);
  4. ^~~~~

At runtime:

runtime_invalid_cast.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var value: i32 = -1;
  4. var unsigned: u32 = @intCast(value);
  5. std.debug.print("value: {}\n", .{unsigned});
  6. }

Shell

  1. $ zig build-exe runtime_invalid_cast.zig
  2. $ ./runtime_invalid_cast
  3. thread 2455848 panic: attempt to cast negative value to unsigned integer
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_cast.zig:5:25: 0x21e82a in main (runtime_invalid_cast)
  5. var unsigned: u32 = @intCast(value);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e082 in posixCallMainAndExit (runtime_invalid_cast)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dbd1 in _start (runtime_invalid_cast)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

To obtain the maximum value of an unsigned integer, use std.math.maxInt.

Cast Truncates Data

At compile-time:

test_comptime_invalid_cast_truncate.zig

  1. comptime {
  2. const spartan_count: u16 = 300;
  3. const byte: u8 = @intCast(spartan_count);
  4. _ = byte;
  5. }

Shell

  1. $ zig test test_comptime_invalid_cast_truncate.zig
  2. docgen_tmp/test_comptime_invalid_cast_truncate.zig:3:31: error: type 'u8' cannot represent integer value '300'
  3. const byte: u8 = @intCast(spartan_count);
  4. ^~~~~~~~~~~~~

At runtime:

runtime_invalid_cast_truncate.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var spartan_count: u16 = 300;
  4. const byte: u8 = @intCast(spartan_count);
  5. std.debug.print("value: {}\n", .{byte});
  6. }

Shell

  1. $ zig build-exe runtime_invalid_cast_truncate.zig
  2. $ ./runtime_invalid_cast_truncate
  3. thread 2455888 panic: integer cast truncated bits
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_cast_truncate.zig:5:22: 0x21e8f1 in main (runtime_invalid_cast_truncate)
  5. const byte: u8 = @intCast(spartan_count);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e142 in posixCallMainAndExit (runtime_invalid_cast_truncate)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dc91 in _start (runtime_invalid_cast_truncate)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

To truncate bits, use @truncate.

Integer Overflow

Default Operations

The following operators can cause integer overflow:

Example with addition at compile-time:

test_comptime_overflow.zig

  1. comptime {
  2. var byte: u8 = 255;
  3. byte += 1;
  4. }

Shell

  1. $ zig test test_comptime_overflow.zig
  2. docgen_tmp/test_comptime_overflow.zig:3:10: error: overflow of integer type 'u8' with value '256'
  3. byte += 1;
  4. ~~~~~^~~~

At runtime:

runtime_overflow.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var byte: u8 = 255;
  4. byte += 1;
  5. std.debug.print("value: {}\n", .{byte});
  6. }

Shell

  1. $ zig build-exe runtime_overflow.zig
  2. $ ./runtime_overflow
  3. thread 2455928 panic: integer overflow
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_overflow.zig:5:10: 0x21e8ce in main (runtime_overflow)
  5. byte += 1;
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e142 in posixCallMainAndExit (runtime_overflow)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dc91 in _start (runtime_overflow)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Standard Library Math Functions

These functions provided by the standard library return possible errors.

  • @import("std").math.add
  • @import("std").math.sub
  • @import("std").math.mul
  • @import("std").math.divTrunc
  • @import("std").math.divFloor
  • @import("std").math.divExact
  • @import("std").math.shl

Example of catching an overflow for addition:

math_add.zig

  1. const math = @import("std").math;
  2. const print = @import("std").debug.print;
  3. pub fn main() !void {
  4. var byte: u8 = 255;
  5. byte = if (math.add(u8, byte, 1)) |result| result else |err| {
  6. print("unable to add one: {s}\n", .{@errorName(err)});
  7. return err;
  8. };
  9. print("result: {}\n", .{byte});
  10. }

Shell

  1. $ zig build-exe math_add.zig
  2. $ ./math_add
  3. unable to add one: Overflow
  4. error: Overflow
  5. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/math.zig:475:21: 0x21e6f5 in add__anon_3060 (math_add)
  6. if (ov[1] != 0) return error.Overflow;
  7. ^
  8. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/math_add.zig:8:9: 0x21e68d in main (math_add)
  9. return err;
  10. ^

Builtin Overflow Functions

These builtins return a tuple containing whether there was an overflow (as a u1) and the possibly overflowed bits of the operation:

Example of @addWithOverflow:

addWithOverflow_builtin.zig

  1. const print = @import("std").debug.print;
  2. pub fn main() void {
  3. var byte: u8 = 255;
  4. const ov = @addWithOverflow(byte, 10);
  5. if (ov[1] != 0) {
  6. print("overflowed result: {}\n", .{ov[0]});
  7. } else {
  8. print("result: {}\n", .{ov[0]});
  9. }
  10. }

Shell

  1. $ zig build-exe addWithOverflow_builtin.zig
  2. $ ./addWithOverflow_builtin
  3. overflowed result: 9

Wrapping Operations

These operations have guaranteed wraparound semantics.

  • +% (wraparound addition)
  • -% (wraparound subtraction)
  • -% (wraparound negation)
  • *% (wraparound multiplication)

test_wraparound_semantics.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. const minInt = std.math.minInt;
  4. const maxInt = std.math.maxInt;
  5. test "wraparound addition and subtraction" {
  6. const x: i32 = maxInt(i32);
  7. const min_val = x +% 1;
  8. try expect(min_val == minInt(i32));
  9. const max_val = min_val -% 1;
  10. try expect(max_val == maxInt(i32));
  11. }

Shell

  1. $ zig test test_wraparound_semantics.zig
  2. 1/1 test.wraparound addition and subtraction... OK
  3. All 1 tests passed.

Exact Left Shift Overflow

At compile-time:

test_comptime_shlExact_overwlow.zig

  1. comptime {
  2. const x = @shlExact(@as(u8, 0b01010101), 2);
  3. _ = x;
  4. }

Shell

  1. $ zig test test_comptime_shlExact_overwlow.zig
  2. docgen_tmp/test_comptime_shlExact_overwlow.zig:2:15: error: operation caused overflow
  3. const x = @shlExact(@as(u8, 0b01010101), 2);
  4. ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

At runtime:

runtime_shlExact_overflow.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var x: u8 = 0b01010101;
  4. var y = @shlExact(x, 2);
  5. std.debug.print("value: {}\n", .{y});
  6. }

Shell

  1. $ zig build-exe runtime_shlExact_overflow.zig
  2. $ ./runtime_shlExact_overflow
  3. thread 2456051 panic: left shift overflowed bits
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_shlExact_overflow.zig:5:5: 0x21e915 in main (runtime_shlExact_overflow)
  5. var y = @shlExact(x, 2);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e162 in posixCallMainAndExit (runtime_shlExact_overflow)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dcb1 in _start (runtime_shlExact_overflow)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Exact Right Shift Overflow

At compile-time:

test_comptime_shrExact_overflow.zig

  1. comptime {
  2. const x = @shrExact(@as(u8, 0b10101010), 2);
  3. _ = x;
  4. }

Shell

  1. $ zig test test_comptime_shrExact_overflow.zig
  2. docgen_tmp/test_comptime_shrExact_overflow.zig:2:15: error: exact shift shifted out 1 bits
  3. const x = @shrExact(@as(u8, 0b10101010), 2);
  4. ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

At runtime:

runtime_shrExact_overflow.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var x: u8 = 0b10101010;
  4. var y = @shrExact(x, 2);
  5. std.debug.print("value: {}\n", .{y});
  6. }

Shell

  1. $ zig build-exe runtime_shrExact_overflow.zig
  2. $ ./runtime_shrExact_overflow
  3. thread 2456091 panic: right shift overflowed bits
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_shrExact_overflow.zig:5:5: 0x21e90e in main (runtime_shrExact_overflow)
  5. var y = @shrExact(x, 2);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e162 in posixCallMainAndExit (runtime_shrExact_overflow)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dcb1 in _start (runtime_shrExact_overflow)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Division by Zero

At compile-time:

test_comptime_division_by_zero.zig

  1. comptime {
  2. const a: i32 = 1;
  3. const b: i32 = 0;
  4. const c = a / b;
  5. _ = c;
  6. }

Shell

  1. $ zig test test_comptime_division_by_zero.zig
  2. docgen_tmp/test_comptime_division_by_zero.zig:4:19: error: division by zero here causes undefined behavior
  3. const c = a / b;
  4. ^

At runtime:

runtime_division_by_zero.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var a: u32 = 1;
  4. var b: u32 = 0;
  5. var c = a / b;
  6. std.debug.print("value: {}\n", .{c});
  7. }

Shell

  1. $ zig build-exe runtime_division_by_zero.zig
  2. $ ./runtime_division_by_zero
  3. thread 2456131 panic: division by zero
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_division_by_zero.zig:6:15: 0x21e83e in main (runtime_division_by_zero)
  5. var c = a / b;
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e082 in posixCallMainAndExit (runtime_division_by_zero)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dbd1 in _start (runtime_division_by_zero)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Remainder Division by Zero

At compile-time:

test_comptime_remainder_division_by_zero.zig

  1. comptime {
  2. const a: i32 = 10;
  3. const b: i32 = 0;
  4. const c = a % b;
  5. _ = c;
  6. }

Shell

  1. $ zig test test_comptime_remainder_division_by_zero.zig
  2. docgen_tmp/test_comptime_remainder_division_by_zero.zig:4:19: error: division by zero here causes undefined behavior
  3. const c = a % b;
  4. ^

At runtime:

runtime_remainder_division_by_zero.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var a: u32 = 10;
  4. var b: u32 = 0;
  5. var c = a % b;
  6. std.debug.print("value: {}\n", .{c});
  7. }

Shell

  1. $ zig build-exe runtime_remainder_division_by_zero.zig
  2. $ ./runtime_remainder_division_by_zero
  3. thread 2456173 panic: division by zero
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_remainder_division_by_zero.zig:6:15: 0x21e83e in main (runtime_remainder_division_by_zero)
  5. var c = a % b;
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e082 in posixCallMainAndExit (runtime_remainder_division_by_zero)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dbd1 in _start (runtime_remainder_division_by_zero)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Exact Division Remainder

At compile-time:

test_comptime_divExact_remainder.zig

  1. comptime {
  2. const a: u32 = 10;
  3. const b: u32 = 3;
  4. const c = @divExact(a, b);
  5. _ = c;
  6. }

Shell

  1. $ zig test test_comptime_divExact_remainder.zig
  2. docgen_tmp/test_comptime_divExact_remainder.zig:4:15: error: exact division produced remainder
  3. const c = @divExact(a, b);
  4. ^~~~~~~~~~~~~~~

At runtime:

runtime_divExact_remainder.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var a: u32 = 10;
  4. var b: u32 = 3;
  5. var c = @divExact(a, b);
  6. std.debug.print("value: {}\n", .{c});
  7. }

Shell

  1. $ zig build-exe runtime_divExact_remainder.zig
  2. $ ./runtime_divExact_remainder
  3. thread 2456213 panic: exact division produced remainder
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_divExact_remainder.zig:6:13: 0x21e898 in main (runtime_divExact_remainder)
  5. var c = @divExact(a, b);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e0a2 in posixCallMainAndExit (runtime_divExact_remainder)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dbf1 in _start (runtime_divExact_remainder)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Attempt to Unwrap Null

At compile-time:

test_comptime_unwrap_null.zig

  1. comptime {
  2. const optional_number: ?i32 = null;
  3. const number = optional_number.?;
  4. _ = number;
  5. }

Shell

  1. $ zig test test_comptime_unwrap_null.zig
  2. docgen_tmp/test_comptime_unwrap_null.zig:3:35: error: unable to unwrap null
  3. const number = optional_number.?;
  4. ~~~~~~~~~~~~~~~^~

At runtime:

runtime_unwrap_null.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var optional_number: ?i32 = null;
  4. var number = optional_number.?;
  5. std.debug.print("value: {}\n", .{number});
  6. }

Shell

  1. $ zig build-exe runtime_unwrap_null.zig
  2. $ ./runtime_unwrap_null
  3. thread 2456253 panic: attempt to use null value
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_unwrap_null.zig:5:33: 0x21e8fa in main (runtime_unwrap_null)
  5. var number = optional_number.?;
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e152 in posixCallMainAndExit (runtime_unwrap_null)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dca1 in _start (runtime_unwrap_null)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

One way to avoid this crash is to test for null instead of assuming non-null, with the if expression:

testing_null_with_if.zig

  1. const print = @import("std").debug.print;
  2. pub fn main() void {
  3. const optional_number: ?i32 = null;
  4. if (optional_number) |number| {
  5. print("got number: {}\n", .{number});
  6. } else {
  7. print("it's null\n", .{});
  8. }
  9. }

Shell

  1. $ zig build-exe testing_null_with_if.zig
  2. $ ./testing_null_with_if
  3. it's null

See also:

Attempt to Unwrap Error

At compile-time:

test_comptime_unwrap_error.zig

  1. comptime {
  2. const number = getNumberOrFail() catch unreachable;
  3. _ = number;
  4. }
  5. fn getNumberOrFail() !i32 {
  6. return error.UnableToReturnNumber;
  7. }

Shell

  1. $ zig test test_comptime_unwrap_error.zig
  2. docgen_tmp/test_comptime_unwrap_error.zig:2:44: error: caught unexpected error 'UnableToReturnNumber'
  3. const number = getNumberOrFail() catch unreachable;
  4. ^~~~~~~~~~~

At runtime:

runtime_unwrap_error.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. const number = getNumberOrFail() catch unreachable;
  4. std.debug.print("value: {}\n", .{number});
  5. }
  6. fn getNumberOrFail() !i32 {
  7. return error.UnableToReturnNumber;
  8. }

Shell

  1. $ zig build-exe runtime_unwrap_error.zig
  2. $ ./runtime_unwrap_error
  3. thread 2456320 panic: attempt to unwrap error: UnableToReturnNumber
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_unwrap_error.zig:9:5: 0x22053f in getNumberOrFail (runtime_unwrap_error)
  5. return error.UnableToReturnNumber;
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_unwrap_error.zig:4:44: 0x21e941 in main (runtime_unwrap_error)
  8. const number = getNumberOrFail() catch unreachable;
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e182 in posixCallMainAndExit (runtime_unwrap_error)
  11. root.main();
  12. ^
  13. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dcd1 in _start (runtime_unwrap_error)
  14. asm volatile (switch (native_arch) {
  15. ^
  16. ???:?:?: 0x0 in ??? (???)
  17. (process terminated by signal)

One way to avoid this crash is to test for an error instead of assuming a successful result, with the if expression:

testing_error_with_if.zig

  1. const print = @import("std").debug.print;
  2. pub fn main() void {
  3. const result = getNumberOrFail();
  4. if (result) |number| {
  5. print("got number: {}\n", .{number});
  6. } else |err| {
  7. print("got error: {s}\n", .{@errorName(err)});
  8. }
  9. }
  10. fn getNumberOrFail() !i32 {
  11. return error.UnableToReturnNumber;
  12. }

Shell

  1. $ zig build-exe testing_error_with_if.zig
  2. $ ./testing_error_with_if
  3. got error: UnableToReturnNumber

See also:

Invalid Error Code

At compile-time:

test_comptime_invalid_error_code.zig

  1. comptime {
  2. const err = error.AnError;
  3. const number = @intFromError(err) + 10;
  4. const invalid_err = @errorFromInt(number);
  5. _ = invalid_err;
  6. }

Shell

  1. $ zig test test_comptime_invalid_error_code.zig
  2. docgen_tmp/test_comptime_invalid_error_code.zig:4:39: error: integer value '11' represents no error
  3. const invalid_err = @errorFromInt(number);
  4. ^~~~~~

At runtime:

runtime_invalid_error_code.zig

  1. const std = @import("std");
  2. pub fn main() void {
  3. var err = error.AnError;
  4. var number = @intFromError(err) + 500;
  5. var invalid_err = @errorFromInt(number);
  6. std.debug.print("value: {}\n", .{invalid_err});
  7. }

Shell

  1. $ zig build-exe runtime_invalid_error_code.zig
  2. $ ./runtime_invalid_error_code
  3. thread 2456387 panic: invalid error code
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_error_code.zig:6:5: 0x21e8c9 in main (runtime_invalid_error_code)
  5. var invalid_err = @errorFromInt(number);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e102 in posixCallMainAndExit (runtime_invalid_error_code)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dc51 in _start (runtime_invalid_error_code)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Invalid Enum Cast

At compile-time:

test_comptime_invalid_enum_cast.zig

  1. const Foo = enum {
  2. a,
  3. b,
  4. c,
  5. };
  6. comptime {
  7. const a: u2 = 3;
  8. const b: Foo = @enumFromInt(a);
  9. _ = b;
  10. }

Shell

  1. $ zig test test_comptime_invalid_enum_cast.zig
  2. docgen_tmp/test_comptime_invalid_enum_cast.zig:8:20: error: enum 'test_comptime_invalid_enum_cast.Foo' has no tag with value '3'
  3. const b: Foo = @enumFromInt(a);
  4. ^~~~~~~~~~~~~~~
  5. docgen_tmp/test_comptime_invalid_enum_cast.zig:1:13: note: enum declared here
  6. const Foo = enum {
  7. ^~~~

At runtime:

runtime_invalid_enum_cast.zig

  1. const std = @import("std");
  2. const Foo = enum {
  3. a,
  4. b,
  5. c,
  6. };
  7. pub fn main() void {
  8. var a: u2 = 3;
  9. var b: Foo = @enumFromInt(a);
  10. std.debug.print("value: {s}\n", .{@tagName(b)});
  11. }

Shell

  1. $ zig build-exe runtime_invalid_enum_cast.zig
  2. $ ./runtime_invalid_enum_cast
  3. thread 2456427 panic: invalid enum value
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_enum_cast.zig:11:18: 0x21e87f in main (runtime_invalid_enum_cast)
  5. var b: Foo = @enumFromInt(a);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e0d2 in posixCallMainAndExit (runtime_invalid_enum_cast)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dc21 in _start (runtime_invalid_enum_cast)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Invalid Error Set Cast

At compile-time:

test_comptime_invalid_error_set_cast.zig

  1. const Set1 = error{
  2. A,
  3. B,
  4. };
  5. const Set2 = error{
  6. A,
  7. C,
  8. };
  9. comptime {
  10. _ = @as(Set2, @errSetCast(Set1.B));
  11. }

Shell

  1. $ zig test test_comptime_invalid_error_set_cast.zig
  2. docgen_tmp/test_comptime_invalid_error_set_cast.zig:10:19: error: 'error.B' not a member of error set 'error{C,A}'
  3. _ = @as(Set2, @errSetCast(Set1.B));
  4. ^~~~~~~~~~~~~~~~~~~

At runtime:

runtime_invalid_error_set_cast.zig

  1. const std = @import("std");
  2. const Set1 = error{
  3. A,
  4. B,
  5. };
  6. const Set2 = error{
  7. A,
  8. C,
  9. };
  10. pub fn main() void {
  11. foo(Set1.B);
  12. }
  13. fn foo(set1: Set1) void {
  14. const x: Set2 = @errSetCast(set1);
  15. std.debug.print("value: {}\n", .{x});
  16. }

Shell

  1. $ zig build-exe runtime_invalid_error_set_cast.zig
  2. $ ./runtime_invalid_error_set_cast
  3. thread 2456467 panic: invalid error code
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_error_set_cast.zig:15:21: 0x2204dc in foo (runtime_invalid_error_set_cast)
  5. const x: Set2 = @errSetCast(set1);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_error_set_cast.zig:12:8: 0x21e88d in main (runtime_invalid_error_set_cast)
  8. foo(Set1.B);
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21e132 in posixCallMainAndExit (runtime_invalid_error_set_cast)
  11. root.main();
  12. ^
  13. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dc81 in _start (runtime_invalid_error_set_cast)
  14. asm volatile (switch (native_arch) {
  15. ^
  16. ???:?:?: 0x0 in ??? (???)
  17. (process terminated by signal)

Incorrect Pointer Alignment

At compile-time:

test_comptime_incorrect_pointer_alignment.zig

  1. comptime {
  2. const ptr: *align(1) i32 = @ptrFromInt(0x1);
  3. const aligned: *align(4) i32 = @alignCast(ptr);
  4. _ = aligned;
  5. }

Shell

  1. $ zig test test_comptime_incorrect_pointer_alignment.zig
  2. docgen_tmp/test_comptime_incorrect_pointer_alignment.zig:3:47: error: pointer address 0x1 is not aligned to 4 bytes
  3. const aligned: *align(4) i32 = @alignCast(ptr);
  4. ^~~

At runtime:

runtime_incorrect_pointer_alignment.zig

  1. const mem = @import("std").mem;
  2. pub fn main() !void {
  3. var array align(4) = [_]u32{ 0x11111111, 0x11111111 };
  4. const bytes = mem.sliceAsBytes(array[0..]);
  5. if (foo(bytes) != 0x11111111) return error.Wrong;
  6. }
  7. fn foo(bytes: []u8) u32 {
  8. const slice4 = bytes[1..5];
  9. const int_slice = mem.bytesAsSlice(u32, @as([]align(4) u8, @alignCast(slice4)));
  10. return int_slice[0];
  11. }

Shell

  1. $ zig build-exe runtime_incorrect_pointer_alignment.zig
  2. $ ./runtime_incorrect_pointer_alignment
  3. thread 2456507 panic: incorrect alignment
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_incorrect_pointer_alignment.zig:9:64: 0x21e43f in foo (runtime_incorrect_pointer_alignment)
  5. const int_slice = mem.bytesAsSlice(u32, @as([]align(4) u8, @alignCast(slice4)));
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_incorrect_pointer_alignment.zig:5:12: 0x21e33f in main (runtime_incorrect_pointer_alignment)
  8. if (foo(bytes) != 0x11111111) return error.Wrong;
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:574:37: 0x21e24e in posixCallMainAndExit (runtime_incorrect_pointer_alignment)
  11. const result = root.main() catch |err| {
  12. ^
  13. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21dd31 in _start (runtime_incorrect_pointer_alignment)
  14. asm volatile (switch (native_arch) {
  15. ^
  16. ???:?:?: 0x0 in ??? (???)
  17. (process terminated by signal)

Wrong Union Field Access

At compile-time:

test_comptime_wrong_union_field_access.zig

  1. comptime {
  2. var f = Foo{ .int = 42 };
  3. f.float = 12.34;
  4. }
  5. const Foo = union {
  6. float: f32,
  7. int: u32,
  8. };

Shell

  1. $ zig test test_comptime_wrong_union_field_access.zig
  2. docgen_tmp/test_comptime_wrong_union_field_access.zig:3:6: error: access of union field 'float' while field 'int' is active
  3. f.float = 12.34;
  4. ~^~~~~~
  5. docgen_tmp/test_comptime_wrong_union_field_access.zig:6:13: note: union declared here
  6. const Foo = union {
  7. ^~~~~

At runtime:

runtime_wrong_union_field_access.zig

  1. const std = @import("std");
  2. const Foo = union {
  3. float: f32,
  4. int: u32,
  5. };
  6. pub fn main() void {
  7. var f = Foo{ .int = 42 };
  8. bar(&f);
  9. }
  10. fn bar(f: *Foo) void {
  11. f.float = 12.34;
  12. std.debug.print("value: {}\n", .{f.float});
  13. }

Shell

  1. $ zig build-exe runtime_wrong_union_field_access.zig
  2. $ ./runtime_wrong_union_field_access
  3. thread 2456547 panic: access of union field 'float' while field 'int' is active
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_wrong_union_field_access.zig:14:6: 0x234cc0 in bar (runtime_wrong_union_field_access)
  5. f.float = 12.34;
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_wrong_union_field_access.zig:10:8: 0x23308c in main (runtime_wrong_union_field_access)
  8. bar(&f);
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x232922 in posixCallMainAndExit (runtime_wrong_union_field_access)
  11. root.main();
  12. ^
  13. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x232471 in _start (runtime_wrong_union_field_access)
  14. asm volatile (switch (native_arch) {
  15. ^
  16. ???:?:?: 0x0 in ??? (???)
  17. (process terminated by signal)

This safety is not available for extern or packed unions.

To change the active field of a union, assign the entire union, like this:

change_active_union_field.zig

  1. const std = @import("std");
  2. const Foo = union {
  3. float: f32,
  4. int: u32,
  5. };
  6. pub fn main() void {
  7. var f = Foo{ .int = 42 };
  8. bar(&f);
  9. }
  10. fn bar(f: *Foo) void {
  11. f.* = Foo{ .float = 12.34 };
  12. std.debug.print("value: {}\n", .{f.float});
  13. }

Shell

  1. $ zig build-exe change_active_union_field.zig
  2. $ ./change_active_union_field
  3. value: 1.23400001e+01

To change the active field of a union when a meaningful value for the field is not known, use undefined, like this:

undefined_active_union_field.zig

  1. const std = @import("std");
  2. const Foo = union {
  3. float: f32,
  4. int: u32,
  5. };
  6. pub fn main() void {
  7. var f = Foo{ .int = 42 };
  8. f = Foo{ .float = undefined };
  9. bar(&f);
  10. std.debug.print("value: {}\n", .{f.float});
  11. }
  12. fn bar(f: *Foo) void {
  13. f.float = 12.34;
  14. }

Shell

  1. $ zig build-exe undefined_active_union_field.zig
  2. $ ./undefined_active_union_field
  3. value: 1.23400001e+01

See also:

Out of Bounds Float to Integer Cast

This happens when casting a float to an integer where the float has a value outside the integer type’s range.

At compile-time:

test_comptime_out_of_bounds_float_to_integer_cast.zig

  1. comptime {
  2. const float: f32 = 4294967296;
  3. const int: i32 = @intFromFloat(float);
  4. _ = int;
  5. }

Shell

  1. $ zig test test_comptime_out_of_bounds_float_to_integer_cast.zig
  2. docgen_tmp/test_comptime_out_of_bounds_float_to_integer_cast.zig:3:33: error: float value '4294967296' cannot be stored in integer type 'i32'
  3. const int: i32 = @intFromFloat(float);
  4. ^~~~~

At runtime:

runtime_out_of_bounds_float_to_integer_cast.zig

  1. pub fn main() void {
  2. var float: f32 = 4294967296;
  3. var int: i32 = @intFromFloat(float);
  4. _ = int;
  5. }

Shell

  1. $ zig build-exe runtime_out_of_bounds_float_to_integer_cast.zig
  2. $ ./runtime_out_of_bounds_float_to_integer_cast
  3. thread 2456641 panic: integer part of floating point value out of bounds
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_out_of_bounds_float_to_integer_cast.zig:3:17: 0x21e70e in main (runtime_out_of_bounds_float_to_integer_cast)
  5. var int: i32 = @intFromFloat(float);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21df42 in posixCallMainAndExit (runtime_out_of_bounds_float_to_integer_cast)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21da91 in _start (runtime_out_of_bounds_float_to_integer_cast)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)

Pointer Cast Invalid Null

This happens when casting a pointer with the address 0 to a pointer which may not have the address 0. For example, C Pointers, Optional Pointers, and allowzero pointers allow address zero, but normal Pointers do not.

At compile-time:

test_comptime_invalid_null_pointer_cast.zig

  1. comptime {
  2. const opt_ptr: ?*i32 = null;
  3. const ptr: *i32 = @ptrCast(opt_ptr);
  4. _ = ptr;
  5. }

Shell

  1. $ zig test test_comptime_invalid_null_pointer_cast.zig
  2. docgen_tmp/test_comptime_invalid_null_pointer_cast.zig:3:32: error: null pointer casted to type '*i32'
  3. const ptr: *i32 = @ptrCast(opt_ptr);
  4. ^~~~~~~

At runtime:

runtime_invalid_null_pointer_cast.zig

  1. pub fn main() void {
  2. var opt_ptr: ?*i32 = null;
  3. var ptr: *i32 = @ptrCast(opt_ptr);
  4. _ = ptr;
  5. }

Shell

  1. $ zig build-exe runtime_invalid_null_pointer_cast.zig
  2. $ ./runtime_invalid_null_pointer_cast
  3. thread 2456681 panic: cast causes pointer to be null
  4. /home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_null_pointer_cast.zig:3:21: 0x21e691 in main (runtime_invalid_null_pointer_cast)
  5. var ptr: *i32 = @ptrCast(opt_ptr);
  6. ^
  7. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:564:22: 0x21def2 in posixCallMainAndExit (runtime_invalid_null_pointer_cast)
  8. root.main();
  9. ^
  10. /home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:243:5: 0x21da41 in _start (runtime_invalid_null_pointer_cast)
  11. asm volatile (switch (native_arch) {
  12. ^
  13. ???:?:?: 0x0 in ??? (???)
  14. (process terminated by signal)