Undefined Behavior

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

    test.zig

    Shell

    1. 1/1 test "safety check"... thread 797490 panic: reached unreachable code
    2. /home/andy/Downloads/zig/docgen_tmp/test.zig:2:5: 0x2079da in test "safety check" (test)
    3. unreachable;
    4. ^
    5. /home/andy/Downloads/zig/lib/std/special/test_runner.zig:80:28: 0x22f3e3 in std.special.main (test)
    6. } else test_fn.func();
    7. ^
    8. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x227ddc in std.start.callMain (test)
    9. root.main();
    10. ^
    11. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2091fe in std.start.callMainWithArgs (test)
    12. return @call(.{ .modifier = .always_inline }, callMain, .{});
    13. ^
    14. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x208296 in std.start.posixCallMainAndExit (test)
    15. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    16. ^
    17. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x2080a2 in std.start._start (test)
    18. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    19. ^
    20. error: the following test command crashed:
    21. docgen_tmp/zig-cache/o/8e4964e05ddaf866e77360a551b3c05b/test /home/andy/Downloads/zig/build-release/zig

    At compile-time:

    test.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.zig
    2. ./docgen_tmp/test.zig:5:14: error: reached unreachable code
    3. if (!ok) unreachable; // assertion failure
    4. ^
    5. ./docgen_tmp/test.zig:2:11: note: called from here
    6. assert(false);
    7. ^
    8. ./docgen_tmp/test.zig:1:10: note: called from here
    9. comptime {
    10. ^
    11. ./docgen_tmp/test.zig:2:11: note: referenced here
    12. assert(false);
    13. ^

    At runtime:

    test.zig

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

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 797551 panic: reached unreachable code
    4. /home/andy/Downloads/zig/lib/std/debug.zig:224:14: 0x204e3b in std.debug.assert (test)
    5. if (!ok) unreachable; // assertion failure
    6. ^
    7. /home/andy/Downloads/zig/docgen_tmp/test.zig:4:21: 0x22ce2a in main (test)
    8. std.debug.assert(false);
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225bbc in std.start.callMain (test)
    11. root.main();
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x206fbe in std.start.callMainWithArgs (test)
    14. return @call(.{ .modifier = .always_inline }, callMain, .{});
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206056 in std.start.posixCallMainAndExit (test)
    17. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    18. ^
    19. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205e62 in std.start._start (test)
    20. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    21. ^
    22. (process terminated by signal)

    Index out of Bounds

    At compile-time:

    test.zig

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

    Shell

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

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 797611 panic: index out of bounds
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:7:13: 0x2344e9 in foo (test)
    5. return x[5];
    6. ^
    7. /home/andy/Downloads/zig/docgen_tmp/test.zig:2:16: 0x22ce36 in main (test)
    8. var x = foo("hello");
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225bbc in std.start.callMain (test)
    11. root.main();
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x206fbe in std.start.callMainWithArgs (test)
    14. return @call(.{ .modifier = .always_inline }, callMain, .{});
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206056 in std.start.posixCallMainAndExit (test)
    17. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    18. ^
    19. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205e62 in std.start._start (test)
    20. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    21. ^
    22. (process terminated by signal)

    Cast Negative Number to Unsigned Integer

    At compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:3:22: error: attempt to cast negative value to unsigned integer
    3. const unsigned = @intCast(u32, value);
    4. ^

    At runtime:

    test.zig

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

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 797672 panic: attempt to cast negative value to unsigned integer
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:20: 0x22cf27 in main (test)
    5. var unsigned = @intCast(u32, value);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

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

    Cast Truncates Data

    At compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:3:18: error: cast from 'u16' to 'u8' truncates bits
    3. const byte = @intCast(u8, spartan_count);
    4. ^

    At runtime:

    test.zig

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

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 797733 panic: integer cast truncated bits
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:18: 0x22cf2c in main (test)
    5. const byte = @intCast(u8, spartan_count);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    To truncate bits, use .

    The following operators can cause integer overflow:

    • + (addition)
    • - (subtraction)
    • - (negation)
    • * (multiplication)
    • / (division)
    • @divTrunc (division)
    • (division)
    • @divExact (division)

    Example with addition at compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:3:10: error: operation caused overflow
    3. byte += 1;
    4. ^

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 797794 panic: integer overflow
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:10: 0x22cf0f in main (test)
    5. byte += 1;
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    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:

    test.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 test.zig
    2. $ ./test
    3. unable to add one: Overflow
    4. error: Overflow
    5. /home/andy/Downloads/zig/lib/std/math.zig:463:5: 0x234a3b in std.math.add (test)
    6. return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
    7. ^
    8. /home/andy/Downloads/zig/docgen_tmp/test.zig:8:9: 0x22d294 in main (test)
    9. return err;
    10. ^

    These builtins return a bool of whether or not overflow occurred, as well as returning the overflowed bits:

    Example of :

    test.zig

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

    Shell

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

    These operations have guaranteed wraparound semantics.

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

    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 wraparound_semantics.zig
    2. 1/1 test "wraparound addition and subtraction"... OK
    3. All 1 tests passed.

    test.zig

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

    Shell

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 797961 panic: left shift overflowed bits
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:13: 0x22cf5b in main (test)
    5. var y = @shlExact(x, 2);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225cac in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2070ae in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206146 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f52 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.zig

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

    Shell

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

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798021 panic: right shift overflowed bits
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:13: 0x22cf6b in main (test)
    5. var y = @shrExact(x, 2);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225cbc in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2070be in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206156 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f62 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.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.zig
    2. ./docgen_tmp/test.zig:4:17: error: division by zero
    3. const c = a / b;
    4. ^

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798081 panic: division by zero
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:6:15: 0x22cf19 in main (test)
    5. var c = a / b;
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.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.zig
    2. ./docgen_tmp/test.zig:4:17: error: division by zero
    3. const c = a % b;
    4. ^

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798142 panic: remainder division by zero or negative value
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:6:15: 0x22cf3b in main (test)
    5. var c = a % b;
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.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.zig
    2. ./docgen_tmp/test.zig:4:15: error: exact division had a remainder
    3. const c = @divExact(a, b);
    4. ^

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798202 panic: exact division produced remainder
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:6:13: 0x22cf5d in main (test)
    5. var c = @divExact(a, b);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.zig

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

    Shell

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

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798262 panic: attempt to use null value
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:33: 0x22cf0c in main (test)
    5. var number = optional_number.?;
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c7c in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20707e in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206116 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f22 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

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

    test.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 test.zig
    2. $ ./test
    3. it's null

    See also:

    Attempt to Unwrap Error

    At compile-time:

    test.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.zig
    2. ./docgen_tmp/test.zig:2:38: error: caught unexpected error 'UnableToReturnNumber'
    3. const number = getNumberOrFail() catch unreachable;
    4. ^

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798359 panic: attempt to unwrap error: UnableToReturnNumber
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:9:5: 0x234644 in getNumberOrFail (test)
    5. return error.UnableToReturnNumber;
    6. ^
    7. ???:?:?: 0x20ce72 in ??? (???)
    8. /home/andy/Downloads/zig/docgen_tmp/test.zig:4:38: 0x22cf6b in main (test)
    9. const number = getNumberOrFail() catch unreachable;
    10. ^
    11. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225c9c in std.start.callMain (test)
    12. root.main();
    13. ^
    14. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x20709e in std.start.callMainWithArgs (test)
    15. return @call(.{ .modifier = .always_inline }, callMain, .{});
    16. ^
    17. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206136 in std.start.posixCallMainAndExit (test)
    18. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    19. ^
    20. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f42 in std.start._start (test)
    21. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    22. ^
    23. (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:

    test.zig

    1. $ zig build-exe test.zig
    2. $ ./test

    See also:

    At compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:4:25: error: integer value 11 represents no error
    3. const invalid_err = @intToError(number);

    At runtime:

    test.zig

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

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 798455 panic: invalid error code
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:6:23: 0x22cf93 in main (test)
    5. var invalid_err = @intToError(number);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225ccc in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2070ce in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206166 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f72 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:8:15: error: enum 'Foo' has no tag matching integer value 3
    3. const b = @intToEnum(Foo, a);
    4. ^
    5. ./docgen_tmp/test.zig:1:13: note: 'Foo' declared here
    6. const Foo = enum {
    7. ^

    At runtime:

    test.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 = @intToEnum(Foo, a);
    10. std.debug.print("value: {s}\n", .{@tagName(b)});
    11. }

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 798517 panic: invalid enum value
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:11:13: 0x22cf89 in main (test)
    5. var b = @intToEnum(Foo, a);
    6. ^
    7. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225cec in std.start.callMain (test)
    8. root.main();
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2070ee in std.start.callMainWithArgs (test)
    11. return @call(.{ .modifier = .always_inline }, callMain, .{});
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206186 in std.start.posixCallMainAndExit (test)
    14. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f92 in std.start._start (test)
    17. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    18. ^
    19. (process terminated by signal)

    At compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:10:9: error: error.B not a member of error set 'Set2'
    3. _ = @errSetCast(Set2, Set1.B);
    4. ^

    At runtime:

    test.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 = @errSetCast(Set2, set1);
    15. std.debug.print("value: {}\n", .{x});
    16. }

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 798577 panic: invalid error code
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:15:15: 0x234636 in foo (test)
    5. const x = @errSetCast(Set2, set1);
    6. ^
    7. /home/andy/Downloads/zig/docgen_tmp/test.zig:12:8: 0x22cf5d in main (test)
    8. foo(Set1.B);
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x225cec in std.start.callMain (test)
    11. root.main();
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2070ee in std.start.callMainWithArgs (test)
    14. return @call(.{ .modifier = .always_inline }, callMain, .{});
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206186 in std.start.posixCallMainAndExit (test)
    17. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    18. ^
    19. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f92 in std.start._start (test)
    20. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    21. ^
    22. (process terminated by signal)

    At compile-time:

    test.zig

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

    Shell

    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes
    3. const aligned = @alignCast(4, ptr);
    4. ^
    5. ./docgen_tmp/test.zig:3:21: note: referenced here
    6. const aligned = @alignCast(4, ptr);
    7. ^

    At runtime:

    test.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, @alignCast(4, slice4));
    10. return int_slice[0];
    11. }

    Shell

    1. $ zig build-exe test.zig
    2. $ ./test
    3. thread 798638 panic: incorrect alignment
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:9:59: 0x2348ac in foo (test)
    5. const int_slice = mem.bytesAsSlice(u32, @alignCast(4, slice4));
    6. ^
    7. /home/andy/Downloads/zig/docgen_tmp/test.zig:5:12: 0x22d0c5 in main (test)
    8. if (foo(bytes) != 0x11111111) return error.Wrong;
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:553:37: 0x225cfa in std.start.callMain (test)
    11. const result = root.main() catch |err| {
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x2070ce in std.start.callMainWithArgs (test)
    14. return @call(.{ .modifier = .always_inline }, callMain, .{});
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x206166 in std.start.posixCallMainAndExit (test)
    17. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    18. ^
    19. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x205f72 in std.start._start (test)
    20. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    21. ^
    22. (process terminated by signal)

    At compile-time:

    test.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.zig
    2. ./docgen_tmp/test.zig:3:6: error: accessing union field 'float' while field 'int' is set
    3. f.float = 12.34;
    4. ^

    At runtime:

    test.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 test.zig
    2. $ ./test
    3. thread 798698 panic: access of inactive union field
    4. /home/andy/Downloads/zig/docgen_tmp/test.zig:14:6: 0x241eea in bar (test)
    5. f.float = 12.34;
    6. ^
    7. /home/andy/Downloads/zig/docgen_tmp/test.zig:10:8: 0x23a80c in main (test)
    8. bar(&f);
    9. ^
    10. /home/andy/Downloads/zig/lib/std/start.zig:543:22: 0x23358c in std.start.callMain (test)
    11. root.main();
    12. ^
    13. /home/andy/Downloads/zig/lib/std/start.zig:495:12: 0x21498e in std.start.callMainWithArgs (test)
    14. return @call(.{ .modifier = .always_inline }, callMain, .{});
    15. ^
    16. /home/andy/Downloads/zig/lib/std/start.zig:409:17: 0x213a26 in std.start.posixCallMainAndExit (test)
    17. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
    18. ^
    19. /home/andy/Downloads/zig/lib/std/start.zig:322:5: 0x213832 in std.start._start (test)
    20. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    21. ^
    22. (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:

    test.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 test.zig
    2. $ ./test
    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:

    test.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 test.zig
    2. $ ./test
    3. value: 1.23400001e+01

    See also:

    Out of Bounds Float to Integer Cast

    TODO

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

    At compile-time:

    test.zig

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

    Shell

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

    At runtime:

    test.zig

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

    Shell