From e4c01c8e9459d86a7dd3eb994d1e17e4fe4f1a02 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 16 Mar 2026 14:39:03 +0200 Subject: [PATCH] cgen,autofree: don't clone array fn args in struct field init, add test (#26709) --- vlib/v/gen/c/struct.v | 12 ++++++++++-- vlib/v/tests/autofree_arrays_reverse_iter_test.v | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/autofree_arrays_reverse_iter_test.v diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index 68a367fa1..95f582530 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -781,8 +781,16 @@ fn (mut g Gen) struct_init_field(sfield ast.StructInitField, language ast.Langua field_type_sym := g.table.sym(sfield.typ) mut cloned := false if g.is_autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] { - if g.gen_clone_assignment(sfield.expected_type, sfield.expr, sfield.typ, false) { - cloned = true + // array fn args should not be cloned into struct fields: the caller owns and + // frees the underlying data, so cloning would break mutation aliasing + // (e.g. `for mut x in iter`) and leak the clone. strings are still cloned + // since they may be freed before the struct field is used. + is_fn_arg := field_type_sym.kind == .array && sfield.expr is ast.Ident + && sfield.expr.obj is ast.Var && (sfield.expr.obj as ast.Var).is_arg + if !is_fn_arg { + if g.gen_clone_assignment(sfield.expected_type, sfield.expr, sfield.typ, false) { + cloned = true + } } } if !cloned { diff --git a/vlib/v/tests/autofree_arrays_reverse_iter_test.v b/vlib/v/tests/autofree_arrays_reverse_iter_test.v new file mode 100644 index 000000000..4b32f37df --- /dev/null +++ b/vlib/v/tests/autofree_arrays_reverse_iter_test.v @@ -0,0 +1,16 @@ +// vtest vflags: -autofree +// vtest build: !sanitize-address-gcc && !sanitize-address-clang +import arrays + +fn test_arrays_fns_arg() { + mut original := [10, 20] + for mut x in arrays.reverse_iterator(original) { + (*x)++ + } + assert original == [11, 21] + + for mut x in original { + (*x)++ + } + assert original == [12, 22] +} -- 2.39.5