Undefined Behavior

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

    test.zig

    1. 1/1 test "safety check"...reached unreachable code
    2. /deps/zig/docgen_tmp/test.zig:2:5: 0x204b9a in test "safety check" (test)
    3. unreachable;
    4. ^
    5. /deps/zig/lib/std/special/test_runner.zig:47:28: 0x22ba9e in std.special.main (test)
    6. } else test_fn.func();
    7. ^
    8. /deps/zig/lib/std/start.zig:253:37: 0x2055cd in std.start.posixCallMainAndExit (test)
    9. const result = root.main() catch |err| {
    10. ^
    11. /deps/zig/lib/std/start.zig:123:5: 0x20530f in std.start._start (test)
    12. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    13. ^
    14. Tests failed. Use the following command to reproduce the failure:
    15. /deps/zig/docgen_tmp/test

    At compile-time:

    test.zig

    1. comptime {
    2. assert(false);
    3. }
    4. fn assert(ok: bool) void {
    5. if (!ok) unreachable; // assertion failure
    6. }
    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:5:14: error: unable to evaluate constant expression
    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. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. reached unreachable code
    4. /deps/zig/lib/std/debug.zig:228:14: 0x203cbb in std.debug.assert (test)
    5. if (!ok) unreachable; // assertion failure
    6. ^
    7. /deps/zig/docgen_tmp/test.zig:4:21: 0x22a7da in main (test)
    8. std.debug.assert(false);
    9. ^
    10. /deps/zig/lib/std/start.zig:243:22: 0x2046df in std.start.posixCallMainAndExit (test)
    11. root.main();
    12. ^
    13. /deps/zig/lib/std/start.zig:123:5: 0x2044bf in std.start._start (test)
    14. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    15. ^
    16. (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. }
    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. }
    4. fn foo(x: []const u8) u8 {
    5. return x[5];
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. index out of bounds
    4. /deps/zig/docgen_tmp/test.zig:6:13: 0x22e969 in foo (test)
    5. return x[5];
    6. ^
    7. /deps/zig/docgen_tmp/test.zig:2:16: 0x22a7e6 in main (test)
    8. var x = foo("hello");
    9. ^
    10. /deps/zig/lib/std/start.zig:243:22: 0x2046df in std.start.posixCallMainAndExit (test)
    11. root.main();
    12. ^
    13. /deps/zig/lib/std/start.zig:123:5: 0x2044bf in std.start._start (test)
    14. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    15. ^
    16. (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. }
    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'
    3. const unsigned = @intCast(u32, value);
    4. ^
    5. ./docgen_tmp/test.zig:3:22: note: referenced here
    6. const unsigned = @intCast(u32, value);
    7. ^

    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.warn("value: {}\n", .{unsigned});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. attempt to cast negative value to unsigned integer
    4. /deps/zig/docgen_tmp/test.zig:5:20: 0x22a867 in main (test)
    5. var unsigned = @intCast(u32, value);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20472f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20450f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (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. }
    1. $ zig test test.zig
    2. ./docgen_tmp/test.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'
    3. const byte = @intCast(u8, spartan_count);
    4. ^
    5. ./docgen_tmp/test.zig:3:18: note: referenced here
    6. const byte = @intCast(u8, spartan_count);
    7. ^

    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.warn("value: {}\n", .{byte});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. integer cast truncated bits
    4. /deps/zig/docgen_tmp/test.zig:5:18: 0x22a86c in main (test)
    5. const byte = @intCast(u8, spartan_count);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20472f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20450f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    To truncate bits, use .

    Integer Overflow

    The following operators can cause integer overflow:

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

    Example with addition at compile-time:

    test.zig

    1. comptime {
    2. var byte: u8 = 255;
    3. byte += 1;
    4. }
    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.warn("value: {}\n", .{byte});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. integer overflow
    4. /deps/zig/docgen_tmp/test.zig:5:10: 0x22a850 in main (test)
    5. byte += 1;
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20472f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20450f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (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 warn = @import("std").debug.warn;
    3. pub fn main() !void {
    4. var byte: u8 = 255;
    5. byte = if (math.add(u8, byte, 1)) |result| result else |err| {
    6. warn("unable to add one: {}\n", .{@errorName(err)});
    7. return err;
    8. };
    9. warn("result: {}\n", .{byte});
    10. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. unable to add one: Overflow
    4. error: Overflow
    5. /deps/zig/lib/std/math.zig:342:5: 0x22ee70 in std.math.add (test)
    6. return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
    7. ^
    8. /deps/zig/docgen_tmp/test.zig:8:9: 0x22ab3b 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 @addWithOverflow:

    test.zig

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

    These operations have guaranteed wraparound semantics.

    • +% (wraparound addition)
    • -% (wraparound subtraction)
    • -% (wraparound negation)
    • *% (wraparound multiplication)
    1. const std = @import("std");
    2. const assert = std.debug.assert;
    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. assert(min_val == minInt(i32));
    9. const max_val = min_val -% 1;
    10. }
    1. $ zig test test.zig
    2. 1/1 test "wraparound addition and subtraction"...OK
    3. All 1 tests passed.

    Exact Left Shift Overflow

    At compile-time:

    test.zig

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

    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.warn("value: {}\n", .{y});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. left shift overflowed bits
    4. /deps/zig/docgen_tmp/test.zig:5:13: 0x22a89d in main (test)
    5. var y = @shlExact(x, 2);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20475f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20453f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    At compile-time:

    test.zig

    1. comptime {
    2. const x = @shrExact(@as(u8, 0b10101010), 2);
    3. }
    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.warn("value: {}\n", .{y});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. right shift overflowed bits
    4. /deps/zig/docgen_tmp/test.zig:5:13: 0x22a89d in main (test)
    5. var y = @shrExact(x, 2);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20475f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20453f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    Division by Zero

    At compile-time:

    test.zig

    1. comptime {
    2. const a: i32 = 1;
    3. const b: i32 = 0;
    4. const c = a / b;
    5. }
    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.warn("value: {}\n", .{c});
    7. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. division by zero
    4. /deps/zig/docgen_tmp/test.zig:6:15: 0x22a859 in main (test)
    5. var c = a / b;
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20472f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20450f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    Remainder Division by Zero

    At compile-time:

    test.zig

    1. comptime {
    2. const a: i32 = 10;
    3. const b: i32 = 0;
    4. const c = a % b;
    5. }
    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.warn("value: {}\n", .{c});
    7. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. remainder division by zero or negative value
    4. /deps/zig/docgen_tmp/test.zig:6:15: 0x22a87b in main (test)
    5. var c = a % b;
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20472f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20450f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    Exact Division Remainder

    At compile-time:

    test.zig

    1. comptime {
    2. const a: u32 = 10;
    3. const b: u32 = 3;
    4. const c = @divExact(a, b);
    5. }
    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.warn("value: {}\n", .{c});
    7. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. exact division produced remainder
    4. /deps/zig/docgen_tmp/test.zig:6:13: 0x22a89d in main (test)
    5. var c = @divExact(a, b);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20472f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20450f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    Attempt to Unwrap Null

    At compile-time:

    test.zig

    1. comptime {
    2. const optional_number: ?i32 = null;
    3. const number = optional_number.?;
    4. }
    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.warn("value: {}\n", .{number});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. attempt to use null value
    4. /deps/zig/docgen_tmp/test.zig:5:33: 0x22a86c in main (test)
    5. var number = optional_number.?;
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20474f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20452f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (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 warn = @import("std").debug.warn;
    2. pub fn main() void {
    3. const optional_number: ?i32 = null;
    4. if (optional_number) |number| {
    5. warn("got number: {}\n", .{number});
    6. } else {
    7. warn("it's null\n", .{});
    8. }
    9. }
    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. }
    4. fn getNumberOrFail() !i32 {
    5. return error.UnableToReturnNumber;
    6. }
    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.warn("value: {}\n", .{number});
    5. }
    6. fn getNumberOrFail() !i32 {
    7. return error.UnableToReturnNumber;
    8. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. attempt to unwrap error: UnableToReturnNumber
    4. /deps/zig/docgen_tmp/test.zig:9:5: 0x22ea6c in getNumberOrFail (test)
    5. return error.UnableToReturnNumber;
    6. ^
    7. ???:?:?: 0x20698c in ??? (???)
    8. /deps/zig/docgen_tmp/test.zig:4:38: 0x22a8cb in main (test)
    9. const number = getNumberOrFail() catch unreachable;
    10. ^
    11. /deps/zig/lib/std/start.zig:243:22: 0x20476f in std.start.posixCallMainAndExit (test)
    12. root.main();
    13. ^
    14. /deps/zig/lib/std/start.zig:123:5: 0x20454f in std.start._start (test)
    15. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    16. ^
    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:

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

    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);
    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);
    4. ^

    At runtime:

    test.zig

    1. const std = @import("std");
    2. pub fn main() void {
    3. var err = error.AnError;
    4. var invalid_err = @intToError(number);
    5. std.debug.warn("value: {}\n", .{number});
    6. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. invalid error code
    4. /deps/zig/docgen_tmp/test.zig:6:23: 0x22a8b4 in main (test)
    5. var invalid_err = @intToError(number);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20475f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20453f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    Invalid Enum Cast

    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. }
    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.warn("value: {}\n", .{@tagName(b)});
    11. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. invalid enum value
    4. /deps/zig/docgen_tmp/test.zig:11:13: 0x22a8cc in main (test)
    5. var b = @intToEnum(Foo, a);
    6. ^
    7. /deps/zig/lib/std/start.zig:243:22: 0x20479f in std.start.posixCallMainAndExit (test)
    8. root.main();
    9. ^
    10. /deps/zig/lib/std/start.zig:123:5: 0x20457f in std.start._start (test)
    11. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    12. ^
    13. (process terminated by signal)

    Invalid Error Set Cast

    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. }
    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.warn("value: {}\n", .{x});
    16. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. invalid error code
    4. /deps/zig/docgen_tmp/test.zig:15:15: 0x22ea4c in foo (test)
    5. const x = @errSetCast(Set2, set1);
    6. ^
    7. /deps/zig/docgen_tmp/test.zig:12:8: 0x22a89d in main (test)
    8. foo(Set1.B);
    9. ^
    10. /deps/zig/lib/std/start.zig:243:22: 0x20479f in std.start.posixCallMainAndExit (test)
    11. root.main();
    12. ^
    13. /deps/zig/lib/std/start.zig:123:5: 0x20457f in std.start._start (test)
    14. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    15. ^
    16. (process terminated by signal)

    Incorrect Pointer Alignment

    At compile-time:

    test.zig

    1. comptime {
    2. const ptr = @intToPtr(*align(1) i32, 0x1);
    3. const aligned = @alignCast(4, ptr);
    4. }
    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. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. incorrect alignment
    4. /deps/zig/docgen_tmp/test.zig:9:59: 0x22edbb in foo (test)
    5. const int_slice = mem.bytesAsSlice(u32, @alignCast(4, slice4));
    6. ^
    7. /deps/zig/docgen_tmp/test.zig:5:12: 0x22aa49 in main (test)
    8. if (foo(bytes) != 0x11111111) return error.Wrong;
    9. ^
    10. /deps/zig/lib/std/start.zig:253:37: 0x2047ed in std.start.posixCallMainAndExit (test)
    11. const result = root.main() catch |err| {
    12. ^
    13. /deps/zig/lib/std/start.zig:123:5: 0x20452f in std.start._start (test)
    14. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    15. ^
    16. (process terminated by signal)

    Wrong Union Field Access

    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. };
    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.warn("value: {}\n", .{f.float});
    13. }
    1. $ zig build-exe test.zig
    2. $ ./test
    3. access of inactive union field
    4. /deps/zig/docgen_tmp/test.zig:14:6: 0x23c21a in bar (test)
    5. f.float = 12.34;
    6. ^
    7. /deps/zig/docgen_tmp/test.zig:10:8: 0x23806c in main (test)
    8. bar(&f);
    9. ^
    10. /deps/zig/lib/std/start.zig:243:22: 0x211f5f in std.start.posixCallMainAndExit (test)
    11. root.main();
    12. ^
    13. /deps/zig/lib/std/start.zig:123:5: 0x211d3f in std.start._start (test)
    14. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    15. ^
    16. (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.warn("value: {}\n", .{f.float});
    13. }
    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 , 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.warn("value: {}\n", .{f.float});
    11. }
    12. fn bar(f: *Foo) void {
    13. f.float = 12.34;
    14. }
    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. }
    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:

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