From c54acdf609f390cd6c10c8a0aae22082892621fb Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 05:48:37 +0300 Subject: [PATCH] cgen: fix invalid memory access when iterating on interface types in an array (fixes #26882) --- vlib/v/gen/c/fn.v | 9 +++- .../interface_arr_for_mut_iter_index_test.v | 50 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index f3180ab4c..e4b9afb91 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -6535,7 +6535,14 @@ fn (mut g Gen) ref_or_deref_arg_ex(arg ast.CallArg, expected_type_ ast.Type, lan g.expr(arg.expr) } } else { - g.write('ADDR(${g.table.sym(expected_wrap_type).cname}, ') + if exp_sym.kind == .interface { + // A converted `mut` interface argument can escape the callee + // (for example into `[]&Interface`), so the wrapper must outlive + // the current block scope. + g.write('HEAP(${g.table.sym(expected_wrap_type).cname}, ') + } else { + g.write('ADDR(${g.table.sym(expected_wrap_type).cname}, ') + } g.expr_with_cast(arg.expr, arg_typ, expected_wrap_type) g.write(')') } diff --git a/vlib/v/tests/interfaces/interface_arr_for_mut_iter_index_test.v b/vlib/v/tests/interfaces/interface_arr_for_mut_iter_index_test.v index d8d6d913c..4036920bd 100644 --- a/vlib/v/tests/interfaces/interface_arr_for_mut_iter_index_test.v +++ b/vlib/v/tests/interfaces/interface_arr_for_mut_iter_index_test.v @@ -12,3 +12,53 @@ fn test_interface_arr_for_mut_iter_index() { assert maap.ennemis.index(ennemi) == 0 } } + +@[heap] +interface WalkerMut { +mut: + children []&WalkerMut + value int + + get_children() []&WalkerMut + add_child(mut child WalkerMut) + bump() +} + +@[heap] +struct WalkNodeMut { +mut: + children []&WalkerMut + value int +} + +fn (n &WalkNodeMut) get_children() []&WalkerMut { + return n.children +} + +fn (mut n WalkNodeMut) add_child(mut child WalkerMut) { + n.children << child +} + +fn (mut n WalkNodeMut) bump() { + n.value++ +} + +fn walk_mut(mut node WalkerMut) { + node.bump() + for mut child in node.get_children() { + walk_mut(mut child) + } +} + +fn add_child_from_concrete(mut root WalkNodeMut, mut child WalkNodeMut) { + root.add_child(mut child) +} + +fn test_for_in_array_of_interface_ptr_regression() { + mut root := &WalkNodeMut{} + mut child := &WalkNodeMut{} + add_child_from_concrete(mut root, mut child) + walk_mut(mut root) + assert child.value == 1 + assert root.value == 1 +} -- 2.39.5