authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-11-10 12:12:37+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-11-12 16:00:16+00:00
log532aa3c5758f110eb7cf0992eb394088ab563899
tree087f1de9f57da7667daa5360b9c2b59b639f2ca2
parent5df5e2ed267deba810811831060a6e1a3593b0f5
signaturelock-open Commit is signed but in an unrecognized format.

cbe: work around some miscompilations

The changes to `codegen.c` are blatant hacks, but the problem they work around isn't a regression: it's an existing miscompilation. This branch happened to *expose* that miscompilation in more cases by changing how an incorrect result is *used*.

3 files changed, 54 insertions(+), 3 deletions(-)

src/Type.zig+1-1
...@@ -3556,7 +3556,7 @@ pub fn packedStructFieldPtrInfo(...@@ -3556,7 +3556,7 @@ pub fn packedStructFieldPtrInfo(
3556 } else .{3556 } else .{
3557 switch (zcu.comp.getZigBackend()) {3557 switch (zcu.comp.getZigBackend()) {
3558 else => (running_bits + 7) / 8,3558 else => (running_bits + 7) / 8,
3559 .stage2_x86_64 => @intCast(struct_ty.abiSize(zcu)),3559 .stage2_x86_64, .stage2_c => @intCast(struct_ty.abiSize(zcu)),
3560 },3560 },
3561 bit_offset,3561 bit_offset,
3562 };3562 };
src/codegen/c.zig+52-1
...@@ -3801,6 +3801,24 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3801,6 +3801,24 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3801 });3801 });
3802 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3802 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3803 try f.allocs.put(zcu.gpa, local.new_local, true);3803 try f.allocs.put(zcu.gpa, local.new_local, true);
3804
3805 switch (elem_ty.zigTypeTag(zcu)) {
3806 .@"struct", .@"union" => switch (elem_ty.containerLayout(zcu)) {
3807 .@"packed" => {
3808 // For packed aggregates, we zero-initialize to try and work around a design flaw
3809 // related to how `packed`, `undefined`, and RLS interact. See comment in `airStore`
3810 // for details.
3811 const w = &f.object.code.writer;
3812 try w.print("memset(&t{d}, 0x00, sizeof(", .{local.new_local});
3813 try f.renderType(w, elem_ty);
3814 try w.writeAll("));");
3815 try f.object.newline();
3816 },
3817 .auto, .@"extern" => {},
3818 },
3819 else => {},
3820 }
3821
3804 return .{ .local_ref = local.new_local };3822 return .{ .local_ref = local.new_local };
3805}3823}
38063824
...@@ -3820,6 +3838,24 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3820,6 +3838,24 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3820 });3838 });
3821 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3839 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3822 try f.allocs.put(zcu.gpa, local.new_local, true);3840 try f.allocs.put(zcu.gpa, local.new_local, true);
3841
3842 switch (elem_ty.zigTypeTag(zcu)) {
3843 .@"struct", .@"union" => switch (elem_ty.containerLayout(zcu)) {
3844 .@"packed" => {
3845 // For packed aggregates, we zero-initialize to try and work around a design flaw
3846 // related to how `packed`, `undefined`, and RLS interact. See comment in `airStore`
3847 // for details.
3848 const w = &f.object.code.writer;
3849 try w.print("memset(&t{d}, 0x00, sizeof(", .{local.new_local});
3850 try f.renderType(w, elem_ty);
3851 try w.writeAll("));");
3852 try f.object.newline();
3853 },
3854 .auto, .@"extern" => {},
3855 },
3856 else => {},
3857 }
3858
3823 return .{ .local_ref = local.new_local };3859 return .{ .local_ref = local.new_local };
3824}3860}
38253861
...@@ -4098,9 +4134,24 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -4098,9 +4134,24 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
4098 if (val_is_undef) {4134 if (val_is_undef) {
4099 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });4135 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4100 if (safety and ptr_info.packed_offset.host_size == 0) {4136 if (safety and ptr_info.packed_offset.host_size == 0) {
4137 // If the thing we're initializing is a packed struct/union, we set to 0 instead of
4138 // 0xAA. This is a hack to work around a problem with partially-undefined packed
4139 // aggregates. If we used 0xAA here, then a later initialization through RLS would
4140 // not zero the high padding bits (for a packed type which is not 8/16/32/64/etc bits),
4141 // so we would get a miscompilation. Using 0x00 here avoids this bug in some cases. It
4142 // is *not* a correct fix; for instance it misses any case where packed structs are
4143 // nested in other aggregates. A proper fix for this will involve changing the language,
4144 // such as to remove RLS. This just prevents miscompilations in *some* common cases.
4145 const byte_str: []const u8 = switch (src_ty.zigTypeTag(zcu)) {
4146 else => "0xaa",
4147 .@"struct", .@"union" => switch (src_ty.containerLayout(zcu)) {
4148 .auto, .@"extern" => "0xaa",
4149 .@"packed" => "0x00",
4150 },
4151 };
4101 try w.writeAll("memset(");4152 try w.writeAll("memset(");
4102 try f.writeCValue(w, ptr_val, .FunctionArgument);4153 try f.writeCValue(w, ptr_val, .FunctionArgument);
4103 try w.writeAll(", 0xaa, sizeof(");4154 try w.print(", {s}, sizeof(", .{byte_str});
4104 try f.renderType(w, .fromInterned(ptr_info.child));4155 try f.renderType(w, .fromInterned(ptr_info.child));
4105 try w.writeAll("));");4156 try w.writeAll("));");
4106 try f.object.newline();4157 try f.object.newline();
test/behavior/union.zig+1-1
...@@ -1547,7 +1547,7 @@ test "packed union field pointer has correct alignment" {...@@ -1547,7 +1547,7 @@ test "packed union field pointer has correct alignment" {
15471547
1548 const host_size = switch (builtin.zig_backend) {1548 const host_size = switch (builtin.zig_backend) {
1549 else => comptime std.math.divCeil(comptime_int, @bitSizeOf(S), 8) catch unreachable,1549 else => comptime std.math.divCeil(comptime_int, @bitSizeOf(S), 8) catch unreachable,
1550 .stage2_x86_64 => @sizeOf(S),1550 .stage2_x86_64, .stage2_c => @sizeOf(S),
1551 };1551 };
1552 comptime assert(@TypeOf(ap) == *align(4:2:host_size) u20);1552 comptime assert(@TypeOf(ap) == *align(4:2:host_size) u20);
1553 comptime assert(@TypeOf(bp) == *align(1:2:host_size) u20);1553 comptime assert(@TypeOf(bp) == *align(1:2:host_size) u20);