From ce5c54fef606ccaa607dcccf859a682a3deb2ce8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 17 Jul 2025 16:44:22 +1000 Subject: [PATCH] Fix #128169: Memory leak in bpy.data.meshes.new_from_object Resolve leak in new_from_object when preserve_all_data_layers=True and a sub-surfaced mesh. A copy was made, then BKE_mesh_wrapper_ensure_subdivision would return the "mesh_eval" of the copy, leaking the mesh passed to BKE_mesh_wrapper_ensure_subdivision. Ref !142176 --- .../blender/blenkernel/intern/mesh_convert.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index b4b6a749083..3d203875b4a 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -821,8 +821,25 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph, mask.lmask |= CD_MASK_ORIGINDEX; mask.pmask |= CD_MASK_ORIGINDEX; } + Mesh *result = blender::bke::mesh_create_eval_final(depsgraph, scene, &object_for_eval, &mask); - return (ensure_subdivision) ? BKE_mesh_wrapper_ensure_subdivision(result) : result; + + if (ensure_subdivision) { + /* Returns a borrowed reference which is still owned by `result`. + * Steal the reference from `result` which can then be freed. */ + Mesh *result_maybe_subdiv = BKE_mesh_wrapper_ensure_subdivision(result); + if (result != result_maybe_subdiv) { + /* Expected, but assert this is the case. */ + BLI_assert(result->runtime->mesh_eval == result_maybe_subdiv); + if (result->runtime->mesh_eval == result_maybe_subdiv) { + result->runtime->mesh_eval = nullptr; + BKE_id_free(nullptr, result); + result = result_maybe_subdiv; + } + } + } + + return result; } static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,