From b619fda04193a290cafd712c7b5a4eeffd5a5e3a Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 14 Apr 2026 12:45:26 +0300 Subject: [PATCH] cgen: Data read is corrupted, depending on the order of struct embedding (fixes #26788) --- vlib/v/gen/c/cgen.v | 20 +++++++++---- ...ruct_embedding_mut_order_regression_test.v | 28 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 vlib/v/tests/interfaces/interface_struct_embedding_mut_order_regression_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 4f6723cc3..858fdea47 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -10613,7 +10613,11 @@ return ${cast_shared_struct_str}; name = g.specialized_method_name_from_receiver(method, st, name) styp := g.cc_type(method.params[0].typ, true) mut method_call := '${styp}_${name}' - if cctype == cctype2 && !method.params[0].typ.is_ptr() { + _, embed_types := g.table.find_method_from_embeds(st_sym, method.name) or { + ast.Fn{}, []ast.Type{} + } + needs_embed_wrapper := embed_types.len > 0 && method.name !in method_names + if cctype == cctype2 && (!method.params[0].typ.is_ptr() || needs_embed_wrapper) { if method.name !in aliased_method_names { method_call = '${cctype}_${name}' } else { @@ -10648,16 +10652,20 @@ return ${cast_shared_struct_str}; if method.return_type != ast.void_type { methods_wrapper.write_string('return ') } - _, embed_types := g.table.find_method_from_embeds(st_sym, method.name) or { - ast.Fn{}, []ast.Type{} - } - if embed_types.len > 0 && method.name !in method_names { + if needs_embed_wrapper { embed_sym := g.table.sym(embed_types.last()) mut method_name := '${embed_sym.cname}_${method.name}' if embed_sym.is_builtin() { method_name = 'builtin__${method_name}' } - methods_wrapper.write_string('${method_name}(${fargs[0]}') + last_embed_is_ptr := embed_types.last().is_any_kind_of_pointer() + methods_wrapper.write_string('${method_name}(') + if method.params[0].typ.is_ptr() && !last_embed_is_ptr { + methods_wrapper.write_string('&') + } else if !method.params[0].typ.is_ptr() && last_embed_is_ptr { + methods_wrapper.write_string('*') + } + methods_wrapper.write_string(fargs[0]) for idx_embed, embed in embed_types { esym := g.table.sym(embed) if idx_embed == 0 || embed_types[idx_embed - 1].is_any_kind_of_pointer() { diff --git a/vlib/v/tests/interfaces/interface_struct_embedding_mut_order_regression_test.v b/vlib/v/tests/interfaces/interface_struct_embedding_mut_order_regression_test.v new file mode 100644 index 000000000..fea6e90c9 --- /dev/null +++ b/vlib/v/tests/interfaces/interface_struct_embedding_mut_order_regression_test.v @@ -0,0 +1,28 @@ +struct EmbeddedBase { + next ?&EmbeddedBase +} + +interface EmbeddedNode { +mut: + is_valid() bool +} + +struct EmbeddedState { +mut: + valid bool +} + +struct EmbeddedAccount { + EmbeddedBase + EmbeddedState +} + +fn (mut self EmbeddedState) is_valid() bool { + return self.valid +} + +fn test_interface_cast_with_mut_method_on_later_embedded_field() { + mut acc := EmbeddedAccount{} + mut node := EmbeddedNode(acc) + assert node.is_valid() == acc.valid +} -- 2.39.5