Skip to content
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

Bit-packed struct with undefined default has inconsistent access #19981

Closed
Arnau478 opened this issue May 16, 2024 · 8 comments
Closed

Bit-packed struct with undefined default has inconsistent access #19981

Arnau478 opened this issue May 16, 2024 · 8 comments
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@Arnau478
Copy link
Contributor

Zig Version

0.13.0-dev.211+6a65561e3

Steps to Reproduce and Observed Behavior

Run the following code:

const std = @import("std");

pub const Foo = packed struct(u2) {
    a: bool = undefined,
    b: bool,
};

const foo = Foo{
    .b = true,
};

pub fn main() void {
    std.debug.print("{}\n", .{foo});
    std.debug.print("{}\n", .{foo.b});
}

which prints

example.Foo{ .a = false, .b = false }
true

Notice how when we print foo, we get .b = false, but when we print foo.b we get true.

Expected Behavior

Both of them should print b as being true, but the first one doesn't.

A few things I've noticed:

  • If you change the undefined default value with false, then everything works as expected
  • Pretty recent regression, works in zig 0.12.0
@Arnau478 Arnau478 added the bug Observed behavior contradicts documented or intended behavior label May 16, 2024
@Arnau478 Arnau478 changed the title Bit-packed struct accessing doesn't work as expected Bit-packed struct with undefined default has inconsistent access May 16, 2024
@Rexicon226
Copy link
Contributor

On 0.12:

❯ zig run empty.zig                                                                                                                   
empty.Foo{ .a = false, .b = true }
true

On 0.13.0-dev.55+fc45e5b39:

❯ zig run empty.zig                                                                                       
empty.Foo{ .a = false, .b = false }
true
❯ zig run empty.zig -fno-llvm -fno-lld
empty.Foo{ .a = false, .b = true }
true

Note that fc45e5b39 is before the LLVM upgrade.

@Rexicon226
Copy link
Contributor

In #19630 it was made so that having undefined in a packed struct would propagate to the entire struct iirc.

So see:

const std = @import("std");

pub const Foo = packed struct(u2) {
    a: bool,
    b: bool,
};

pub fn main() void {
    var foo: Foo = undefined;
    _ = &foo;

    foo.b = true;

    std.debug.print("{}\n", .{foo});
    std.debug.print("{}\n", .{foo.b});
}

which works fine.

Might be talking non-sense, but I believe this is what is happening.

@mikdusan
Copy link
Member

having undefined in a packed struct would propagate to the entire struct

If that's the expected/desired behaviour with:

const std = @import("std");

pub const Foo = packed struct(u2) {
    a: bool = undefined,
    b: bool,
};

pub fn main() void {
    var foo = Foo{
        .b = true,
    };
    _ = &foo;

    std.debug.print("{}\n", .{foo});
    std.debug.print("{}\n", .{foo.b});
}

consistent with that expectation (master branch) does mark as undef:

store i2 undef, ptr %2, align 1, !dbg !2322

however, simply swapping field order:

pub const Foo = packed struct(u2) {
    b: bool,
    a: bool = undefined,
};

the IR becomes inconsistent with that expectation:

store i2 1, ptr %2, align 1, !dbg !2322

fwiw, this specific repro bisects to c231d94

@mlugg
Copy link
Member

mlugg commented May 16, 2024

@Rexicon226 that idea was put on hold for now, and so has never been in a build of Zig.

@Rexicon226
Copy link
Contributor

Ah, my bad. No idea then.

@ifreund
Copy link
Member

ifreund commented May 17, 2024

Is there a way to print an undefined value without branching on it and invoking UB? It doesn't surprise me personally that LLVM seems to do weird things after branching on undefined...

@Arnau478
Copy link
Contributor Author

Is there a way to print an undefined value without branching on it and invoking UB? It doesn't surprise me personally that LLVM seems to do weird things after branching on undefined...

The thing is that only one field is undefined. Also, when casting to an int (where there's no branching) this also happens.

@Vexu
Copy link
Member

Vexu commented May 31, 2024

Caused by #20095, using -fno-llvm -fno-lld results in a.Foo{ .a = false, .b = true }.

@Vexu Vexu closed this as not planned Won't fix, can't repro, duplicate, stale May 31, 2024
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
Projects
None yet
Development

No branches or pull requests

6 participants