Skip to content

Packed union field ptr at comptime hits unreachable #19411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Vexu opened this issue Mar 23, 2024 · 1 comment
Open

Packed union field ptr at comptime hits unreachable #19411

Vexu opened this issue Mar 23, 2024 · 1 comment
Labels
bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Milestone

Comments

@Vexu
Copy link
Member

Vexu commented Mar 23, 2024

Discovered in #19347

export fn entry() void {
    comptime testFlagsInPackedUnionAtOffset();
}
fn testFlagsInPackedUnionAtOffset() void {
    const FlagBits = packed union {
        base_flags: packed union {
            flags: packed struct(u4) {
                enable_1: bool = true,
                enable_2: bool = false,
                enable_3: bool = false,
                enable_4: bool = false,
            },
            bits: u4,
        },
        adv_flags: packed struct(u12) {
            pad: u8 = 0,
            adv: packed union {
                flags: packed struct(u4) {
                    enable_1: bool = true,
                    enable_2: bool = false,
                    enable_3: bool = false,
                    enable_4: bool = false,
                },
                bits: u4,
            },
        },
    };
    var test_bits: FlagBits = .{ .adv_flags = .{ .adv = .{ .flags = .{} } } };
    test_bits.adv_flags.adv.bits = 12;
    if ((&test_bits.adv_flags.adv.flags.enable_1).* != false) unreachable;
}
Stack trace
thread 92776 panic: reached unreachable code
Analyzing a.zig: a.zig:testFlagsInPackedUnionAtOffset
      %91 = dbg_stmt(27, 20)
      %92 = field_ptr(%67, "adv_flags") node_offset:42:11 to :42:30
      %93 = dbg_stmt(27, 30)
      %94 = field_ptr(%92, "adv") node_offset:42:11 to :42:34
      %95 = dbg_stmt(27, 34)
      %96 = field_ptr(%94, "flags") node_offset:42:11 to :42:40
      %97 = dbg_stmt(27, 40)
      %98 = field_ptr(%96, "enable_1") node_offset:42:11 to :42:49
      %99 = validate_deref(%98) node_offset:42:9 to :42:52
    > %100 = load(%98) node_offset:42:9 to :42:52
      %101 = cmp_neq(%100, @bool_false) node_offset:42:9 to :42:61
      %102 = condbr(%101, {
        %104 = dbg_stmt(27, 63)
        %105 = unreachable() node_offset:42:63 to :42:74
      }, {
        %106 = break(%103, @void_value)
      }) node_offset:42:5 to :42:74
    For full context, use the command
      zig ast-check -t a.zig

  in a.zig: a.zig:testFlagsInPackedUnionAtOffset
    > %103 = block({%91..%102}) node_offset:42:5 to :42:74
  in a.zig: a.zig:entry
    > %27 = call(.compile_time, %25, []) node_offset:14:14 to :14:46
  in a.zig: a.zig:entry
    > %24 = block_comptime({%25..%28}) node_offset:14:14 to :14:46

/home/vexu/Documents/zig/zig/src/Value.zig:1770:21: 0xa1f7b69 in fieldValue (zig)
            else => unreachable,
                    ^
/home/vexu/Documents/zig/zig/src/Sema.zig:31429:53: 0xb7ecd9e in beginComptimePtrLoad (zig)
                        .val = try tv.val.fieldValue(mod, field_index),
                                                    ^
/home/vexu/Documents/zig/zig/src/Sema.zig:38160:44: 0xb2d3d68 in pointerDerefExtra (zig)
    const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
                                           ^
/home/vexu/Documents/zig/zig/src/Sema.zig:38131:43: 0xad63302 in pointerDeref (zig)
    const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty);
                                          ^
/home/vexu/Documents/zig/zig/src/Sema.zig:32594:34: 0xa825b93 in analyzeLoad (zig)
        if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
                                 ^

This test case is modified from the flags in packed union at offset test in behavior/packed-union.zig.

@Vexu Vexu added bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness. labels Mar 23, 2024
@Vexu Vexu added this to the 0.12.0 milestone Mar 23, 2024
@Vexu
Copy link
Member Author

Vexu commented Mar 23, 2024

Other similar cases:

test "extern union doesn't trigger field check at comptime" {
    const U = extern union {
        x: u32,
        y: u8,
    };

    const x = U{ .x = 0x55AAAA55 };
    comptime assert((&x.y).* == 0x55);
}
test "memset extern union" {
    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

    const U = extern union {
        foo: u8,
        bar: u32,
    };

    const S = struct {
        fn doTheTest() !void {
            var u: U = undefined;
            @memset(std.mem.asBytes(&u), 0);
            try expectEqual(@as(u8, 0), (&u.foo).*);
            try expectEqual(@as(u32, 0), u.bar);
        }
    };

    try comptime S.doTheTest();
    try S.doTheTest();
}
const endian = builtin.cpu.arch.endian();
fn littleToNativeEndian(comptime T: type, v: T) T {
    return if (endian == .little) v else @byteSwap(v);
}
test "extern union initialized via reintepreted struct field initializer" {
    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

    const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };

    const U = extern union {
        a: u32,
        b: u8,
    };

    const S = extern struct {
        u: U = std.mem.bytesAsValue(U, &bytes).*,
    };

    const s: S = .{};
    try expect(s.u.a == littleToNativeEndian(u32, 0xddccbbaa));
    try expect((&s.u.b).* == 0xaa);
}

@andrewrk andrewrk modified the milestones: 0.12.0, 0.13.0 Mar 26, 2024
@andrewrk andrewrk modified the milestones: 0.14.0, 0.15.0 Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Projects
None yet
Development

No branches or pull requests

2 participants