Compiler segfault on global slice initialization with null[:0] #2404.

This commit is contained in:
Christoffer Lerno
2025-08-15 20:10:28 +02:00
parent 4b95d6be4c
commit b52ab886d2
5 changed files with 116 additions and 97 deletions

View File

@@ -38,6 +38,7 @@
- Compile time indexing at compile time in a $typeof was no considered compile time.
- Slicing a constant array with designated initialization would not update the indexes.
- Fix for bug when `@format` encountered `*` in some cases.
- Compiler segfault on global slice initialization with null[:0] #2404.
### Stdlib changes
- Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`.

View File

@@ -2638,19 +2638,26 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
ASSERT(slice->expr_kind == EXPR_SLICE);
Expr *parent_expr = exprptr(slice->subscript_expr.expr);
Type *parent_type = type_flatten(parent_expr->type);
parent_type = type_no_optional(parent_type);
BEValue parent_addr_x;
llvm_emit_expr(c, &parent_addr_x, parent_expr);
llvm_value_addr(c, &parent_addr_x);
LLVMValueRef parent_addr = parent_addr_x.value;
LLVMValueRef parent_load_value = NULL;
LLVMValueRef parent_base;
parent_type = type_no_optional(parent_type);
LLVMValueRef parent_addr;
if (parent_type->type_kind == TYPE_POINTER)
{
llvm_value_rvalue(c, &parent_addr_x);
parent_load_value = parent_base = parent_addr_x.value;
}
else
{
llvm_value_addr(c, &parent_addr_x);
parent_addr = parent_addr_x.value;
}
switch (parent_type->type_kind)
{
case TYPE_POINTER:
parent_load_value = parent_base = LLVMBuildLoad2(c->builder, llvm_get_type(c, parent_type), parent_addr, "");
break;
case TYPE_SLICE:
parent_load_value = LLVMBuildLoad2(c->builder, llvm_get_type(c, parent_type), parent_addr, "");

View File

@@ -0,0 +1,19 @@
// #target: macos-x64
module test;
char[] bad @export = null[:0];
fn void main()
{
char[] good = null[:0];
}
/* #expect: test.ll
@test__bad = local_unnamed_addr global %"char[]" zeroinitializer, align 8
define void @test.main() #0 {
entry:
%good = alloca %"char[]", align 8
store %"char[]" zeroinitializer, ptr %good, align 8
ret void
}

View File

@@ -373,7 +373,6 @@ entry:
%.inlinecache = alloca ptr, align 8
%.cachedtype = alloca ptr, align 8
%retparam = alloca ptr, align 8
%taddr = alloca ptr, align 8
%varargslots = alloca [1 x %any], align 16
%indirectarg = alloca %"any[]", align 8
%i = alloca i32, align 4
@@ -467,79 +466,75 @@ after_check: ; preds = %match
expr_block.exit: ; preds = %after_check, %if.then
%25 = load ptr, ptr %blockret11, align 8, !dbg !167
store ptr %25, ptr %taddr, align 8
%26 = load ptr, ptr %taddr, align 8
%27 = load i64, ptr %elements8, align 8, !dbg !168
%add = add i64 0, %27, !dbg !168
%26 = load i64, ptr %elements8, align 8, !dbg !168
%add = add i64 0, %26, !dbg !168
%size13 = sub i64 %add, 0, !dbg !168
%28 = insertvalue %"char[][]" undef, ptr %26, 0, !dbg !168
%29 = insertvalue %"char[][]" %28, i64 %size13, 1, !dbg !168
%27 = insertvalue %"char[][]" undef, ptr %25, 0, !dbg !168
%28 = insertvalue %"char[][]" %27, i64 %size13, 1, !dbg !168
br label %noerr_block, !dbg !168
panic_block: ; preds = %assign_optional
%30 = insertvalue %any undef, ptr %error_var, 0, !dbg !168
%31 = insertvalue %any %30, i64 ptrtoint (ptr @"$ct.fault" to i64), 1, !dbg !168
store %any %31, ptr %varargslots, align 16
%32 = insertvalue %"any[]" undef, ptr %varargslots, 0
%"$$temp" = insertvalue %"any[]" %32, i64 1, 1
%29 = insertvalue %any undef, ptr %error_var, 0, !dbg !168
%30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.fault" to i64), 1, !dbg !168
store %any %30, ptr %varargslots, align 16
%31 = insertvalue %"any[]" undef, ptr %varargslots, 0
%"$$temp" = insertvalue %"any[]" %31, i64 1, 1
store %"any[]" %"$$temp", ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg.1
call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 36, ptr @.file, i64 16, ptr @.func, i64 6, i32 287, ptr byval(%"any[]") align 8 %indirectarg) #5, !dbg !157
unreachable, !dbg !157
noerr_block: ; preds = %expr_block.exit
store %"char[][]" %29, ptr %list5, align 8, !dbg !157
store %"char[][]" %28, ptr %list5, align 8, !dbg !157
store i32 0, ptr %i, align 4, !dbg !172
br label %loop.cond, !dbg !172
loop.cond: ; preds = %loop.exit, %noerr_block
%33 = load i32, ptr %i, align 4, !dbg !173
%34 = load i32, ptr %argc2, align 4, !dbg !174
%lt = icmp slt i32 %33, %34, !dbg !173
%32 = load i32, ptr %i, align 4, !dbg !173
%33 = load i32, ptr %argc2, align 4, !dbg !174
%lt = icmp slt i32 %32, %33, !dbg !173
br i1 %lt, label %loop.body, label %loop.exit26, !dbg !173
loop.body: ; preds = %loop.cond
%35 = load ptr, ptr %argv3, align 8, !dbg !178
%36 = load i32, ptr %i, align 4, !dbg !179
%sext14 = sext i32 %36 to i64, !dbg !179
%ptroffset = getelementptr inbounds [8 x i8], ptr %35, i64 %sext14, !dbg !179
%37 = load ptr, ptr %ptroffset, align 8, !dbg !179
store ptr %37, ptr %arg, align 8, !dbg !179
%34 = load ptr, ptr %argv3, align 8, !dbg !178
%35 = load i32, ptr %i, align 4, !dbg !179
%sext14 = sext i32 %35 to i64, !dbg !179
%ptroffset = getelementptr inbounds [8 x i8], ptr %34, i64 %sext14, !dbg !179
%36 = load ptr, ptr %ptroffset, align 8, !dbg !179
store ptr %36, ptr %arg, align 8, !dbg !179
store i64 0, ptr %len, align 8, !dbg !182
%38 = load ptr, ptr %arg, align 8, !dbg !183
%39 = load ptr, ptr %arg, align 8
store ptr %39, ptr %ptr, align 8
%37 = load ptr, ptr %arg, align 8, !dbg !183
%38 = load ptr, ptr %arg, align 8
store ptr %38, ptr %ptr, align 8
store i64 0, ptr %len16, align 8, !dbg !188
br label %loop.cond17, !dbg !189
loop.cond17: ; preds = %loop.body19, %loop.body
%40 = load ptr, ptr %ptr, align 8, !dbg !190
%41 = load i64, ptr %len16, align 8, !dbg !192
%ptradd18 = getelementptr inbounds i8, ptr %40, i64 %41, !dbg !192
%42 = load i8, ptr %ptradd18, align 1, !dbg !192
%i2b = icmp ne i8 %42, 0, !dbg !192
%39 = load ptr, ptr %ptr, align 8, !dbg !190
%40 = load i64, ptr %len16, align 8, !dbg !192
%ptradd18 = getelementptr inbounds i8, ptr %39, i64 %40, !dbg !192
%41 = load i8, ptr %ptradd18, align 1, !dbg !192
%i2b = icmp ne i8 %41, 0, !dbg !192
br i1 %i2b, label %loop.body19, label %loop.exit, !dbg !192
loop.body19: ; preds = %loop.cond17
%43 = load i64, ptr %len16, align 8, !dbg !193
%add20 = add i64 %43, 1, !dbg !193
%42 = load i64, ptr %len16, align 8, !dbg !193
%add20 = add i64 %42, 1, !dbg !193
store i64 %add20, ptr %len16, align 8, !dbg !193
br label %loop.cond17, !dbg !193
loop.exit: ; preds = %loop.cond17
%44 = load i64, ptr %len16, align 8, !dbg !194
%add21 = add i64 0, %44, !dbg !194
%43 = load i64, ptr %len16, align 8, !dbg !194
%add21 = add i64 0, %43, !dbg !194
%size22 = sub i64 %add21, 0, !dbg !194
%45 = insertvalue %"char[]" undef, ptr %38, 0, !dbg !194
%46 = insertvalue %"char[]" %45, i64 %size22, 1, !dbg !194
%47 = load ptr, ptr %list5, align 8, !dbg !195
%48 = load i32, ptr %i, align 4, !dbg !196
%sext23 = sext i32 %48 to i64, !dbg !196
%ptroffset24 = getelementptr inbounds [16 x i8], ptr %47, i64 %sext23, !dbg !196
store %"char[]" %46, ptr %ptroffset24, align 8, !dbg !196
%49 = load i32, ptr %i, align 4, !dbg !197
%add25 = add i32 %49, 1, !dbg !197
%44 = insertvalue %"char[]" undef, ptr %37, 0, !dbg !194
%45 = insertvalue %"char[]" %44, i64 %size22, 1, !dbg !194
%46 = load ptr, ptr %list5, align 8, !dbg !195
%47 = load i32, ptr %i, align 4, !dbg !196
%sext23 = sext i32 %47 to i64, !dbg !196
%ptroffset24 = getelementptr inbounds [16 x i8], ptr %46, i64 %sext23, !dbg !196
store %"char[]" %45, ptr %ptroffset24, align 8, !dbg !196
%48 = load i32, ptr %i, align 4, !dbg !197
%add25 = add i32 %48, 1, !dbg !197
store i32 %add25, ptr %i, align 4, !dbg !197
br label %loop.cond, !dbg !197
@@ -548,15 +543,15 @@ loop.exit26: ; preds = %loop.cond
%lo = load ptr, ptr %list, align 8, !dbg !199
%ptradd27 = getelementptr inbounds i8, ptr %list, i64 8, !dbg !199
%hi = load i64, ptr %ptradd27, align 8, !dbg !199
%50 = call i32 @test.main(ptr %lo, i64 %hi), !dbg !200
store i32 %50, ptr %blockret, align 4, !dbg !200
%51 = load ptr, ptr %list, align 8, !dbg !201
call void @std.core.mem.free(ptr %51) #4, !dbg !203
%49 = call i32 @test.main(ptr %lo, i64 %hi), !dbg !200
store i32 %49, ptr %blockret, align 4, !dbg !200
%50 = load ptr, ptr %list, align 8, !dbg !201
call void @std.core.mem.free(ptr %50) #4, !dbg !203
br label %expr_block.exit28, !dbg !203
expr_block.exit28: ; preds = %loop.exit26
%52 = load i32, ptr %blockret, align 4, !dbg !203
ret i32 %52, !dbg !203
%51 = load i32, ptr %blockret, align 4, !dbg !203
ret i32 %51, !dbg !203
}
declare { i32, ptr } @attach.to_scope() #0

View File

@@ -295,14 +295,13 @@ entry:
%taddr4 = alloca %"char[]", align 8
%taddr5 = alloca %"char[]", align 8
%retparam = alloca ptr, align 8
%taddr6 = alloca ptr, align 8
%taddr6 = alloca %"char[]", align 8
%taddr7 = alloca %"char[]", align 8
%taddr8 = alloca %"char[]", align 8
%taddr9 = alloca %"char[]", align 8
%varargslots = alloca [1 x %any], align 8
%taddr10 = alloca %"any[]", align 8
%retparam14 = alloca %"char[]", align 8
%taddr15 = alloca %"char[]", align 8
%taddr9 = alloca %"any[]", align 8
%retparam13 = alloca %"char[]", align 8
%taddr14 = alloca %"char[]", align 8
store ptr null, ptr %.cachedtype, align 8
%0 = call ptr @llvm.threadlocal.address.p0(ptr @std.core.mem.allocator.thread_allocator)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %allocator, ptr align 8 %0, i32 16, i1 false)
@@ -343,7 +342,7 @@ missing_function: ; preds = %6
store %"char[]" { ptr @.func, i64 4 }, ptr %taddr5, align 8
%10 = load [2 x i64], ptr %taddr5, align 8
%11 = load ptr, ptr @std.core.builtin.panic, align 8
call void %11([2 x i64] %8, [2 x i64] %9, [2 x i64] %10,
call void %11([2 x i64] %8, [2 x i64] %9, [2 x i64] %10, i32 98) #4
unreachable
match: ; preds = %6
@@ -359,60 +358,58 @@ assign_optional: ; preds = %match
after_check: ; preds = %match
%15 = load ptr, ptr %retparam, align 8
store ptr %15, ptr %taddr6, align 8
%16 = load ptr, ptr %taddr6, align 8
%17 = insertvalue %"char[]" undef, ptr %16, 0
%18 = insertvalue %"char[]" %17, i64 12, 1
%16 = insertvalue %"char[]" undef, ptr %15, 0
%17 = insertvalue %"char[]" %16, i64 12, 1
br label %noerr_block
panic_block: ; preds = %assign_optional
%19 = insertvalue %any undef, ptr %error_var, 0
%20 = insertvalue %any %19, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
store %"char[]" { ptr @.panic_msg.4, i64 36 }, ptr %taddr7, align 8
%18 = insertvalue %any undef, ptr %error_var, 0
%19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
store %"char[]" { ptr @.panic_msg.4, i64 36 }, ptr %taddr6, align 8
%20 = load [2 x i64], ptr %taddr6, align 8
store %"char[]" { ptr @.file, i64 16 }, ptr %taddr7, align 8
%21 = load [2 x i64], ptr %taddr7, align 8
store %"char[]" { ptr @.file, i64 16 }, ptr %taddr8, align 8
store %"char[]" { ptr @.func, i64 4 }, ptr %taddr8, align 8
%22 = load [2 x i64], ptr %taddr8, align 8
store %"char[]" { ptr @.func, i64 4 }, ptr %taddr9, align 8
%23 = load [2 x i64], ptr %taddr9, align 8
store %any %20, ptr %varargslots, align 8
%24 = insertvalue %"any[]" undef, ptr %varargslots, 0
%"$$temp" = insertvalue %"any[]" %24, i64 1, 1
store %"any[]" %"$$temp", ptr %taddr10, align 8
%25 = load [2 x i64], ptr %taddr10, align 8
call void @std.core.builtin.panicf([2 x i64] %21, [2 x i64] %22, [2 x i64] %23,
store %any %19, ptr %varargslots, align 8
%23 = insertvalue %"any[]" undef, ptr %varargslots, 0
%"$$temp" = insertvalue %"any[]" %23, i64 1, 1
store %"any[]" %"$$temp", ptr %taddr9, align 8
%24 = load [2 x i64], ptr %taddr9, align 8
call void @std.core.builtin.panicf([2 x i64] %20, [2 x i64] %21, [2 x i64] %22, i32 262, [2 x i64] %24) #4
unreachable
noerr_block: ; preds = %after_check
store %"char[]" %18, ptr %buffer, align 8
store %"char[]" %17, ptr %buffer, align 8
store i64 0, ptr %buffer.f, align 8
%optval = load i64, ptr %buffer.f, align 8
%not_err11 = icmp eq i64 %optval, 0
%26 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true)
br i1 %26, label %after_check13, label %assign_optional12
%not_err10 = icmp eq i64 %optval, 0
%25 = call i1 @llvm.expect.i1(i1 %not_err10, i1 true)
br i1 %25, label %after_check12, label %assign_optional11
assign_optional12: ; preds = %noerr_block
assign_optional11: ; preds = %noerr_block
store i64 %optval, ptr %buffer.f, align 8
br label %after_assign
after_check13: ; preds = %noerr_block
store %"char[]" { ptr @.str.5, i64 13 }, ptr %taddr15, align 8
%27 = load [2 x i64], ptr %taddr15, align 8
%28 = load [2 x i64], ptr %buffer, align 8
%29 = call i64 @test.fileReader(ptr %retparam14, [2 x i64] %27, [2 x i64] %28)
%not_err16 = icmp eq i64 %29, 0
%30 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
br i1 %30, label %after_check18, label %assign_optional17
after_check12: ; preds = %noerr_block
store %"char[]" { ptr @.str.5, i64 13 }, ptr %taddr14, align 8
%26 = load [2 x i64], ptr %taddr14, align 8
%27 = load [2 x i64], ptr %buffer, align 8
%28 = call i64 @test.fileReader(ptr %retparam13, [2 x i64] %26, [2 x i64] %27)
%not_err15 = icmp eq i64 %28, 0
%29 = call i1 @llvm.expect.i1(i1 %not_err15, i1 true)
br i1 %29, label %after_check17, label %assign_optional16
assign_optional17: ; preds = %after_check13
store i64 %29, ptr %buffer.f, align 8
assign_optional16: ; preds = %after_check12
store i64 %28, ptr %buffer.f, align 8
br label %after_assign
after_check18: ; preds = %after_check13
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %buffer, ptr align 8 %retparam14, i32 16, i1 false)
after_check17: ; preds = %after_check12
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %buffer, ptr align 8 %retparam13, i32 16, i1 false)
store i64 0, ptr %buffer.f, align 8
br label %after_assign
after_assign: ; preds = %after_check18, %assign_optional17, %assign_optional12
after_assign: ; preds = %after_check17, %assign_optional16, %assign_optional11
ret void
}