zig icon indicating copy to clipboard operation
zig copied to clipboard

Aligned union fields exceed the union size

Open T1nk3r1 opened this issue 1 year ago • 0 comments

Zig Version

0.12.0-dev.3428+d8bb139da

Steps to Reproduce and Observed Behavior

const std = @import("std");

pub fn main() !void {
    const S = union(enum) {
        a: i16 align(1),
        b: f64 align(1),
    };
    var a: S = .{ .b = 5000 };

    std.log.debug("Size: {}", .{@sizeOf(S)});
    std.log.debug("Alignment: {}", .{@alignOf(S)});

    std.log.debug("S.b offset: {x}", .{@intFromPtr(&a.b) - @intFromPtr(&a)});
}

Output:

debug: Size: 9
debug: Alignment: 1
debug: S.b offset: 8

This means that S.b will exceed the union size. It can be observed in the following example:

const std = @import("std");

pub fn main() !void {
    const S = union(enum) {
        a: i16 align(1),
        b: f64 align(1),
    };
    var a: S = .{ .b = 5000 };
    a.b = 5001;
    const b: [3]S = .{ a, a, a };

    std.log.debug("{any}", .{b});
}

Output:

debug: { main.main.S{ .b = 0e0 }, main.main.S{ .b = -3.3428705905156227e196 }, main.main.S{ .a =  } }

However it works fine with constant a:

const std = @import("std");

pub fn main() !void {
    const S = union(enum) {
        a: i16 align(1),
        b: f64 align(1),
    };
    const a: S = .{ .b = 5000 };
    const b: [3]S = .{ a, a, a };

    std.log.debug("{any}", .{b});
}

Output:

debug: { main.main.S{ .b = 5e3 }, main.main.S{ .b = 5e3 }, main.main.S{ .b = 5e3 } }

Expected Behavior

Aligned union fields must not exceed the union size.

T1nk3r1 avatar Mar 23 '24 06:03 T1nk3r1