To: vim_dev@googlegroups.com Subject: Patch 8.2.1538 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1538 Problem: Python: iteration over vim objects fails to keep reference. Solution: Keep a reference for the object. (Paul Ollis, closes #6803, closes #6806) Files: src/if_py_both.h, src/testdir/test_python3.vim *** ../vim-8.2.1537/src/if_py_both.h 2020-07-14 21:08:44.350001848 +0200 --- src/if_py_both.h 2020-08-29 12:54:00.708370457 +0200 *************** *** 1442,1452 **** destructorfun destruct; traversefun traverse; clearfun clear; } IterObject; static PyObject * IterNew(void *start, destructorfun destruct, nextfun next, traversefun traverse, ! clearfun clear) { IterObject *self; --- 1442,1453 ---- destructorfun destruct; traversefun traverse; clearfun clear; + PyObject *iter_object; } IterObject; static PyObject * IterNew(void *start, destructorfun destruct, nextfun next, traversefun traverse, ! clearfun clear, PyObject *iter_object) { IterObject *self; *************** *** 1456,1461 **** --- 1457,1466 ---- self->destruct = destruct; self->traverse = traverse; self->clear = clear; + self->iter_object = iter_object; + + if (iter_object) + Py_INCREF(iter_object); return (PyObject *)(self); } *************** *** 1463,1468 **** --- 1468,1475 ---- static void IterDestructor(IterObject *self) { + if (self->iter_object) + Py_DECREF(self->iter_object); PyObject_GC_UnTrack((void *)(self)); self->destruct(self->cur); PyObject_GC_Del((void *)(self)); *************** *** 1844,1850 **** return IterNew(dii, (destructorfun) PyMem_Free, (nextfun) DictionaryIterNext, ! NULL, NULL); } static PyInt --- 1851,1857 ---- return IterNew(dii, (destructorfun) PyMem_Free, (nextfun) DictionaryIterNext, ! NULL, NULL, (PyObject *)self); } static PyInt *************** *** 2842,2848 **** return IterNew(lii, (destructorfun) ListIterDestruct, (nextfun) ListIterNext, ! NULL, NULL); } static char *ListAttrs[] = { --- 2849,2855 ---- return IterNew(lii, (destructorfun) ListIterDestruct, (nextfun) ListIterNext, ! NULL, NULL, (PyObject *)self); } static char *ListAttrs[] = { *************** *** 3491,3497 **** return IterNew(oii, (destructorfun) PyMem_Free, (nextfun) OptionsIterNext, ! NULL, NULL); } static int --- 3498,3504 ---- return IterNew(oii, (destructorfun) PyMem_Free, (nextfun) OptionsIterNext, ! NULL, NULL, (PyObject *)self); } static int *************** *** 5488,5501 **** } static PyObject * ! BufMapIter(PyObject *self UNUSED) { PyObject *buffer; buffer = BufferNew(firstbuf); return IterNew(buffer, (destructorfun) BufMapIterDestruct, (nextfun) BufMapIterNext, ! (traversefun) BufMapIterTraverse, (clearfun) BufMapIterClear); } static PyMappingMethods BufMapAsMapping = { --- 5495,5509 ---- } static PyObject * ! BufMapIter(PyObject *self) { PyObject *buffer; buffer = BufferNew(firstbuf); return IterNew(buffer, (destructorfun) BufMapIterDestruct, (nextfun) BufMapIterNext, ! (traversefun) BufMapIterTraverse, (clearfun) BufMapIterClear, ! (PyObject *)self); } static PyMappingMethods BufMapAsMapping = { *** ../vim-8.2.1537/src/testdir/test_python3.vim 2020-07-11 22:14:54.314422214 +0200 --- src/testdir/test_python3.vim 2020-08-29 12:54:00.712370444 +0200 *************** *** 4,9 **** --- 4,18 ---- CheckFeature python3 source shared.vim + func Create_vim_list() + return [1] + endfunction + + func Create_vim_dict() + return {'a': 1} + endfunction + + " This function should be called first. This sets up python functions used by " the other tests. func Test_AAA_python3_setup() *************** *** 3944,3947 **** --- 3953,3999 ---- close! endfunc + " Regression: Iterator for a Vim object should hold a reference. + func Test_python3_iter_ref() + let g:list_iter_ref_count_increase = -1 + let g:dict_iter_ref_count_increase = -1 + let g:bufmap_iter_ref_count_increase = -1 + let g:options_iter_ref_count_increase = -1 + + py3 << trim EOF + import sys + import vim + + def test_python3_iter_ref(): + create_list = vim.Function('Create_vim_list') + v = create_list() + base_ref_count = sys.getrefcount(v) + for el in v: + vim.vars['list_iter_ref_count_increase'] = sys.getrefcount(v) - base_ref_count + + create_dict = vim.Function('Create_vim_dict') + v = create_dict() + base_ref_count = sys.getrefcount(v) + for el in v: + vim.vars['dict_iter_ref_count_increase'] = sys.getrefcount(v) - base_ref_count + + v = vim.buffers + base_ref_count = sys.getrefcount(v) + for el in v: + vim.vars['bufmap_iter_ref_count_increase'] = sys.getrefcount(v) - base_ref_count + + v = vim.options + base_ref_count = sys.getrefcount(v) + for el in v: + vim.vars['options_iter_ref_count_increase'] = sys.getrefcount(v) - base_ref_count + + test_python3_iter_ref() + EOF + + call assert_equal(1, g:list_iter_ref_count_increase) + call assert_equal(1, g:dict_iter_ref_count_increase) + call assert_equal(1, g:bufmap_iter_ref_count_increase) + call assert_equal(1, g:options_iter_ref_count_increase) + endfunc + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-8.2.1537/src/version.c 2020-08-28 23:27:16.932923997 +0200 --- src/version.c 2020-08-29 12:56:15.951977902 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1538, /**/ -- GALAHAD: No. Look, I can tackle this lot single-handed! GIRLS: Yes, yes, let him Tackle us single-handed! "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///