zig icon indicating copy to clipboard operation
zig copied to clipboard

llvm backend panic when using tagged union backed by enum with negative values

Open jonathanderque opened this issue 1 year ago • 4 comments

Zig Version

0.12.0

Steps to Reproduce and Observed Behavior

Running the following code with zig 0.12.0 leads to "panic: switch on corrupt value" while the code runs fine with 0.11.0 (tested on linux x86_64):

const std = @import("std");

const RoomTitle = struct {
    delay: f32 = 0,

    fn init(self: *RoomTitle) void {
        _ = self;
    }
};

const EntityType = enum(i8) {
    room_title = -1,
};

const Entity = union(EntityType) {
    room_title: RoomTitle,
};

pub fn main() void {
    var rt: RoomTitle = RoomTitle{};
    rt.init();
    const e = Entity{ .room_title = rt };

    // zig v0.12.0 -> panic: switch on corrupt value
    switch (e) {
        else => {
            std.log.debug("ok", .{});
        },
    }
}

[jo@norfair celeste_clazzig]$ zig run src/celeste.zig
thread 44163 panic: switch on corrupt value
/home/jo/sandbox/celeste/celeste_clazzig/src/celeste.zig:25:13: 0x1033e6d in main (celeste)
    switch (e) {
            ^
/nix/store/mq5vacngyamayigxiz5rfamlnyjpr49b-zig-0.12.0/lib/std/start.zig:501:22: 0x10336c9 in posixCallMainAndExit (celeste)
            root.main();
                     ^
/nix/store/mq5vacngyamayigxiz5rfamlnyjpr49b-zig-0.12.0/lib/std/start.zig:253:5: 0x1033231 in _start (celeste)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x0 in ??? (???)
Aborted (core dumped)

Expected Behavior

Same behaviour as zig 0.11.0 - no crash.

jonathanderque avatar Apr 27 '24 08:04 jonathanderque

This can also be replicated with the latest nightly: 0.13.0-dev.46+3648d7df1 The first nightly release to have this issue seems to be: 0.12.0-dev.587+eb072fa52 0.12.0-dev.564+759b0fe00 is fine.

jonathanderque avatar Apr 27 '24 10:04 jonathanderque

After further bisecting, commit 09a57583a4 may be the first to introduce this issue, but reading this change and the associated commit message, I don't see an obvious link. I think I've reached the limit of what I can do to help here.

Here is the associated stack trace which for some reason, is rather different from what I got with the nightly builds:

[jo@norfair build]$ git rev-parse --short HEAD
09a57583a4
[jo@norfair build]$ ./stage3/bin/zig run ./celeste.zig
Semantic Analysis [116] thread 92227 panic: attempt to use null value
/home/jo/sandbox/zig/src/value.zig:560:40: 0xafa541 in toUnsignedInt (zig)
        return getUnsignedInt(val, mod).?;
                                       ^
/home/jo/sandbox/zig/src/codegen/llvm.zig:9792:49: 0x159bf64 in airUnionInit (zig)
            break :blk tag_int_val.toUnsignedInt(mod);
                                                ^
/home/jo/sandbox/zig/src/codegen/llvm.zig:4854:57: 0x10190a2 in genBody (zig)
                .union_init     => try self.airUnionInit(inst),
                                                        ^
/home/jo/sandbox/zig/src/codegen/llvm.zig:1625:19: 0x10116ec in updateFunc (zig)
        fg.genBody(air.getMainBody()) catch |err| switch (err) {
                  ^
/home/jo/sandbox/zig/src/link/Elf.zig:2738:70: 0x101c3d9 in updateFunc (zig)
    if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
                                                                     ^
/home/jo/sandbox/zig/src/link.zig:594:77: 0xd14e18 in updateFunc (zig)
            .elf   => return @fieldParentPtr(Elf,   "base", base).updateFunc(module, func_index, air, liveness),
                                                                            ^
/home/jo/sandbox/zig/src/Module.zig:3508:37: 0xae00aa in ensureFuncBodyAnalyzed (zig)
            comp.bin_file.updateFunc(mod, func_index, air, liveness) catch |err| switch (err) {
                                    ^
/home/jo/sandbox/zig/src/Compilation.zig:3370:42: 0xadd74d in processOneJob (zig)
            module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
                                         ^
/home/jo/sandbox/zig/src/Compilation.zig:3307:30: 0x94a2cb in performAllTheWork (zig)
            try processOneJob(comp, work_item, main_progress_node);
                             ^
/home/jo/sandbox/zig/src/Compilation.zig:2184:31: 0x94585c in update (zig)
    try comp.performAllTheWork(main_progress_node);
                              ^
/home/jo/sandbox/zig/src/main.zig:4159:24: 0x975d70 in updateModule (zig)
        try comp.update(main_progress_node);
                       ^
/home/jo/sandbox/zig/src/main.zig:3580:17: 0x999388 in buildOutputType (zig)
    updateModule(comp) catch |err| switch (err) {
                ^
/home/jo/sandbox/zig/src/main.zig:278:31: 0x7ef32f in mainArgs (zig)
        return buildOutputType(gpa, arena, args, .run);
                              ^
/home/jo/sandbox/zig/src/main.zig:214:20: 0x7ec2b5 in main (zig)
    return mainArgs(gpa, arena, args);
                   ^
/home/jo/sandbox/zig/lib/std/start.zig:486:37: 0x7ebcce in main (zig)
    std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@as(usize, @intCast(c_argc))];
                                    ^
???:?:?: 0x7744fbe43ccf in ??? (libc.so.6)
Unwind information for `libc.so.6:0x7744fbe43ccf` was not available, trace may be incomplete

Aborted (core dumped)

jonathanderque avatar Apr 27 '24 14:04 jonathanderque

It seems like the issue occurs when the enum type is signed and the sign-bit of the value is on. I'm guessing that the discrepancy in errors is due to safety checks present in debug builds of the compiler, causing a panic at compile-time instead of runtime.

Parzival-3141 avatar Apr 27 '24 23:04 Parzival-3141

The minimal reproducible code is as follows in c231d94960ec2cecbea0de877f645ba5d439fd13:

const std = @import("std");

const EntityType = enum(i8) {
    room_title = -1, // negative
};

const Entity = union(EntityType) {
    room_title: i32,
};

pub fn main() void {
    var rt: i32 = 0;
    rt = rt; // for 'var' declare is work, if use `const` the example build success.
    const e = Entity{ .room_title = rt };
    _ = e;
}

If using 0.13.0-dev.46+3648d7df1, you must add switch to trigger a crash at runtime.

zhylmzr avatar Apr 28 '24 06:04 zhylmzr