- 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
- Slice Widen 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 build mode disables all safety checks in order to facilitate optimizations.
When a safety check fails, Zig crashes with a stack trace, like this:
test.zig
test "safety check" {
unreachable;
}
$ zig test test.zig
Test 1/1 safety check...reached unreachable code
/home/andy/dev/zig/docgen_tmp/test.zig:2:5: 0x2040d7 in ??? (test)
unreachable;
^
/home/andy/dev/zig/build/lib/zig/std/special/test_runner.zig:13:25: 0x225bab in ??? (test)
if (test_fn.func()) |_| {
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:122:22: 0x225336 in ??? (test)
root.main() catch |err| {
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x2250a1 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Tests failed. Use the following command to reproduce the failure:
/home/andy/dev/zig/docgen_tmp/test
Reaching Unreachable Code
At compile-time:
test.zig
comptime {
assert(false);
}
fn assert(ok: bool) void {
if (!ok) unreachable; // assertion failure
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:5:14: error: unable to evaluate constant expression
if (!ok) unreachable; // assertion failure
^
/home/andy/dev/zig/docgen_tmp/test.zig:2:11: note: called from here
assert(false);
^
/home/andy/dev/zig/docgen_tmp/test.zig:1:10: note: called from here
comptime {
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
std.debug.assert(false);
}
$ zig build-exe test.zig
$ ./test
reached unreachable code
/home/andy/dev/zig/build/lib/zig/std/debug.zig:169:14: 0x20402c in ??? (test)
if (!ok) unreachable; // assertion failure
^
/home/andy/dev/zig/docgen_tmp/test.zig:4:21: 0x22581b in ??? (test)
std.debug.assert(false);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Index out of Bounds
At compile-time:
test.zig
comptime {
const array = "hello";
const garbage = array[5];
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:26: error: index 5 outside array of size 5
const garbage = array[5];
^
At runtime:
test.zig
pub fn main() void {
var x = foo("hello");
}
fn foo(x: []const u8) u8 {
return x[5];
}
$ zig build-exe test.zig
$ ./test
index out of bounds
/home/andy/dev/zig/docgen_tmp/test.zig:6:13: 0x22585a in ??? (test)
return x[5];
^
/home/andy/dev/zig/docgen_tmp/test.zig:2:16: 0x225827 in ??? (test)
var x = foo("hello");
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Cast Negative Number to Unsigned Integer
At compile-time:
test.zig
comptime {
const value: i32 = -1;
const unsigned = @intCast(u32, value);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'
const unsigned = @intCast(u32, value);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var value: i32 = -1;
var unsigned = @intCast(u32, value);
std.debug.warn("value: {}\n", unsigned);
}
$ zig build-exe test.zig
$ ./test
attempt to cast negative value to unsigned integer
/home/andy/dev/zig/docgen_tmp/test.zig:5:20: 0x225851 in ??? (test)
var unsigned = @intCast(u32, value);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
To obtain the maximum value of an unsigned integer, use std.math.maxInt
.
Cast Truncates Data
At compile-time:
test.zig
comptime {
const spartan_count: u16 = 300;
const byte = @intCast(u8, spartan_count);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'
const byte = @intCast(u8, spartan_count);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var spartan_count: u16 = 300;
const byte = @intCast(u8, spartan_count);
std.debug.warn("value: {}\n", byte);
}
$ zig build-exe test.zig
$ ./test
integer cast truncated bits
/home/andy/dev/zig/docgen_tmp/test.zig:5:18: 0x22585a in ??? (test)
const byte = @intCast(u8, spartan_count);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
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.zig
comptime {
var byte: u8 = 255;
byte += 1;
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:10: error: operation caused overflow
byte += 1;
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var byte: u8 = 255;
byte += 1;
std.debug.warn("value: {}\n", byte);
}
$ zig build-exe test.zig
$ ./test
integer overflow
/home/andy/dev/zig/docgen_tmp/test.zig:5:10: 0x225841 in ??? (test)
byte += 1;
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
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:
test.zig
const math = @import("std").math;
const warn = @import("std").debug.warn;
pub fn main() !void {
var byte: u8 = 255;
byte = if (math.add(u8, byte, 1)) |result| result else |err| {
warn("unable to add one: {}\n", @errorName(err));
return err;
};
warn("result: {}\n", byte);
}
$ zig build-exe test.zig
$ ./test
unable to add one: Overflow
error: Overflow
/home/andy/dev/zig/build/lib/zig/std/math.zig:268:5: 0x225c4e in ??? (test)
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
^
/home/andy/dev/zig/docgen_tmp/test.zig:8:9: 0x225a3e in ??? (test)
return err;
^
Builtin Overflow Functions
These builtins return a bool
of whether or not overflow occurred, as well as returning the overflowed bits:
Example of @addWithOverflow:
test.zig
const warn = @import("std").debug.warn;
pub fn main() void {
var byte: u8 = 255;
var result: u8 = undefined;
if (@addWithOverflow(u8, byte, 10, &result)) {
warn("overflowed result: {}\n", result);
} else {
warn("result: {}\n", result);
}
}
$ zig build-exe test.zig
$ ./test
overflowed result: 9
Wrapping Operations
These operations have guaranteed wraparound semantics.
+%
(wraparound addition)-%
(wraparound subtraction)-%
(wraparound negation)*%
(wraparound multiplication)
test.zig
const std = @import("std");
const assert = std.debug.assert;
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;
assert(min_val == minInt(i32));
const max_val = min_val -% 1;
assert(max_val == maxInt(i32));
}
$ zig test test.zig
Test 1/1 wraparound addition and subtraction...OK
All tests passed.
Exact Left Shift Overflow
At compile-time:
test.zig
comptime {
const x = @shlExact(u8(0b01010101), 2);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:2:15: error: operation caused overflow
const x = @shlExact(u8(0b01010101), 2);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var x: u8 = 0b01010101;
var y = @shlExact(x, 2);
std.debug.warn("value: {}\n", y);
}
$ zig build-exe test.zig
$ ./test
left shift overflowed bits
/home/andy/dev/zig/docgen_tmp/test.zig:5:13: 0x225858 in ??? (test)
var y = @shlExact(x, 2);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Exact Right Shift Overflow
At compile-time:
test.zig
comptime {
const x = @shrExact(u8(0b10101010), 2);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:2:15: error: exact shift shifted out 1 bits
const x = @shrExact(u8(0b10101010), 2);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var x: u8 = 0b10101010;
var y = @shrExact(x, 2);
std.debug.warn("value: {}\n", y);
}
$ zig build-exe test.zig
$ ./test
right shift overflowed bits
/home/andy/dev/zig/docgen_tmp/test.zig:5:13: 0x225858 in ??? (test)
var y = @shrExact(x, 2);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Division by Zero
At compile-time:
test.zig
comptime {
const a: i32 = 1;
const b: i32 = 0;
const c = a / b;
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:4:17: error: division by zero
const c = a / b;
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var a: u32 = 1;
var b: u32 = 0;
var c = a / b;
std.debug.warn("value: {}\n", c);
}
$ zig build-exe test.zig
$ ./test
division by zero
/home/andy/dev/zig/docgen_tmp/test.zig:6:15: 0x22584a in ??? (test)
var c = a / b;
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Remainder Division by Zero
At compile-time:
test.zig
comptime {
const a: i32 = 10;
const b: i32 = 0;
const c = a % b;
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:4:17: error: division by zero
const c = a % b;
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var a: u32 = 10;
var b: u32 = 0;
var c = a % b;
std.debug.warn("value: {}\n", c);
}
$ zig build-exe test.zig
$ ./test
remainder division by zero or negative value
/home/andy/dev/zig/docgen_tmp/test.zig:6:15: 0x225865 in ??? (test)
var c = a % b;
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Exact Division Remainder
At compile-time:
test.zig
comptime {
const a: u32 = 10;
const b: u32 = 3;
const c = @divExact(a, b);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:4:15: error: exact division had a remainder
const c = @divExact(a, b);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var a: u32 = 10;
var b: u32 = 3;
var c = @divExact(a, b);
std.debug.warn("value: {}\n", c);
}
$ zig build-exe test.zig
$ ./test
exact division produced remainder
/home/andy/dev/zig/docgen_tmp/test.zig:6:13: 0x225887 in ??? (test)
var c = @divExact(a, b);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Slice Widen Remainder
At compile-time:
test.zig
comptime {
var bytes = [5]u8{ 1, 2, 3, 4, 5 };
var slice = @bytesToSlice(u32, bytes);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:17: error: unable to convert [5]u8 to []align(1) const u32: size mismatch
var slice = @bytesToSlice(u32, bytes);
^
/home/andy/dev/zig/docgen_tmp/test.zig:3:31: note: u32 has size 4; remaining bytes: 1
var slice = @bytesToSlice(u32, bytes);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var bytes = [5]u8{ 1, 2, 3, 4, 5 };
var slice = @bytesToSlice(u32, bytes[0..]);
std.debug.warn("value: {}\n", slice[0]);
}
$ zig build-exe test.zig
$ ./test
slice widening size mismatch
/home/andy/dev/zig/docgen_tmp/test.zig:5:17: 0x2258ae in ??? (test)
var slice = @bytesToSlice(u32, bytes[0..]);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Attempt to Unwrap Null
At compile-time:
test.zig
comptime {
const optional_number: ?i32 = null;
const number = optional_number.?;
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:35: error: unable to unwrap null
const number = optional_number.?;
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var optional_number: ?i32 = null;
var number = optional_number.?;
std.debug.warn("value: {}\n", number);
}
$ zig build-exe test.zig
$ ./test
attempt to unwrap null
/home/andy/dev/zig/docgen_tmp/test.zig:5:33: 0x225853 in ??? (test)
var number = optional_number.?;
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
One way to avoid this crash is to test for null instead of assuming non-null, with the if
expression:
test.zig
const warn = @import("std").debug.warn;
pub fn main() void {
const optional_number: ?i32 = null;
if (optional_number) |number| {
warn("got number: {}\n", number);
} else {
warn("it's null\n");
}
}
$ zig build-exe test.zig
$ ./test
it's null
See also:
Attempt to Unwrap Error
At compile-time:
test.zig
comptime {
const number = getNumberOrFail() catch unreachable;
}
fn getNumberOrFail() !i32 {
return error.UnableToReturnNumber;
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:2:38: error: caught unexpected error 'UnableToReturnNumber'
const number = getNumberOrFail() catch unreachable;
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
const number = getNumberOrFail() catch unreachable;
std.debug.warn("value: {}\n", number);
}
fn getNumberOrFail() !i32 {
return error.UnableToReturnNumber;
}
$ zig build-exe test.zig
$ ./test
attempt to unwrap error: UnableToReturnNumber
/home/andy/dev/zig/docgen_tmp/test.zig:9:5: 0x2258bb in ??? (test)
return error.UnableToReturnNumber;
^
???:?:?: 0x225948 in ??? (???)
/home/andy/dev/zig/docgen_tmp/test.zig:4:38: 0x22587c in ??? (test)
const number = getNumberOrFail() catch unreachable;
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
One way to avoid this crash is to test for an error instead of assuming a successful result, with the if
expression:
test.zig
const warn = @import("std").debug.warn;
pub fn main() void {
const result = getNumberOrFail();
if (result) |number| {
warn("got number: {}\n", number);
} else |err| {
warn("got error: {}\n", @errorName(err));
}
}
fn getNumberOrFail() !i32 {
return error.UnableToReturnNumber;
}
$ zig build-exe test.zig
$ ./test
got error: UnableToReturnNumber
See also:
Invalid Error Code
At compile-time:
test.zig
comptime {
const err = error.AnError;
const number = @errorToInt(err) + 10;
const invalid_err = @intToError(number);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:4:25: error: integer value 11 represents no error
const invalid_err = @intToError(number);
^
At runtime:
test.zig
const std = @import("std");
pub fn main() void {
var err = error.AnError;
var number = @errorToInt(err) + 500;
var invalid_err = @intToError(number);
std.debug.warn("value: {}\n", number);
}
$ zig build-exe test.zig
$ ./test
invalid error code
/home/andy/dev/zig/docgen_tmp/test.zig:6:23: 0x22586d in ??? (test)
var invalid_err = @intToError(number);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Invalid Enum Cast
At compile-time:
test.zig
const Foo = enum {
A,
B,
C,
};
comptime {
const a: u2 = 3;
const b = @intToEnum(Foo, a);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:8:15: error: enum 'Foo' has no tag matching integer value 3
const b = @intToEnum(Foo, a);
^
/home/andy/dev/zig/docgen_tmp/test.zig:1:13: note: 'Foo' declared here
const Foo = enum {
^
At runtime:
test.zig
const std = @import("std");
const Foo = enum {
A,
B,
C,
};
pub fn main() void {
var a: u2 = 3;
var b = @intToEnum(Foo, a);
std.debug.warn("value: {}\n", @tagName(b));
}
$ zig build-exe test.zig
$ ./test
invalid enum value
/home/andy/dev/zig/docgen_tmp/test.zig:11:13: 0x225850 in ??? (test)
var b = @intToEnum(Foo, a);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Invalid Error Set Cast
At compile-time:
test.zig
const Set1 = error{
A,
B,
};
const Set2 = error{
A,
C,
};
comptime {
_ = @errSetCast(Set2, Set1.B);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:10:9: error: error.B not a member of error set 'Set2'
_ = @errSetCast(Set2, Set1.B);
^
At runtime:
test.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 = @errSetCast(Set2, set1);
std.debug.warn("value: {}\n", x);
}
$ zig build-exe test.zig
$ ./test
invalid error code
/home/andy/dev/zig/docgen_tmp/test.zig:15:15: 0x225880 in ??? (test)
const x = @errSetCast(Set2, set1);
^
/home/andy/dev/zig/docgen_tmp/test.zig:12:8: 0x22581e in ??? (test)
foo(Set1.B);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Incorrect Pointer Alignment
At compile-time:
test.zig
comptime {
const ptr = @intToPtr(*i32, 0x1);
const aligned = @alignCast(4, ptr);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes
const aligned = @alignCast(4, ptr);
^
At runtime:
test.zig
pub fn main() !void {
var array align(4) = []u32{ 0x11111111, 0x11111111 };
const bytes = @sliceToBytes(array[0..]);
if (foo(bytes) != 0x11111111) return error.Wrong;
}
fn foo(bytes: []u8) u32 {
const slice4 = bytes[1..5];
const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
return int_slice[0];
}
$ zig build-exe test.zig
$ ./test
incorrect alignment
/home/andy/dev/zig/docgen_tmp/test.zig:8:56: 0x225be6 in ??? (test)
const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
^
/home/andy/dev/zig/docgen_tmp/test.zig:4:12: 0x225a22 in ??? (test)
if (foo(bytes) != 0x11111111) return error.Wrong;
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:122:22: 0x225316 in ??? (test)
root.main() catch |err| {
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Wrong Union Field Access
At compile-time:
test.zig
comptime {
var f = Foo{ .int = 42 };
f.float = 12.34;
}
const Foo = union {
float: f32,
int: u32,
};
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:6: error: accessing union field 'float' while field 'int' is set
f.float = 12.34;
^
At runtime:
test.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.warn("value: {}\n", f.float);
}
$ zig build-exe test.zig
$ ./test
access of inactive union field
/home/andy/dev/zig/docgen_tmp/test.zig:14:6: 0x22c88b in ??? (test)
f.float = 12.34;
^
/home/andy/dev/zig/docgen_tmp/test.zig:10:8: 0x22c82d in ??? (test)
bar(&f);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22c28b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x22c081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
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
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.warn("value: {}\n", f.float);
}
$ zig build-exe test.zig
$ ./test
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
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.warn("value: {}\n", f.float);
}
fn bar(f: *Foo) void {
f.float = 12.34;
}
$ zig build-exe test.zig
$ ./test
value: 1.23400001e+01
See also:
Out of Bounds Float to Integer Cast
TODO
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.zig
comptime {
const opt_ptr: ?*i32 = null;
const ptr = @ptrCast(*i32, opt_ptr);
}
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:3:17: error: null pointer casted to type '*i32'
const ptr = @ptrCast(*i32, opt_ptr);
^
At runtime:
test.zig
pub fn main() void {
var opt_ptr: ?*i32 = null;
var ptr = @ptrCast(*i32, opt_ptr);
}
$ zig build-exe test.zig
$ ./test
cast causes pointer to be null
/home/andy/dev/zig/docgen_tmp/test.zig:3:15: 0x225841 in ??? (test)
var ptr = @ptrCast(*i32, opt_ptr);
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (test)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^