-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Incorrect byte offset and struct size for packed structs #2627
Comments
I believe the problem could be in analyze.cpp:resolve_struct_type.cpp as that seems to be where the packed struct offsets are calculated. Line 1657 in fdddd13
|
Most of ir code is beyond my understanding but I see in diff --git a/src/ir.cpp b/src/ir.cpp
index fb9e7b51..0dcd1d44 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -18331,11 +18331,11 @@ static IrInstruction *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira,
IrInstruction *field_name_value = instruction->field_name->child;
size_t byte_offset = 0;
- if (!validate_byte_offset(ira, type_value, field_name_value, &byte_offset))
+ TypeStructField *field = nullptr;
+ if (!(field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset)))
return ira->codegen->invalid_instruction;
-
- return ir_const_unsigned(ira, &instruction->base, byte_offset);
+ return ir_const_unsigned(ira, &instruction->base, byte_offset + field->bit_offset_in_host / 8);
}
static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, note: this doesn't address |
I see no checks for whether or not the struct is packed in analyze.cpp:get_struct_type, could that be the root of the issue? I see some field offset calculations in there. I don't believe that this is just an issue with |
Another possibly simpler case:
|
It seems this is a problem even on structs which don't contain non-byte-divisble sized types pub const Test = packed struct {
a: [3]u8,
b: [8]u8,
};
|
They are arrays of u8, so the first member is 24 bits. |
It seems like i ran into this problem as well. Here is some additional findings wheather when this happens or not: pub const Flags1 = packed struct {
// byte 0
b0_0: u1,
b0_1: u1,
b0_2: u1,
b0_3: u1,
b0_4: u1,
b0_5: u1,
b0_6: u1,
b0_7: u1,
// partial byte 1 (but not 8 bits)
b1_0: u1,
b1_1: u1,
b1_2: u1,
b1_3: u1,
b1_4: u1,
b1_5: u1,
b1_6: u1,
// some padding to fill to size 3
_: u9,
};
pub const Flags2 = packed struct {
// byte 0
b0_0: u1,
b0_1: u1,
b0_2: u1,
b0_3: u1,
b0_4: u1,
b0_5: u1,
b0_6: u1,
b0_7: u1,
// partial byte 1 (but not 8 bits)
b1_0: u1,
b1_1: u1,
b1_2: u1,
b1_3: u1,
b1_4: u1,
b1_5: u1,
b1_6: u1,
// some padding that should yield @sizeOf(Flags2) == 4
_: u10, // this *was* originally 17, but the error happens with 10 as well
};
pub const Flags3 = packed struct {
// byte 0
b0_0: u1,
b0_1: u1,
b0_2: u1,
b0_3: u1,
b0_4: u1,
b0_5: u1,
b0_6: u1,
b0_7: u1,
// byte 1
b1_0: u1,
b1_1: u1,
b1_2: u1,
b1_3: u1,
b1_4: u1,
b1_5: u1,
b1_6: u1,
b1_7: u1,
// some padding that should yield @sizeOf(Flags2) == 4
_: u16, // it works, if the padding is 8-based
};
comptime {
@compileLog("Flags1", @sizeOf(Flags1)); // => 3
@compileLog("Flags2", @sizeOf(Flags2)); // => 5
@compileLog("Flags3", @sizeOf(Flags3)); // => 4
} |
I could reduce this problem to a struct with a single field: const std = @import("std");
const Broken = packed struct {
element: u24,
};
test "sizeOf == 4" { // succeeds
std.debug.assert(@sizeOf(Broken) == 4);
}
test "sizeOf == 3" { // fails
std.debug.assert(@sizeOf(Broken) == 3);
} The assertion fails, my current zig version is |
Another failure case is packed structs:
|
I ran into this today, minified my example to this code which fails its comptime check: pub const S = packed struct {
_: [3]u8,
};
comptime { std.debug.assert(@sizeOf(S) == 3); } |
I also ran into this. Somehow, const std = @import("std");
const Foo = packed struct {
_: [3]u8,
};
pub fn main() !void {
var fooBuf = [_]u8{0} ** @sizeOf(Foo);
std.debug.assert(@sizeOf(Foo) == fooBuf.len); // succeeds
var foo = @bitCast(Foo, fooBuf);
}
|
I think this is another example of this?: const std = @import("std");
const assert = std.debug.assert;
pub const InReplyTo = packed struct {
id: [6]u8,
hash: [16]u8,
};
comptime {
assert(@sizeOf(InReplyTo) == 22);
}
|
Fixed formatting in packed-struct-zig Skipped packed_structs tests in stage2 simplified packed struct tests
Fixed formatting in packed-struct-zig Skipped packed_structs tests in stage2 simplified packed struct tests
still have the issue on v0.9.1. looks like I have to wait v1.0 |
0.10.0 changes the |
Packed structs are now integer backed. |
The byte offsets of fields within a packed struct are sometimes incorrect, see the below example.
The comments show what the bit offsets and byte offsets should be judging by the documentation[1], but below is the result:
The size is also incorrect, since it should be 4 bytes (the sum of the fields) but is instead 5.
1: "bool fields use exactly 1 bit" and "Zig supports arbitrary width Integers and although normally, integers with fewer than 8 bits will still use 1 byte of memory, in packed structs, they use exactly their bit width" at https://ziglang.org/documentation/0.4.0/#packed-struct
The text was updated successfully, but these errors were encountered: