From 475816251b82bce68169195aacba04df649b8b36 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 12 Dec 2025 20:35:11 +0100 Subject: [PATCH] - Strings assigned to longer arrays would crash codegen, e.g. `char[10] x = "abcd`. --- releasenotes.md | 1 + src/compiler/llvm_codegen_expr.c | 7 ++++--- .../constants/array_zero_string_long.c3t | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 test/test_suite/constants/array_zero_string_long.c3t diff --git a/releasenotes.md b/releasenotes.md index c4c6d3b0a..ecc984f38 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -15,6 +15,7 @@ - Ignore const null check on deref in `$defined` and `$sizeof` #2633. - Subscripting of constant slices would sometimes be considered non-constant #2635. - Compiler crash when concatenating structs and arrays to an untyped list. +- Strings assigned to longer arrays would crash codegen, e.g. `char[10] x = "abcd`. ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index fe7210f95..6064ef03f 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -4821,9 +4821,6 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) ArraySize size = expr->const_expr.bytes.len; size++; if (is_array && type->array.len > size) size = type->array.len; - LLVMValueRef global_name = llvm_add_global_raw(c, is_bytes ? ".bytes" : ".str", LLVMArrayType(llvm_get_type(c, type_char), size), 1); - llvm_set_private_declaration(global_name); - LLVMSetGlobalConstant(global_name, 1); LLVMValueRef data = llvm_get_zstring(c, expr->const_expr.bytes.ptr, expr->const_expr.bytes.len); LLVMValueRef trailing_zeros = NULL; if (size > len + 1) @@ -4835,6 +4832,10 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) LLVMValueRef values[2] = { data, trailing_zeros }; data = llvm_get_packed_struct(c, values, 2); } + LLVMValueRef global_name = llvm_add_global_raw(c, is_bytes ? ".bytes" : ".str", LLVMTypeOf(data), 1); + llvm_set_private_declaration(global_name); + LLVMSetGlobalConstant(global_name, 1); + LLVMSetInitializer(global_name, data); if (is_array) { diff --git a/test/test_suite/constants/array_zero_string_long.c3t b/test/test_suite/constants/array_zero_string_long.c3t new file mode 100644 index 000000000..187486f90 --- /dev/null +++ b/test/test_suite/constants/array_zero_string_long.c3t @@ -0,0 +1,21 @@ +// #target: macos-x64 + +module test; +import std; + +fn int main() +{ + char[10] x = "abcd"; + return 0; +} + +/* #expect: test.ll + +@.str = private unnamed_addr constant <{ [5 x i8], [5 x i8] }> <{ [5 x i8] c"abcd\00", [5 x i8] zeroinitializer }>, align 1 + +define i32 @main() #0 { +entry: + %x = alloca [10 x i8], align 1 + call void @llvm.memcpy.p0.p0.i32(ptr align 1 %x, ptr align 1 @.str, i32 10, i1 false) + ret i32 0 +}