# HG changeset patch # User Bram Moolenaar # Date 1369162319 -7200 # Node ID 47e6dec5ce3cbc8e833480b8300132d4bf5f035e # Parent 364b26198af633281a8e870027125b1907498886 updated for version 7.3.998 Problem: Python: garbage collection issues. Solution: Fix the GC issues: Use proper DESTRUCTOR_FINISH: avoids negative refcounts, use PyObject_GC_* for objects with tp_traverse and tp_clear, add RangeTraverse and RangeClear, use Py_XDECREF in some places. (ZyX) diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -461,7 +461,7 @@ VimToPython(typval_T *our_tv, int depth, } static PyObject * -VimEval(PyObject *self UNUSED, PyObject *args UNUSED) +VimEval(PyObject *self UNUSED, PyObject *args) { char *expr; typval_T *our_tv; @@ -602,7 +602,7 @@ IterNew(void *start, destructorfun destr { IterObject *self; - self = PyObject_NEW(IterObject, &IterType); + self = PyObject_GC_New(IterObject, &IterType); self->cur = start; self->next = next; self->destruct = destruct; @@ -615,9 +615,9 @@ IterNew(void *start, destructorfun destr static void IterDestructor(IterObject *self) { + PyObject_GC_UnTrack((void *)(self)); self->destruct(self->cur); - - DESTRUCTOR_FINISH(self); + PyObject_GC_Del((void *)(self)); } static int @@ -1414,7 +1414,7 @@ OptionsNew(int opt_type, void *from, che { OptionsObject *self; - self = PyObject_NEW(OptionsObject, &OptionsType); + self = PyObject_GC_New(OptionsObject, &OptionsType); if (self == NULL) return NULL; @@ -1431,9 +1431,9 @@ OptionsNew(int opt_type, void *from, che static void OptionsDestructor(OptionsObject *self) { - if (self->fromObj) - Py_DECREF(self->fromObj); - DESTRUCTOR_FINISH(self); + PyObject_GC_UnTrack((void *)(self)); + Py_XDECREF(self->fromObj); + PyObject_GC_Del((void *)(self)); } static int @@ -1869,7 +1869,7 @@ WindowNew(win_T *win, tabpage_T *tab) } else { - self = PyObject_NEW(WindowObject, &WindowType); + self = PyObject_GC_New(WindowObject, &WindowType); if (self == NULL) return NULL; self->win = win; @@ -1884,12 +1884,25 @@ WindowNew(win_T *win, tabpage_T *tab) static void WindowDestructor(WindowObject *self) { + PyObject_GC_UnTrack((void *)(self)); if (self->win && self->win != INVALID_WINDOW_VALUE) WIN_PYTHON_REF(self->win) = NULL; - - Py_DECREF(((PyObject *)(self->tabObject))); - - DESTRUCTOR_FINISH(self); + Py_XDECREF(((PyObject *)(self->tabObject))); + PyObject_GC_Del((void *)(self)); +} + + static int +WindowTraverse(WindowObject *self, visitproc visit, void *arg) +{ + Py_VISIT(((PyObject *)(self->tabObject))); + return 0; +} + + static int +WindowClear(WindowObject *self) +{ + Py_CLEAR(self->tabObject); + return 0; } static win_T * @@ -1909,19 +1922,6 @@ get_firstwin(TabPageObject *tabObject) else return firstwin; } - static int -WindowTraverse(WindowObject *self, visitproc visit, void *arg) -{ - Py_VISIT(((PyObject *)(self->tabObject))); - return 0; -} - - static int -WindowClear(WindowObject *self) -{ - Py_CLEAR(self->tabObject); - return 0; -} static PyObject * WindowAttr(WindowObject *self, char *name) @@ -2917,7 +2917,7 @@ RangeNew(buf_T *buf, PyInt start, PyInt { BufferObject *bufr; RangeObject *self; - self = PyObject_NEW(RangeObject, &RangeType); + self = PyObject_GC_New(RangeObject, &RangeType); if (self == NULL) return NULL; @@ -2939,8 +2939,23 @@ RangeNew(buf_T *buf, PyInt start, PyInt static void RangeDestructor(RangeObject *self) { + PyObject_GC_UnTrack((void *)(self)); Py_XDECREF(self->buf); - DESTRUCTOR_FINISH(self); + PyObject_GC_Del((void *)(self)); +} + + static int +RangeTraverse(RangeObject *self, visitproc visit, void *arg) +{ + Py_VISIT(((PyObject *)(self->buf))); + return 0; +} + + static int +RangeClear(RangeObject *self) +{ + Py_CLEAR(self->buf); + return 0; } static PyInt @@ -3267,14 +3282,16 @@ BufMapIterDestruct(PyObject *buffer) static int BufMapIterTraverse(PyObject *buffer, visitproc visit, void *arg) { - Py_VISIT(buffer); + if (buffer) + Py_VISIT(buffer); return 0; } static int BufMapIterClear(PyObject **buffer) { - Py_CLEAR(*buffer); + if (*buffer) + Py_CLEAR(*buffer); return 0; } @@ -4144,6 +4161,8 @@ init_structs(void) RangeType.tp_flags = Py_TPFLAGS_DEFAULT; RangeType.tp_doc = "vim Range object"; RangeType.tp_methods = RangeMethods; + RangeType.tp_traverse = (traverseproc)RangeTraverse; + RangeType.tp_clear = (inquiry)RangeClear; #if PY_MAJOR_VERSION >= 3 RangeType.tp_getattro = (getattrofunc)RangeGetattro; RangeType.tp_alloc = call_PyType_GenericAlloc; diff --git a/src/if_python.c b/src/if_python.c --- a/src/if_python.c +++ b/src/if_python.c @@ -224,6 +224,9 @@ struct PyMethodDef { Py_ssize_t a; }; # define Py_Finalize dll_Py_Finalize # define Py_IsInitialized dll_Py_IsInitialized # define _PyObject_New dll__PyObject_New +# define _PyObject_GC_New dll__PyObject_GC_New +# define PyObject_GC_Del dll_PyObject_GC_Del +# define PyObject_GC_UnTrack dll_PyObject_GC_UnTrack # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000 # define _PyObject_NextNotImplemented (*dll__PyObject_NextNotImplemented) # endif @@ -331,6 +334,9 @@ static void(*dll_Py_Initialize)(void); static void(*dll_Py_Finalize)(void); static int(*dll_Py_IsInitialized)(void); static PyObject*(*dll__PyObject_New)(PyTypeObject *, PyObject *); +static PyObject*(*dll__PyObject_GC_New)(PyTypeObject *); +static void(*dll_PyObject_GC_Del)(void *); +static void(*dll_PyObject_GC_UnTrack)(void *); static PyObject*(*dll__PyObject_Init)(PyObject *, PyTypeObject *); static PyObject* (*dll_PyObject_GetIter)(PyObject *); static int (*dll_PyObject_IsTrue)(PyObject *); @@ -474,6 +480,9 @@ static struct {"Py_Finalize", (PYTHON_PROC*)&dll_Py_Finalize}, {"Py_IsInitialized", (PYTHON_PROC*)&dll_Py_IsInitialized}, {"_PyObject_New", (PYTHON_PROC*)&dll__PyObject_New}, + {"_PyObject_GC_New", (PYTHON_PROC*)&dll__PyObject_GC_New}, + {"PyObject_GC_Del", (PYTHON_PROC*)&dll_PyObject_GC_Del}, + {"PyObject_GC_UnTrack", (PYTHON_PROC*)&dll_PyObject_GC_UnTrack}, {"PyObject_Init", (PYTHON_PROC*)&dll__PyObject_Init}, {"PyObject_GetIter", (PYTHON_PROC*)&dll_PyObject_GetIter}, {"PyObject_IsTrue", (PYTHON_PROC*)&dll_PyObject_IsTrue}, @@ -632,7 +641,7 @@ static int initialised = 0; #define DICTKEY_UNREF #define DICTKEY_DECL -#define DESTRUCTOR_FINISH(self) Py_DECREF(self); +#define DESTRUCTOR_FINISH(self) Py_TYPE(self)->tp_free((PyObject*)self); #define WIN_PYTHON_REF(win) win->w_python_ref #define BUF_PYTHON_REF(buf) buf->b_python_ref diff --git a/src/if_python3.c b/src/if_python3.c --- a/src/if_python3.c +++ b/src/if_python3.c @@ -213,6 +213,9 @@ # define PyObject_Malloc py3_PyObject_Malloc # define PyObject_Free py3_PyObject_Free # endif +# define _PyObject_GC_New py3__PyObject_GC_New +# define PyObject_GC_Del py3_PyObject_GC_Del +# define PyObject_GC_UnTrack py3_PyObject_GC_UnTrack # define PyType_GenericAlloc py3_PyType_GenericAlloc # define PyType_GenericNew py3_PyType_GenericNew # define PyModule_Create2 py3_PyModule_Create2 @@ -334,6 +337,9 @@ static void* (*py3_PyCapsule_GetPointer) static void (*py3_PyObject_Free)(void*); static void* (*py3_PyObject_Malloc)(size_t); # endif +static PyObject*(*py3__PyObject_GC_New)(PyTypeObject *); +static void(*py3_PyObject_GC_Del)(void *); +static void(*py3_PyObject_GC_UnTrack)(void *); static int (*py3_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *); static HINSTANCE hinstPy3 = 0; /* Instance of python.dll */ @@ -463,6 +469,9 @@ static struct {"PyObject_Malloc", (PYTHON_PROC*)&py3_PyObject_Malloc}, {"PyObject_Free", (PYTHON_PROC*)&py3_PyObject_Free}, # endif + {"_PyObject_GC_New", (PYTHON_PROC*)&py3__PyObject_GC_New}, + {"PyObject_GC_Del", (PYTHON_PROC*)&py3_PyObject_GC_Del}, + {"PyObject_GC_UnTrack", (PYTHON_PROC*)&py3_PyObject_GC_UnTrack}, {"PyType_IsSubtype", (PYTHON_PROC*)&py3_PyType_IsSubtype}, {"PyCapsule_New", (PYTHON_PROC*)&py3_PyCapsule_New}, {"PyCapsule_GetPointer", (PYTHON_PROC*)&py3_PyCapsule_GetPointer}, @@ -638,7 +647,7 @@ static int py3initialised = 0; if (bytes != NULL) \ Py_XDECREF(bytes); -#define DESTRUCTOR_FINISH(self) Py_TYPE(self)->tp_free((PyObject*)self); +#define DESTRUCTOR_FINISH(self) Py_TYPE(self)->tp_free((PyObject*)self) #define WIN_PYTHON_REF(win) win->w_python3_ref #define BUF_PYTHON_REF(buf) buf->b_python3_ref diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 998, +/**/ 997, /**/ 996,