changeset 4500:47e6dec5ce3c v7.3.998

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)
author Bram Moolenaar <bram@vim.org>
date Tue, 21 May 2013 20:51:59 +0200
parents 364b26198af6
children f4d9819ae32b
files src/if_py_both.h src/if_python.c src/if_python3.c src/version.c
diffstat 4 files changed, 71 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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
--- 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
--- 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,