mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
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*.
This commit is contained in:
parent
5df5e2ed26
commit
532aa3c575
3 changed files with 54 additions and 3 deletions
|
|
@ -3556,7 +3556,7 @@ pub fn packedStructFieldPtrInfo(
|
||||||
} else .{
|
} else .{
|
||||||
switch (zcu.comp.getZigBackend()) {
|
switch (zcu.comp.getZigBackend()) {
|
||||||
else => (running_bits + 7) / 8,
|
else => (running_bits + 7) / 8,
|
||||||
.stage2_x86_64 => @intCast(struct_ty.abiSize(zcu)),
|
.stage2_x86_64, .stage2_c => @intCast(struct_ty.abiSize(zcu)),
|
||||||
},
|
},
|
||||||
bit_offset,
|
bit_offset,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3801,6 +3801,24 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
});
|
});
|
||||||
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
|
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
|
||||||
try f.allocs.put(zcu.gpa, local.new_local, true);
|
try f.allocs.put(zcu.gpa, local.new_local, true);
|
||||||
|
|
||||||
|
switch (elem_ty.zigTypeTag(zcu)) {
|
||||||
|
.@"struct", .@"union" => switch (elem_ty.containerLayout(zcu)) {
|
||||||
|
.@"packed" => {
|
||||||
|
// For packed aggregates, we zero-initialize to try and work around a design flaw
|
||||||
|
// related to how `packed`, `undefined`, and RLS interact. See comment in `airStore`
|
||||||
|
// for details.
|
||||||
|
const w = &f.object.code.writer;
|
||||||
|
try w.print("memset(&t{d}, 0x00, sizeof(", .{local.new_local});
|
||||||
|
try f.renderType(w, elem_ty);
|
||||||
|
try w.writeAll("));");
|
||||||
|
try f.object.newline();
|
||||||
|
},
|
||||||
|
.auto, .@"extern" => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
return .{ .local_ref = local.new_local };
|
return .{ .local_ref = local.new_local };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3820,6 +3838,24 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
});
|
});
|
||||||
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
|
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
|
||||||
try f.allocs.put(zcu.gpa, local.new_local, true);
|
try f.allocs.put(zcu.gpa, local.new_local, true);
|
||||||
|
|
||||||
|
switch (elem_ty.zigTypeTag(zcu)) {
|
||||||
|
.@"struct", .@"union" => switch (elem_ty.containerLayout(zcu)) {
|
||||||
|
.@"packed" => {
|
||||||
|
// For packed aggregates, we zero-initialize to try and work around a design flaw
|
||||||
|
// related to how `packed`, `undefined`, and RLS interact. See comment in `airStore`
|
||||||
|
// for details.
|
||||||
|
const w = &f.object.code.writer;
|
||||||
|
try w.print("memset(&t{d}, 0x00, sizeof(", .{local.new_local});
|
||||||
|
try f.renderType(w, elem_ty);
|
||||||
|
try w.writeAll("));");
|
||||||
|
try f.object.newline();
|
||||||
|
},
|
||||||
|
.auto, .@"extern" => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
return .{ .local_ref = local.new_local };
|
return .{ .local_ref = local.new_local };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4098,9 +4134,24 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
|
||||||
if (val_is_undef) {
|
if (val_is_undef) {
|
||||||
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
||||||
if (safety and ptr_info.packed_offset.host_size == 0) {
|
if (safety and ptr_info.packed_offset.host_size == 0) {
|
||||||
|
// If the thing we're initializing is a packed struct/union, we set to 0 instead of
|
||||||
|
// 0xAA. This is a hack to work around a problem with partially-undefined packed
|
||||||
|
// aggregates. If we used 0xAA here, then a later initialization through RLS would
|
||||||
|
// not zero the high padding bits (for a packed type which is not 8/16/32/64/etc bits),
|
||||||
|
// so we would get a miscompilation. Using 0x00 here avoids this bug in some cases. It
|
||||||
|
// is *not* a correct fix; for instance it misses any case where packed structs are
|
||||||
|
// nested in other aggregates. A proper fix for this will involve changing the language,
|
||||||
|
// such as to remove RLS. This just prevents miscompilations in *some* common cases.
|
||||||
|
const byte_str: []const u8 = switch (src_ty.zigTypeTag(zcu)) {
|
||||||
|
else => "0xaa",
|
||||||
|
.@"struct", .@"union" => switch (src_ty.containerLayout(zcu)) {
|
||||||
|
.auto, .@"extern" => "0xaa",
|
||||||
|
.@"packed" => "0x00",
|
||||||
|
},
|
||||||
|
};
|
||||||
try w.writeAll("memset(");
|
try w.writeAll("memset(");
|
||||||
try f.writeCValue(w, ptr_val, .FunctionArgument);
|
try f.writeCValue(w, ptr_val, .FunctionArgument);
|
||||||
try w.writeAll(", 0xaa, sizeof(");
|
try w.print(", {s}, sizeof(", .{byte_str});
|
||||||
try f.renderType(w, .fromInterned(ptr_info.child));
|
try f.renderType(w, .fromInterned(ptr_info.child));
|
||||||
try w.writeAll("));");
|
try w.writeAll("));");
|
||||||
try f.object.newline();
|
try f.object.newline();
|
||||||
|
|
|
||||||
|
|
@ -1547,7 +1547,7 @@ test "packed union field pointer has correct alignment" {
|
||||||
|
|
||||||
const host_size = switch (builtin.zig_backend) {
|
const host_size = switch (builtin.zig_backend) {
|
||||||
else => comptime std.math.divCeil(comptime_int, @bitSizeOf(S), 8) catch unreachable,
|
else => comptime std.math.divCeil(comptime_int, @bitSizeOf(S), 8) catch unreachable,
|
||||||
.stage2_x86_64 => @sizeOf(S),
|
.stage2_x86_64, .stage2_c => @sizeOf(S),
|
||||||
};
|
};
|
||||||
comptime assert(@TypeOf(ap) == *align(4:2:host_size) u20);
|
comptime assert(@TypeOf(ap) == *align(4:2:host_size) u20);
|
||||||
comptime assert(@TypeOf(bp) == *align(1:2:host_size) u20);
|
comptime assert(@TypeOf(bp) == *align(1:2:host_size) u20);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue