Clean the C members of Error in tp_dealloc instead of tp_clear

tp_clear should only be used to break the reference cycles. tp_clear was
causing a segfault because it was called twice (by the gc and by _dealloc) so
self->codec was freed twice.

Amazingly the double free was only causing a segfault on Python 3.3 (released
in late 2012) talking to Postgres 8.1 (released in 2005) in async mode... no
other combination crashed. Thank you buildbot.
This commit is contained in:
Daniele Varrazzo 2013-03-21 11:51:29 +00:00
parent d5316d7eb2
commit 3b8abf3fc4

View File

@ -93,6 +93,7 @@ error_traverse(errorObject *self, visitproc visit, void *arg)
Py_VISIT(self->pgerror); Py_VISIT(self->pgerror);
Py_VISIT(self->pgcode); Py_VISIT(self->pgcode);
Py_VISIT(self->cursor); Py_VISIT(self->cursor);
return ((PyTypeObject *)PyExc_StandardError)->tp_traverse( return ((PyTypeObject *)PyExc_StandardError)->tp_traverse(
(PyObject *)self, visit, arg); (PyObject *)self, visit, arg);
} }
@ -104,16 +105,17 @@ error_clear(errorObject *self)
Py_CLEAR(self->pgcode); Py_CLEAR(self->pgcode);
Py_CLEAR(self->cursor); Py_CLEAR(self->cursor);
PyMem_Free(self->codec);
CLEARPGRES(self->pgres);
return ((PyTypeObject *)PyExc_StandardError)->tp_clear((PyObject *)self); return ((PyTypeObject *)PyExc_StandardError)->tp_clear((PyObject *)self);
} }
static void static void
error_dealloc(errorObject *self) error_dealloc(errorObject *self)
{ {
PyObject_GC_UnTrack((PyObject *)self);
error_clear(self); error_clear(self);
PyMem_Free(self->codec);
CLEARPGRES(self->pgres);
return Py_TYPE(self)->tp_free((PyObject *)self); return Py_TYPE(self)->tp_free((PyObject *)self);
} }