- Undefined Behavior
- Reaching Unreachable Code
- Index out of Bounds
- Cast Negative Number to Unsigned Integer
- Cast Truncates Data
- Integer Overflow
- Exact Left Shift Overflow
- Exact Right Shift Overflow
- Division by Zero
- Remainder Division by Zero
- Exact Division Remainder
- Attempt to Unwrap Null
- Attempt to Unwrap Error
- Invalid Error Code
- Invalid Enum Cast
- Invalid Error Set Cast
- Incorrect Pointer Alignment
- Wrong Union Field Access
- Out of Bounds Float to Integer Cast
- Pointer Cast Invalid Null
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
test "safety check" {
unreachable;
}
Shell
$ zig test test_undefined_behavior.zig
1/1 test_undefined_behavior.test.safety check... thread 990514 panic: reached unreachable code
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/test_undefined_behavior.zig:2:5: 0x1038e50 in test.safety check (test)
unreachable;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/compiler/test_runner.zig:158:25: 0x1044252 in mainTerminal (test)
if (test_fn.func()) |_| {
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/compiler/test_runner.zig:35:28: 0x103a23b in main (test)
return mainTerminal();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1039379 in posixCallMainAndExit (test)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1038ee1 in _start (test)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
error: the following test command crashed:
/home/ci/actions-runner/_work/zig-bootstrap/out/zig-local-cache/o/2b91ce43fc94ee5453af2c9e105375fc/test
Reaching Unreachable Code
At compile-time:
test_comptime_reaching_unreachable.zig
comptime {
assert(false);
}
fn assert(ok: bool) void {
if (!ok) unreachable; // assertion failure
}
Shell
$ zig test test_comptime_reaching_unreachable.zig
docgen_tmp/test_comptime_reaching_unreachable.zig:5:14: error: reached unreachable code
if (!ok) unreachable; // assertion failure
^~~~~~~~~~~
docgen_tmp/test_comptime_reaching_unreachable.zig:2:11: note: called from here
assert(false);
~~~~~~^~~~~~~
At runtime:
runtime_reaching_unreachable.zig
const std = @import("std");
pub fn main() void {
std.debug.assert(false);
}
Shell
$ zig build-exe runtime_reaching_unreachable.zig
$ ./runtime_reaching_unreachable
thread 990554 panic: reached unreachable code
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/debug.zig:403:14: 0x10357fd in assert (runtime_reaching_unreachable)
if (!ok) unreachable; // assertion failure
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_reaching_unreachable.zig:4:21: 0x1033bba in main (runtime_reaching_unreachable)
std.debug.assert(false);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033469 in posixCallMainAndExit (runtime_reaching_unreachable)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1032fd1 in _start (runtime_reaching_unreachable)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Index out of Bounds
At compile-time:
test_comptime_index_out_of_bounds.zig
comptime {
const array: [5]u8 = "hello".*;
const garbage = array[5];
_ = garbage;
}
Shell
$ zig test test_comptime_index_out_of_bounds.zig
docgen_tmp/test_comptime_index_out_of_bounds.zig:3:27: error: index 5 outside array of length 5
const garbage = array[5];
^
At runtime:
runtime_index_out_of_bounds.zig
pub fn main() void {
const x = foo("hello");
_ = x;
}
fn foo(x: []const u8) u8 {
return x[5];
}
Shell
$ zig build-exe runtime_index_out_of_bounds.zig
$ ./runtime_index_out_of_bounds
thread 990594 panic: index out of bounds: index 5, len 5
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_index_out_of_bounds.zig:7:13: 0x1035c79 in foo (runtime_index_out_of_bounds)
return x[5];
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_index_out_of_bounds.zig:2:18: 0x1033be6 in main (runtime_index_out_of_bounds)
const x = foo("hello");
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033489 in posixCallMainAndExit (runtime_index_out_of_bounds)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1032ff1 in _start (runtime_index_out_of_bounds)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Cast Negative Number to Unsigned Integer
At compile-time:
test_comptime_invalid_cast.zig
comptime {
const value: i32 = -1;
const unsigned: u32 = @intCast(value);
_ = unsigned;
}
Shell
$ zig test test_comptime_invalid_cast.zig
docgen_tmp/test_comptime_invalid_cast.zig:3:36: error: type 'u32' cannot represent integer value '-1'
const unsigned: u32 = @intCast(value);
^~~~~
At runtime:
runtime_invalid_cast.zig
const std = @import("std");
pub fn main() void {
var value: i32 = -1; // runtime-known
_ = &value;
const unsigned: u32 = @intCast(value);
std.debug.print("value: {}\n", .{unsigned});
}
Shell
$ zig build-exe runtime_invalid_cast.zig
$ ./runtime_invalid_cast
thread 990635 panic: attempt to cast negative value to unsigned integer
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_cast.zig:6:27: 0x1033d22 in main (runtime_invalid_cast)
const unsigned: u32 = @intCast(value);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033589 in posixCallMainAndExit (runtime_invalid_cast)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x10330f1 in _start (runtime_invalid_cast)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(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
comptime {
const spartan_count: u16 = 300;
const byte: u8 = @intCast(spartan_count);
_ = byte;
}
Shell
$ zig test test_comptime_invalid_cast_truncate.zig
docgen_tmp/test_comptime_invalid_cast_truncate.zig:3:31: error: type 'u8' cannot represent integer value '300'
const byte: u8 = @intCast(spartan_count);
^~~~~~~~~~~~~
At runtime:
runtime_invalid_cast_truncate.zig
const std = @import("std");
pub fn main() void {
var spartan_count: u16 = 300; // runtime-known
_ = &spartan_count;
const byte: u8 = @intCast(spartan_count);
std.debug.print("value: {}\n", .{byte});
}
Shell
$ zig build-exe runtime_invalid_cast_truncate.zig
$ ./runtime_invalid_cast_truncate
thread 990675 panic: integer cast truncated bits
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_cast_truncate.zig:6:22: 0x1033dbc in main (runtime_invalid_cast_truncate)
const byte: u8 = @intCast(spartan_count);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033619 in posixCallMainAndExit (runtime_invalid_cast_truncate)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033181 in _start (runtime_invalid_cast_truncate)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
To truncate bits, use @truncate.
Integer Overflow
Default Operations
The following operators can cause integer overflow:
+
(addition)-
(subtraction)-
(negation)*
(multiplication)/
(division)- @divTrunc (division)
- @divFloor (division)
- @divExact (division)
Example with addition at compile-time:
test_comptime_overflow.zig
comptime {
var byte: u8 = 255;
byte += 1;
}
Shell
$ zig test test_comptime_overflow.zig
docgen_tmp/test_comptime_overflow.zig:3:10: error: overflow of integer type 'u8' with value '256'
byte += 1;
~~~~~^~~~
At runtime:
runtime_overflow.zig
const std = @import("std");
pub fn main() void {
var byte: u8 = 255;
byte += 1;
std.debug.print("value: {}\n", .{byte});
}
Shell
$ zig build-exe runtime_overflow.zig
$ ./runtime_overflow
thread 990715 panic: integer overflow
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_overflow.zig:5:10: 0x1033d9e in main (runtime_overflow)
byte += 1;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033619 in posixCallMainAndExit (runtime_overflow)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033181 in _start (runtime_overflow)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(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
const math = @import("std").math;
const print = @import("std").debug.print;
pub fn main() !void {
var byte: u8 = 255;
byte = if (math.add(u8, byte, 1)) |result| result else |err| {
print("unable to add one: {s}\n", .{@errorName(err)});
return err;
};
print("result: {}\n", .{byte});
}
Shell
$ zig build-exe math_add.zig
$ ./math_add
unable to add one: Overflow
error: Overflow
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/math.zig:619:21: 0x1033df5 in add__anon_2650 (math_add)
if (ov[1] != 0) return error.Overflow;
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/math_add.zig:8:9: 0x1033d93 in main (math_add)
return err;
^
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
const print = @import("std").debug.print;
pub fn main() void {
const byte: u8 = 255;
const ov = @addWithOverflow(byte, 10);
if (ov[1] != 0) {
print("overflowed result: {}\n", .{ov[0]});
} else {
print("result: {}\n", .{ov[0]});
}
}
Shell
$ zig build-exe addWithOverflow_builtin.zig
$ ./addWithOverflow_builtin
overflowed result: 9
Wrapping Operations
These operations have guaranteed wraparound semantics.
+%
(wraparound addition)-%
(wraparound subtraction)-%
(wraparound negation)*%
(wraparound multiplication)
test_wraparound_semantics.zig
const std = @import("std");
const expect = std.testing.expect;
const minInt = std.math.minInt;
const maxInt = std.math.maxInt;
test "wraparound addition and subtraction" {
const x: i32 = maxInt(i32);
const min_val = x +% 1;
try expect(min_val == minInt(i32));
const max_val = min_val -% 1;
try expect(max_val == maxInt(i32));
}
Shell
$ zig test test_wraparound_semantics.zig
1/1 test_wraparound_semantics.test.wraparound addition and subtraction... OK
All 1 tests passed.
Exact Left Shift Overflow
At compile-time:
test_comptime_shlExact_overwlow.zig
comptime {
const x = @shlExact(@as(u8, 0b01010101), 2);
_ = x;
}
Shell
$ zig test test_comptime_shlExact_overwlow.zig
docgen_tmp/test_comptime_shlExact_overwlow.zig:2:15: error: operation caused overflow
const x = @shlExact(@as(u8, 0b01010101), 2);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At runtime:
runtime_shlExact_overflow.zig
const std = @import("std");
pub fn main() void {
var x: u8 = 0b01010101; // runtime-known
_ = &x;
const y = @shlExact(x, 2);
std.debug.print("value: {}\n", .{y});
}
Shell
$ zig build-exe runtime_shlExact_overflow.zig
$ ./runtime_shlExact_overflow
thread 990836 panic: left shift overflowed bits
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_shlExact_overflow.zig:6:5: 0x1033ddd in main (runtime_shlExact_overflow)
const y = @shlExact(x, 2);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033639 in posixCallMainAndExit (runtime_shlExact_overflow)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x10331a1 in _start (runtime_shlExact_overflow)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Exact Right Shift Overflow
At compile-time:
test_comptime_shrExact_overflow.zig
comptime {
const x = @shrExact(@as(u8, 0b10101010), 2);
_ = x;
}
Shell
$ zig test test_comptime_shrExact_overflow.zig
docgen_tmp/test_comptime_shrExact_overflow.zig:2:15: error: exact shift shifted out 1 bits
const x = @shrExact(@as(u8, 0b10101010), 2);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At runtime:
runtime_shrExact_overflow.zig
const std = @import("std");
pub fn main() void {
var x: u8 = 0b10101010; // runtime-known
_ = &x;
const y = @shrExact(x, 2);
std.debug.print("value: {}\n", .{y});
}
Shell
$ zig build-exe runtime_shrExact_overflow.zig
$ ./runtime_shrExact_overflow
thread 990876 panic: right shift overflowed bits
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_shrExact_overflow.zig:6:5: 0x1033dd9 in main (runtime_shrExact_overflow)
const y = @shrExact(x, 2);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033639 in posixCallMainAndExit (runtime_shrExact_overflow)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x10331a1 in _start (runtime_shrExact_overflow)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Division by Zero
At compile-time:
test_comptime_division_by_zero.zig
comptime {
const a: i32 = 1;
const b: i32 = 0;
const c = a / b;
_ = c;
}
Shell
$ zig test test_comptime_division_by_zero.zig
docgen_tmp/test_comptime_division_by_zero.zig:4:19: error: division by zero here causes undefined behavior
const c = a / b;
^
At runtime:
runtime_division_by_zero.zig
const std = @import("std");
pub fn main() void {
var a: u32 = 1;
var b: u32 = 0;
_ = .{ &a, &b };
const c = a / b;
std.debug.print("value: {}\n", .{c});
}
Shell
$ zig build-exe runtime_division_by_zero.zig
$ ./runtime_division_by_zero
thread 990916 panic: division by zero
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_division_by_zero.zig:7:17: 0x1033d36 in main (runtime_division_by_zero)
const c = a / b;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033589 in posixCallMainAndExit (runtime_division_by_zero)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x10330f1 in _start (runtime_division_by_zero)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Remainder Division by Zero
At compile-time:
test_comptime_remainder_division_by_zero.zig
comptime {
const a: i32 = 10;
const b: i32 = 0;
const c = a % b;
_ = c;
}
Shell
$ zig test test_comptime_remainder_division_by_zero.zig
docgen_tmp/test_comptime_remainder_division_by_zero.zig:4:19: error: division by zero here causes undefined behavior
const c = a % b;
^
At runtime:
runtime_remainder_division_by_zero.zig
const std = @import("std");
pub fn main() void {
var a: u32 = 10;
var b: u32 = 0;
_ = .{ &a, &b };
const c = a % b;
std.debug.print("value: {}\n", .{c});
}
Shell
$ zig build-exe runtime_remainder_division_by_zero.zig
$ ./runtime_remainder_division_by_zero
thread 990956 panic: division by zero
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_remainder_division_by_zero.zig:7:17: 0x1033d36 in main (runtime_remainder_division_by_zero)
const c = a % b;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033589 in posixCallMainAndExit (runtime_remainder_division_by_zero)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x10330f1 in _start (runtime_remainder_division_by_zero)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Exact Division Remainder
At compile-time:
test_comptime_divExact_remainder.zig
comptime {
const a: u32 = 10;
const b: u32 = 3;
const c = @divExact(a, b);
_ = c;
}
Shell
$ zig test test_comptime_divExact_remainder.zig
docgen_tmp/test_comptime_divExact_remainder.zig:4:15: error: exact division produced remainder
const c = @divExact(a, b);
^~~~~~~~~~~~~~~
At runtime:
runtime_divExact_remainder.zig
const std = @import("std");
pub fn main() void {
var a: u32 = 10;
var b: u32 = 3;
_ = .{ &a, &b };
const c = @divExact(a, b);
std.debug.print("value: {}\n", .{c});
}
Shell
$ zig build-exe runtime_divExact_remainder.zig
$ ./runtime_divExact_remainder
thread 990996 panic: exact division produced remainder
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_divExact_remainder.zig:7:15: 0x1033d8b in main (runtime_divExact_remainder)
const c = @divExact(a, b);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x10335a9 in posixCallMainAndExit (runtime_divExact_remainder)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033111 in _start (runtime_divExact_remainder)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Attempt to Unwrap Null
At compile-time:
test_comptime_unwrap_null.zig
comptime {
const optional_number: ?i32 = null;
const number = optional_number.?;
_ = number;
}
Shell
$ zig test test_comptime_unwrap_null.zig
docgen_tmp/test_comptime_unwrap_null.zig:3:35: error: unable to unwrap null
const number = optional_number.?;
~~~~~~~~~~~~~~~^~
At runtime:
runtime_unwrap_null.zig
const std = @import("std");
pub fn main() void {
var optional_number: ?i32 = null;
_ = &optional_number;
const number = optional_number.?;
std.debug.print("value: {}\n", .{number});
}
Shell
$ zig build-exe runtime_unwrap_null.zig
$ ./runtime_unwrap_null
thread 991036 panic: attempt to use null value
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_unwrap_null.zig:6:35: 0x1033db2 in main (runtime_unwrap_null)
const number = optional_number.?;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033619 in posixCallMainAndExit (runtime_unwrap_null)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033181 in _start (runtime_unwrap_null)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(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
const print = @import("std").debug.print;
pub fn main() void {
const optional_number: ?i32 = null;
if (optional_number) |number| {
print("got number: {}\n", .{number});
} else {
print("it's null\n", .{});
}
}
Shell
$ zig build-exe testing_null_with_if.zig
$ ./testing_null_with_if
it's null
See also:
Attempt to Unwrap Error
At compile-time:
test_comptime_unwrap_error.zig
comptime {
const number = getNumberOrFail() catch unreachable;
_ = number;
}
fn getNumberOrFail() !i32 {
return error.UnableToReturnNumber;
}
Shell
$ zig test test_comptime_unwrap_error.zig
docgen_tmp/test_comptime_unwrap_error.zig:2:44: error: caught unexpected error 'UnableToReturnNumber'
const number = getNumberOrFail() catch unreachable;
^~~~~~~~~~~
docgen_tmp/test_comptime_unwrap_error.zig:7:18: note: error returned here
return error.UnableToReturnNumber;
^~~~~~~~~~~~~~~~~~~~
At runtime:
runtime_unwrap_error.zig
const std = @import("std");
pub fn main() void {
const number = getNumberOrFail() catch unreachable;
std.debug.print("value: {}\n", .{number});
}
fn getNumberOrFail() !i32 {
return error.UnableToReturnNumber;
}
Shell
$ zig build-exe runtime_unwrap_error.zig
$ ./runtime_unwrap_error
thread 991103 panic: attempt to unwrap error: UnableToReturnNumber
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_unwrap_error.zig:9:5: 0x1035e9f in getNumberOrFail (runtime_unwrap_error)
return error.UnableToReturnNumber;
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_unwrap_error.zig:4:44: 0x1033e31 in main (runtime_unwrap_error)
const number = getNumberOrFail() catch unreachable;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033679 in posixCallMainAndExit (runtime_unwrap_error)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x10331e1 in _start (runtime_unwrap_error)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(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
const print = @import("std").debug.print;
pub fn main() void {
const result = getNumberOrFail();
if (result) |number| {
print("got number: {}\n", .{number});
} else |err| {
print("got error: {s}\n", .{@errorName(err)});
}
}
fn getNumberOrFail() !i32 {
return error.UnableToReturnNumber;
}
Shell
$ zig build-exe testing_error_with_if.zig
$ ./testing_error_with_if
got error: UnableToReturnNumber
See also:
Invalid Error Code
At compile-time:
test_comptime_invalid_error_code.zig
comptime {
const err = error.AnError;
const number = @intFromError(err) + 10;
const invalid_err = @errorFromInt(number);
_ = invalid_err;
}
Shell
$ zig test test_comptime_invalid_error_code.zig
docgen_tmp/test_comptime_invalid_error_code.zig:4:39: error: integer value '11' represents no error
const invalid_err = @errorFromInt(number);
^~~~~~
At runtime:
runtime_invalid_error_code.zig
const std = @import("std");
pub fn main() void {
const err = error.AnError;
var number = @intFromError(err) + 500;
_ = &number;
const invalid_err = @errorFromInt(number);
std.debug.print("value: {}\n", .{invalid_err});
}
Shell
$ zig build-exe runtime_invalid_error_code.zig
$ ./runtime_invalid_error_code
thread 991170 panic: invalid error code
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_error_code.zig:7:5: 0x1033dc0 in main (runtime_invalid_error_code)
const invalid_err = @errorFromInt(number);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033609 in posixCallMainAndExit (runtime_invalid_error_code)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033171 in _start (runtime_invalid_error_code)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Invalid Enum Cast
At compile-time:
test_comptime_invalid_enum_cast.zig
const Foo = enum {
a,
b,
c,
};
comptime {
const a: u2 = 3;
const b: Foo = @enumFromInt(a);
_ = b;
}
Shell
$ zig test test_comptime_invalid_enum_cast.zig
docgen_tmp/test_comptime_invalid_enum_cast.zig:8:20: error: enum 'test_comptime_invalid_enum_cast.Foo' has no tag with value '3'
const b: Foo = @enumFromInt(a);
^~~~~~~~~~~~~~~
docgen_tmp/test_comptime_invalid_enum_cast.zig:1:13: note: enum declared here
const Foo = enum {
^~~~
At runtime:
runtime_invalid_enum_cast.zig
const std = @import("std");
const Foo = enum {
a,
b,
c,
};
pub fn main() void {
var a: u2 = 3;
_ = &a;
const b: Foo = @enumFromInt(a);
std.debug.print("value: {s}\n", .{@tagName(b)});
}
Shell
$ zig build-exe runtime_invalid_enum_cast.zig
$ ./runtime_invalid_enum_cast
thread 991210 panic: invalid enum value
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_enum_cast.zig:12:20: 0x1033d97 in main (runtime_invalid_enum_cast)
const b: Foo = @enumFromInt(a);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x10335f9 in posixCallMainAndExit (runtime_invalid_enum_cast)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033161 in _start (runtime_invalid_enum_cast)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Invalid Error Set Cast
At compile-time:
test_comptime_invalid_error_set_cast.zig
const Set1 = error{
A,
B,
};
const Set2 = error{
A,
C,
};
comptime {
_ = @as(Set2, @errorCast(Set1.B));
}
Shell
$ zig test test_comptime_invalid_error_set_cast.zig
docgen_tmp/test_comptime_invalid_error_set_cast.zig:10:19: error: 'error.B' not a member of error set 'error{A,C}'
_ = @as(Set2, @errorCast(Set1.B));
^~~~~~~~~~~~~~~~~~
At runtime:
runtime_invalid_error_set_cast.zig
const std = @import("std");
const Set1 = error{
A,
B,
};
const Set2 = error{
A,
C,
};
pub fn main() void {
foo(Set1.B);
}
fn foo(set1: Set1) void {
const x: Set2 = @errorCast(set1);
std.debug.print("value: {}\n", .{x});
}
Shell
$ zig build-exe runtime_invalid_error_set_cast.zig
$ ./runtime_invalid_error_set_cast
thread 991250 panic: invalid error code
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_error_set_cast.zig:15:21: 0x1035e37 in foo (runtime_invalid_error_set_cast)
const x: Set2 = @errorCast(set1);
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_error_set_cast.zig:12:8: 0x1033d7d in main (runtime_invalid_error_set_cast)
foo(Set1.B);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033629 in posixCallMainAndExit (runtime_invalid_error_set_cast)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033191 in _start (runtime_invalid_error_set_cast)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Incorrect Pointer Alignment
At compile-time:
test_comptime_incorrect_pointer_alignment.zig
comptime {
const ptr: *align(1) i32 = @ptrFromInt(0x1);
const aligned: *align(4) i32 = @alignCast(ptr);
_ = aligned;
}
Shell
$ zig test test_comptime_incorrect_pointer_alignment.zig
docgen_tmp/test_comptime_incorrect_pointer_alignment.zig:3:47: error: pointer address 0x1 is not aligned to 4 bytes
const aligned: *align(4) i32 = @alignCast(ptr);
^~~
At runtime:
runtime_incorrect_pointer_alignment.zig
const mem = @import("std").mem;
pub fn main() !void {
var array align(4) = [_]u32{ 0x11111111, 0x11111111 };
const bytes = mem.sliceAsBytes(array[0..]);
if (foo(bytes) != 0x11111111) return error.Wrong;
}
fn foo(bytes: []u8) u32 {
const slice4 = bytes[1..5];
const int_slice = mem.bytesAsSlice(u32, @as([]align(4) u8, @alignCast(slice4)));
return int_slice[0];
}
Shell
$ zig build-exe runtime_incorrect_pointer_alignment.zig
$ ./runtime_incorrect_pointer_alignment
thread 991290 panic: incorrect alignment
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_incorrect_pointer_alignment.zig:9:64: 0x1033a7a in foo (runtime_incorrect_pointer_alignment)
const int_slice = mem.bytesAsSlice(u32, @as([]align(4) u8, @alignCast(slice4)));
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_incorrect_pointer_alignment.zig:5:12: 0x1033937 in main (runtime_incorrect_pointer_alignment)
if (foo(bytes) != 0x11111111) return error.Wrong;
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:511:37: 0x1033835 in posixCallMainAndExit (runtime_incorrect_pointer_alignment)
const result = root.main() catch |err| {
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1033351 in _start (runtime_incorrect_pointer_alignment)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)
Wrong Union Field Access
At compile-time:
test_comptime_wrong_union_field_access.zig
comptime {
var f = Foo{ .int = 42 };
f.float = 12.34;
}
const Foo = union {
float: f32,
int: u32,
};
Shell
$ zig test test_comptime_wrong_union_field_access.zig
docgen_tmp/test_comptime_wrong_union_field_access.zig:3:6: error: access of union field 'float' while field 'int' is active
f.float = 12.34;
~^~~~~~
docgen_tmp/test_comptime_wrong_union_field_access.zig:6:13: note: union declared here
const Foo = union {
^~~~~
At runtime:
runtime_wrong_union_field_access.zig
const std = @import("std");
const Foo = union {
float: f32,
int: u32,
};
pub fn main() void {
var f = Foo{ .int = 42 };
bar(&f);
}
fn bar(f: *Foo) void {
f.float = 12.34;
std.debug.print("value: {}\n", .{f.float});
}
Shell
$ zig build-exe runtime_wrong_union_field_access.zig
$ ./runtime_wrong_union_field_access
thread 991330 panic: access of union field 'float' while field 'int' is active
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_wrong_union_field_access.zig:14:6: 0x103b7c0 in bar (runtime_wrong_union_field_access)
f.float = 12.34;
^
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_wrong_union_field_access.zig:10:8: 0x103971c in main (runtime_wrong_union_field_access)
bar(&f);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1038fb9 in posixCallMainAndExit (runtime_wrong_union_field_access)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1038b21 in _start (runtime_wrong_union_field_access)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(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
const std = @import("std");
const Foo = union {
float: f32,
int: u32,
};
pub fn main() void {
var f = Foo{ .int = 42 };
bar(&f);
}
fn bar(f: *Foo) void {
f.* = Foo{ .float = 12.34 };
std.debug.print("value: {}\n", .{f.float});
}
Shell
$ zig build-exe change_active_union_field.zig
$ ./change_active_union_field
value: 1.234e1
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
const std = @import("std");
const Foo = union {
float: f32,
int: u32,
};
pub fn main() void {
var f = Foo{ .int = 42 };
f = Foo{ .float = undefined };
bar(&f);
std.debug.print("value: {}\n", .{f.float});
}
fn bar(f: *Foo) void {
f.float = 12.34;
}
Shell
$ zig build-exe undefined_active_union_field.zig
$ ./undefined_active_union_field
value: 1.234e1
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
comptime {
const float: f32 = 4294967296;
const int: i32 = @intFromFloat(float);
_ = int;
}
Shell
$ zig test test_comptime_out_of_bounds_float_to_integer_cast.zig
docgen_tmp/test_comptime_out_of_bounds_float_to_integer_cast.zig:3:36: error: float value '4294967296' cannot be stored in integer type 'i32'
const int: i32 = @intFromFloat(float);
^~~~~
At runtime:
runtime_out_of_bounds_float_to_integer_cast.zig
pub fn main() void {
var float: f32 = 4294967296; // runtime-known
_ = &float;
const int: i32 = @intFromFloat(float);
_ = int;
}
Shell
$ zig build-exe runtime_out_of_bounds_float_to_integer_cast.zig
$ ./runtime_out_of_bounds_float_to_integer_cast
thread 991424 panic: integer part of floating point value out of bounds
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_out_of_bounds_float_to_integer_cast.zig:4:22: 0x1033c49 in main (runtime_out_of_bounds_float_to_integer_cast)
const int: i32 = @intFromFloat(float);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033489 in posixCallMainAndExit (runtime_out_of_bounds_float_to_integer_cast)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1032ff1 in _start (runtime_out_of_bounds_float_to_integer_cast)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(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
comptime {
const opt_ptr: ?*i32 = null;
const ptr: *i32 = @ptrCast(opt_ptr);
_ = ptr;
}
Shell
$ zig test test_comptime_invalid_null_pointer_cast.zig
docgen_tmp/test_comptime_invalid_null_pointer_cast.zig:3:32: error: null pointer casted to type '*i32'
const ptr: *i32 = @ptrCast(opt_ptr);
^~~~~~~
At runtime:
runtime_invalid_null_pointer_cast.zig
pub fn main() void {
var opt_ptr: ?*i32 = null;
_ = &opt_ptr;
const ptr: *i32 = @ptrCast(opt_ptr);
_ = ptr;
}
Shell
$ zig build-exe runtime_invalid_null_pointer_cast.zig
$ ./runtime_invalid_null_pointer_cast
thread 991464 panic: cast causes pointer to be null
/home/ci/actions-runner/_work/zig-bootstrap/zig/docgen_tmp/runtime_invalid_null_pointer_cast.zig:4:23: 0x1033bfc in main (runtime_invalid_null_pointer_cast)
const ptr: *i32 = @ptrCast(opt_ptr);
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:501:22: 0x1033469 in posixCallMainAndExit (runtime_invalid_null_pointer_cast)
root.main();
^
/home/ci/actions-runner/_work/zig-bootstrap/out/host/lib/zig/std/start.zig:253:5: 0x1032fd1 in _start (runtime_invalid_null_pointer_cast)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
(process terminated by signal)