zig icon indicating copy to clipboard operation
zig copied to clipboard

stage2 llvm: pointer access with excess alignment, causing segfault

Open topolarity opened this issue 1 year ago • 2 comments

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.

topolarity avatar Oct 20 '22 04:10 topolarity

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,
    },
});

topolarity avatar Oct 20 '22 04:10 topolarity

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.

topolarity avatar Oct 20 '22 04:10 topolarity

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
  ...

topolarity avatar Nov 01 '22 15:11 topolarity