Strange behavior with comptime

The following program crashes with a SIGABRT when executing (it compiles correctly):

const std = @import("std");
const SIZEX = 6;
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    const indexes = init: {
        comptime var t: [SIZEX]usize = undefined;
        for (t) |*b, ix| {
            b.* = ix;
        }
        break :init t;
    };
    try stdout.print("{d}\n", .{indexes[0]});
}

but the program works if I suppress the comptime qualifier.
I am quite new to zig, and I am surprised by a behaviour. Why is it crashing, and if it has to crash, why the compiler doesn’t detect the problem (the code is not exactly that complex).
Thanks

Usually when you get crashes with seg faults or the like, it means you’re compiling straight to release mode, which removes a lot of useful checks and information for debugging. You should try compilig in debug mode to see what errors you get. In this case though, I tried your code and all I get is a cryptic Bus error at address.. error, so that doesn’t help much. I did get it working just by moving the comptime keyword to before the init:, making the whole block comptime instead of just the var.

This error can happen on some architectures in case of unaligned access.

I don’t think there is any possible unaligned access on current x86_64 architecture. Looks just like the compiler is heavily bugged and the language not mature enough to be evan useful for elementary applications. Thanks to both of you however for trying. (BTW: I tested the code both in release and debug mode, and with two versions of the compiler 0.10.0 and the “nightly” branch). Thanks again.

On x86_64 the example crashes at b.* = ix; with segfault:

$ ./486 
Segmentation fault at address 0x201828
./486.zig:9:13: 0x20ff5a in main (486)
            b.* = ix;
            ^
/opt/zig-0.10/lib/std/start.zig:606:37: 0x20fa5e in posixCallMainAndExit (486)
            const result = root.main() catch |err| {
                                    ^
/opt/zig-0.10/lib/std/start.zig:368:5: 0x20f4d1 in _start (486)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});

Compare the faulty address with the address when comptime removed (I added std.debug.print("{*}\n", .{&indexes}); at the end of the main()):

$ ./486 
0
[6]usize@7ffe31c29f80

The array is located on the stack, but with comptime it is located somewhere else (BSS?)…

If I understand correctly what the manual says, comptime variable at computed at compile time and statically stored in the Data Segment of the compiled code while without comptime they are computed at run time and stored in the stack. My question was mainly if I, as a beginner, had made a major mistake. Looks like the mistake is in the compiler…
Thanks.

But note that faulty address (0x201828) is lower than addresses inside the code segment (0x20f4d1…).

I have been learning Zig for ~ 3 months, so I am more a beginner too, but this really looks as a compiler bug for me also. There are a lot of issues, you can add another one :slight_smile: .

The reason this crashes is that comptime values are not modifiable at runtime (in an ELF binary, their symbols will go in the .rodata section), but the for loop that modifies the value of t tries to use it in a runtime context. Change it to inline for to have it unrolled and evaluated at compile time, and it will work.

Yes, Zig should warn about this. The stage1/C++ compiler doesn’t do this, perhaps the stage2/self-hosted compiler will, but I haven’t tried that.

1 Like

Thanks, it is much clearer. Now that I understand the problem, I found another solution which is to wrap the right hand declaration of indexes with comptime (i.e. const indexes = comptime init:{… )
Thanks again.