I am doing this year’s AoC with zig (again). For the first time I have noticed errors when running my code with the self-hosted compiler, which disappear when running with -OReleaseFast (which, I understand, uses the LLVM-based compiler). Two examples so far:
thread 413132 panic: reached unreachable code
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/debug.zig:559:14: 0x1044179 in assert (std.zig)
if (!ok) unreachable; // assertion failure
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/debug.zig:1735:15: 0x10ba133 in lock (std.zig)
assert(l.state == .unlocked);
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/hash_map.zig:1113:44: 0x1150ca5 in getOrPutContextAdapted__anon_23417 (std.zig)
self.pointer_stability.lock();
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/hash_map.zig:1100:56: 0x114836d in getOrPutContext (std.zig)
const gop = try self.getOrPutContextAdapted(allocator, key, ctx, ctx);
and
thread 413162 panic: integer overflow
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/mem.zig:4357:61: 0x114b27c in sliceAsBytes__anon_23281 (std.zig)
return @as(cast_target, @ptrCast(slice))[0 .. slice.len * @sizeOf(std.meta.Elem(Slice))];
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/mem/Allocator.zig:351:40: 0x11574b9 in remap__anon_23771 (std.zig)
const old_memory = mem.sliceAsBytes(allocation);
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/array_list.zig:1227:26: 0x11530d5 in ensureTotalCapacityPrecise (std.zig)
if (gpa.remap(old_memory, new_capacity)) |new_memory| {
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/array_list.zig:1207:51: 0x114ab35 in ensureTotalCapacity (std.zig)
return self.ensureTotalCapacityPrecise(gpa, growCapacity(self.capacity, new_capacity));
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/array_list.zig:1261:41: 0x1147cdb in addOne (std.zig)
try self.ensureTotalCapacity(gpa, newlen);
^
/home/gonzo/.local/share/mise/installs/zig/0.15.2/lib/std/array_list.zig:894:49: 0x1143dad in append (std.zig)
const new_item_ptr = try self.addOne(gpa);
Are these known regressions, or should I make an effort to open issues for them?
This is not a difference between LLVM and the self-hosted backends. Both of these errors are results of runtime safety checks, which are present in Debug and ReleaseSafe, but in ReleaseFast and ReleaseSmall they result in undefined/illegal behavior instead.
I.e. in Debug and ReleaseSafe you get these crashes, but in ReleaseFast and ReleaseSmall the compiler assumes your program is written so that the checked behavior never happens and uses that as information for optimizations.
I have been looking into this, and your suggestion seems correct. But now I am having all kinds of existential doubts… For the longest time, when I have needed to write a struct which contais a list, I would do something like this:
But now I notice that this works correctly in ReleaseFast but not in Debug: the list seems to never be properly initialized; calling add does not change the list. Even more, if I create a Module and try to print the list size right away, it returns 0xaaaaaaaaaaaaaaaa – clearly undefined.
This is obviously my mistake, and I’m sure a really basic one – how should is this done correctly with zig 0.15.2?
The code you posted looks correct to me. You can always double check whether the issue also occurs with an equivalent LLVM build by passing -fllvm to the compiler.