zig
zig copied to clipboard
stage2 llvm: pointer access with excess alignment, causing segfault
Zig Version
0.10.0-dev.4472+a4eb221b9
Steps to Reproduce
Build Zig and save the LLVM IR:
$ /build/zig2 build -p stage3_debug -Dstrip=true -Denable-llvm=true --verbose-llvm-ir 2>llvm_ir.txt
If you examine Autodocs.walkInstruction
in the generated LLVM IR, you'll see this:
; Function Attrs: nounwind sspstrong uwtable
define internal fastcc void @Autodoc.walkInstruction(ptr noalias nonnull sret({ %Autodoc.DocData.WalkResult, i16, [14 x i8] }) %0, ptr nonnull align 8 %1, ptr nonnull align 8 %2, ptr nonnull align 8 %3, ptr nonnull readonly align 8 %4, i64 %5, i1 %6) unnamed_addr #0 {
Entry:
...
%891 = alloca %Autodoc.DocData.Type, align 8
...
%2849 = getelementptr inbounds { %Autodoc.DocData.Type.Type__struct_34832, i5, [15 x i8] }, ptr %891, i32 0, i32 0
call void @llvm.memcpy.p0.p0.i64(ptr align 16 %2849, ptr align 16 %892, i64 592, i1 false)
...
}
Zig claims that %2849
has alignment 16, but it actually has alignment 8.
Expected Behavior
Alignment should be consistent between alloca and memcpy.
Actual Behavior
Alignments do not match.
This LLVM IR is generated from this part of Autodocs.walkInstruction
, at line 1581:
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
.Pointer = .{
.size = ptr.size,
.child = elem_type_ref.expr,
.has_align = ptr.flags.has_align,
.@"align" = @"align",
.has_addrspace = ptr.flags.has_addrspace,
.address_space = address_space,
.has_sentinel = ptr.flags.has_sentinel,
.sentinel = sentinel,
.is_mutable = ptr.flags.is_mutable,
.is_volatile = ptr.flags.is_volatile,
.has_bit_range = ptr.flags.has_bit_range,
.bit_start = bit_start,
.host_size = host_size,
},
});
In release modes, this memcpy sometimes gets lowered to a movaps
instruction, which requires 16-byte alignment and causes a segfault otherwise.
That segfault is preventing https://github.com/ziglang/zig/pull/13074 from passing CI.
Reduction:
const Type = union(enum) {
Pointer: struct {
child: u32 align(16),
},
};
fn foo(x: Type) void {
_ = x;
}
test {
var child: u32 = 1;
foo(.{ .Pointer = .{ .child = child } });
}
Generates an under-aligned alloca
:
define internal fastcc i16 @test22.test_0(ptr nonnull %0) unnamed_addr #0 !dbg !4390 {
Entry:
%1 = alloca %test22.Type, align 8
...