ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.97k stars 2.55k forks source link

Compiler segfault - hit unreachable code at src/arch/x86_64/CodeGen.zig:19534:13 #21550

Open RetroDev256 opened 1 month ago

RetroDev256 commented 1 month ago

Zig Version

0.14.0-dev.1671+085cc54aa

Steps to Reproduce and Observed Behavior

Zig reduced main.zig reproduction: ```zig const fmt = struct { const Tokenizer = struct { const Self = @This(); source: []const u8, index: usize, fn nextUtf8(self: *Self) ?u21 { _ = self; @trap(); } pub const TokenizerError = error{}; const State = enum { start, }; pub fn next(self: *Self) TokenizerError!?Token { const start = self.index; state: switch (State.start) { .start => { const cp = self.nextUtf8() orelse { const end = self.index; return Token{ .string = self.source[start..end] }; }; switch (cp) { else => continue :state .start, } }, } } pub const Token = union(enum) { string: []const u8, }; }; pub fn format( writer: anytype, fmt2: []const u8, args: anytype, ) !void { _ = fmt2; var toker: Tokenizer = undefined; while (try toker.next()) |token| { switch (token) { .string => |string| { _ = writer; _ = string; }, } } _ = args; } }; pub fn main() !void { try fmt.format(undefined, "Hello, World!\n", .{}); } ```
Error trace from debug-built zig compiler: ``` ramen:[retrodev]:~/repos/Zig/hmmm$ ../zig-shishua/zig-out/bin/zig build install └─ install test └─ zig build-exe test Debug native failure error: thread 11287 panic: reached unreachable code Unwind error at address `exe:0x25711f3` (error.AddressOutOfRange), trace may be incomplete /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:19534:13: 0x3d84fe9 in registerAlias (main.zig) unreachable // should be comptime-known ^ /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:2767:58: 0x366e88d in allocRegOrMemAdvanced (main.zig) return MCValue{ .register = registerAlias(reg, abi_size) }; ^ /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:2735:38: 0x366ed84 in allocRegOrMem (main.zig) return self.allocRegOrMemAdvanced(self.typeOfIndex(inst), inst, reg_ok); ^ /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:13863:48: 0x47adc53 in airLoopSwitchBr (main.zig) const mat_cond = try self.allocRegOrMem(inst, true); ^ /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:2381:57: 0x47d6ad4 in genBody (main.zig) .loop_switch_br => try self.airLoopSwitchBr(inst), ^ /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:2029:25: 0x414c06d in gen (main.zig) try self.genBody(self.air.getMainBody()); ^ /home/retrodev/repos/Zig/zig-shishua/src/arch/x86_64/CodeGen.zig:929:17: 0x3a8caf4 in generate (main.zig) function.gen() catch |err| switch (err) { ^ /home/retrodev/repos/Zig/zig-shishua/src/codegen.zig:81:51: 0x334fe1f in generateFunction (main.zig) return importBackend(backend).generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output); ^ /home/retrodev/repos/Zig/zig-shishua/src/link/Elf/ZigObject.zig:1487:45: 0x2c3a195 in updateFunc (main.zig) const res = try codegen.generateFunction( ^ /home/retrodev/repos/Zig/zig-shishua/src/link/Elf.zig:2705:44: 0x2c3cf80 in updateFunc (main.zig) return self.zigObjectPtr().?.updateFunc(self, pt, func_index, air, liveness); ^ /home/retrodev/repos/Zig/zig-shishua/src/link.zig:431:82: 0x2c501f1 in updateFunc (main.zig) return @as(*tag.Type(), @fieldParentPtr("base", base)).updateFunc(pt, func_index, air, liveness); ^ /home/retrodev/repos/Zig/zig-shishua/src/Zcu/PerThread.zig:876:22: 0x264f0ff in linkerUpdateFunc (main.zig) lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) { ^ /home/retrodev/repos/Zig/zig-shishua/src/Compilation.zig:3973:36: 0x2138783 in processOneCodegenJob (main.zig) try pt.linkerUpdateFunc(func.func, func.air); ^ /home/retrodev/repos/Zig/zig-shishua/src/Compilation.zig:3945:33: 0x2137371 in codegenThread (main.zig) processOneCodegenJob(tid, comp, codegen_job) catch |job_error| { ^ /home/retrodev/repos/Zig/zig-shishua/lib/std/Thread/Pool.zig:178:50: 0x213771a in runFn (std.zig) @call(.auto, func, .{id.?} ++ closure.arguments); ^ /home/retrodev/repos/Zig/zig-shishua/lib/std/Thread/Pool.zig:291:32: 0x2092606 in worker (std.zig) run_node.data.runFn(&run_node.data, id); ^ /home/retrodev/repos/Zig/zig-shishua/lib/std/Thread.zig:409:13: 0x1b4cafa in callFn__anon_187681 (std.zig) @call(.auto, f, args); ^ /home/retrodev/repos/Zig/zig-shishua/lib/std/Thread.zig:1297:30: 0x1843cdc in entryFn (std.zig) return callFn(f, self.fn_args); ^ /home/retrodev/repos/Zig/zig-shishua/lib/std/os/linux/x86_64.zig:104:5: 0x1b4cc14 in clone (std.zig) asm volatile ( ^ error: the following command terminated unexpectedly: /home/retrodev/repos/Zig/zig-shishua/zig-out/bin/zig build-exe -fno-llvm -ODebug -Mroot=/home/retrodev/repos/Zig/hmmm/src/main.zig --cache-dir /home/retrodev/repos/Zig/hmmm/.zig-cache --global-cache-dir /home/retrodev/.cache/zig --name test --zig-lib-dir /home/retrodev/repos/Zig/zig-shishua/lib/ --listen=- Build Summary: 0/3 steps succeeded; 1 failed install transitive failure └─ install test transitive failure └─ zig build-exe test Debug native failure error: the following build command failed with exit code 1: /home/retrodev/repos/Zig/hmmm/.zig-cache/o/ddfc8aa8f6ef44574e3a6eb4fb512ce6/build /home/retrodev/repos/Zig/zig-shishua/zig-out/bin/zig /home/retrodev/repos/Zig/zig-shishua/lib /home/retrodev/repos/Zig/hmmm /home/retrodev/repos/Zig/hmmm/.zig-cache /home/retrodev/.cache/zig --seed 0x3e8eeb25 -Z4d6b24af71fa2576 ```

Expected Behavior

No unreachable code hit, no segfault, no crash.

Rexicon226 commented 1 month ago

Could you please post the repro and segfault as a collapsible block or just in a block instead of a file upload? I think it'd be better if people didn't need to download a file in order to comment or help on the issue. See something like: https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/markdown/collapsible-items.html to see how to do this.

RetroDev256 commented 1 month ago

Reduction

pub fn main() void {
    const State = enum { start };
    state: switch (State.start) {
        .start => {
            continue :state .start;
        },
    }
}

I would expect this to codegen to a loop. While a Debug-built zig does say this hit an unreachable, a ReleaseFast-built zig says: error: Bitwidth for integer type out of range (Producer: 'zig 0.14.0' Reader: 'LLVM 19.1.0')

Rexicon226 commented 1 month ago

An enum with a single value is an OPV (one possible value) type. This means that it doesn't exist at runtime, since it has a size of 0. I bet for LLVM we're emitting an i0 in ReleaseFast.

A possible solution I can see is to emit a loop instead of loop_switch_br when the type is OPV and replace switch_dispatch with repeat in those cases. I think that would be the minimal amount of changing around and giving the wanted behavior.