zig icon indicating copy to clipboard operation
zig copied to clipboard

x86_64 backend crashes on returning packed struct containing zero-sized enum

Open davnavr opened this issue 2 weeks ago • 2 comments

Zig Version

0.16.0-dev.1234+74900e938

Steps to Reproduce and Observed Behavior

Attempting to compile the following program with the x86-64 backend targeting x86_64-linux results in a SIGSEGV:

const Zero = enum(u0) { my_zero };

const MyStruct = packed struct(u32) {
    value: u32,
    zst: Zero,
};

pub fn crasher(a: u32, zst: Zero) MyStruct {
    return MyStruct{
        .value = a,
        .zst = zst,
    };
}

pub fn main() !void {
    const result = crasher(5, .my_zero);
    std.debug.print("{}", .{result.value});
}

const std = @import("std");

Doing the same on Zig version 0.15.1 actually results in a compilation error instead:

src/main.zig:8:5: error: emit MIR failed: InvalidInstruction (Zig compiler bug)
pub fn crasher(a: u32, zst: Zero) MyStruct {
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: error(x86_64_encoder): no encoding found for: none mov m256 imm8s none none

Oddly enough, this compiles and runs successfully when targeting x86_64-windows.

Expected Behavior

The program should successfully compile and print 5 when run, or at least display an error message describing why compilation failed.

Workarounds

Use the LLVM backend instead or do not use zero-sized types.

davnavr avatar Nov 07 '25 01:11 davnavr

Stack trace:

❯ zig4 build-exe test.zig
Compiler crash context:
Generating function 'test.crasher'

thread 90926 panic: reached unreachable code
/home/alexrp/Source/ziglang/zig/lib/std/debug.zig:416:14: 0x1c9d6c9 in assert (std.zig)
    if (!ok) unreachable; // assertion failure
             ^
/home/alexrp/Source/ziglang/zig/lib/std/math.zig:1123:11: 0x2872b60 in isPowerOfTwo__anon_249367 (std.zig)
    assert(int > 0);
          ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:174053:34: 0x3a75b3e in allocRegOrMemAdvanced (main.zig)
        if (std.math.isPowerOfTwo(abi_size) and abi_size <= @as(u32, max_abi_size: switch (ty.zigTypeTag(zcu)) {
                                 ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:174038:38: 0x3a7629a in allocRegOrMem (main.zig)
    return self.allocRegOrMemAdvanced(self.typeOfIndex(inst), inst, reg_ok);
                                     ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:179397:51: 0x4efc8b4 in airBitCast (main.zig)
            const dst_mcv = try self.allocRegOrMem(inst, true);
                                                  ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:67355:42: 0x4f551ae in genBody (main.zig)
            .bitcast => try cg.airBitCast(inst),
                                         ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:176497:21: 0x4f01b8d in lowerBlock (main.zig)
    try self.genBody(body);
                    ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:67360:34: 0x4f554e9 in genBody (main.zig)
                try cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[block.end..][0..block.data.body_len]));
                                 ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:176497:21: 0x4f01b8d in lowerBlock (main.zig)
    try self.genBody(body);
                    ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:67360:34: 0x4f554e9 in genBody (main.zig)
                try cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[block.end..][0..block.data.body_len]));
                                 ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:2269:19: 0x47f7b2d in genMainBody (main.zig)
    try cg.genBody(main_body[air_arg_count..]);
                  ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:2065:29: 0x402dce8 in gen (main.zig)
        try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count);
                            ^
/home/alexrp/Source/ziglang/zig/src/codegen/x86_64/CodeGen.zig:991:17: 0x38f0650 in generate (main.zig)
    function.gen(&file.zir.?, func_zir.inst, func.comptime_args, call_info.air_arg_count) catch |err| switch (err) {
                ^
/home/alexrp/Source/ziglang/zig/src/codegen.zig:163:45: 0x2ec6337 in generateFunction (main.zig)
            const mir = try CodeGen.generate(lf, pt, src_loc, func_index, air, liveness);
                                            ^
/home/alexrp/Source/ziglang/zig/src/Zcu/PerThread.zig:4522:36: 0x2922aaa in runCodegenInner (main.zig)
    return codegen.generateFunction(lf, pt, zcu.navSrcLoc(nav), func_index, air, &liveness) catch |err| switch (err) {
                                   ^
/home/alexrp/Source/ziglang/zig/src/Zcu/PerThread.zig:4400:46: 0x243605f in runCodegen (main.zig)
    const success: bool = if (runCodegenInner(pt, func_index, air)) |mir| success: {
                                             ^
/home/alexrp/Source/ziglang/zig/src/Compilation.zig:5881:18: 0x2911cee in workerZcuCodegen (main.zig)
    pt.runCodegen(func_index, &air, out);
                 ^
/home/alexrp/Source/ziglang/zig/lib/std/Thread/Pool.zig:180:50: 0x2911fbd in runFn (std.zig)
            @call(.auto, func, .{id.?} ++ closure.arguments);
                                                 ^
/home/alexrp/Source/ziglang/zig/lib/std/Thread/Pool.zig:293:27: 0x2397630 in worker (std.zig)
            runnable.runFn(runnable, id);
                          ^
/home/alexrp/Source/ziglang/zig/lib/std/Thread.zig:558:13: 0x21c7a20 in callFn__anon_196835 (std.zig)
            @call(.auto, f, args);
            ^
/home/alexrp/Source/ziglang/zig/lib/std/Thread.zig:830:30: 0x205f149 in entryFn (std.zig)
                return callFn(f, args_ptr.*);
                             ^
./nptl/pthread_create.c:448:8: 0x74e21c0a27f0 in start_thread (pthread_create.c)
../sysdeps/unix/sysv/linux/x86_64/clone3.S:78:0: 0x74e21c133b5b in __GI___clone3 (../sysdeps/unix/sysv/linux/x86_64/clone3.S)
fish: Job 1, 'zig4 build-exe test.zig' terminated by signal SIGABRT (Abort)

Unsure if frontend or backend bug; labeling as the latter for now.

alexrp avatar Nov 07 '25 01:11 alexrp

%16 = bitcast(u0, <repro.Zero, .my_zero>)

jacobly0 avatar Nov 07 '25 13:11 jacobly0