Skip to content

Commit

Permalink
Fix memory leak (#306)
Browse files Browse the repository at this point in the history
  • Loading branch information
asvetlov authored Nov 22, 2018
1 parent 8e4275d commit d957636
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 56 deletions.
5 changes: 5 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
.. _changes:

4.5.1 (2018-11-22)
------------------

* Fix a memory leak introduced by 4.5.0 release (:pr:`306`)

4.5.0 (2018-11-19)
------------------

Expand Down
2 changes: 1 addition & 1 deletion multidict/_multidict.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ cdef class _Base:

def impl(self):
return self._impl

def getall(self, key, default=_marker):
"""Return a list of all values matching the key."""
try:
Expand Down
6 changes: 3 additions & 3 deletions multidict/_multidict_iter.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static PyTypeObject multidict_items_iter_type = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)multidict_iter_traverse, /* tp_traverse */
multidict_iter_clear, /* tp_clear */
(inquiry)multidict_iter_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
Expand Down Expand Up @@ -223,7 +223,7 @@ static PyTypeObject multidict_values_iter_type = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)multidict_iter_traverse, /* tp_traverse */
multidict_iter_clear, /* tp_clear */
(inquiry)multidict_iter_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
Expand Down Expand Up @@ -253,7 +253,7 @@ static PyTypeObject multidict_keys_iter_type = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)multidict_iter_traverse, /* tp_traverse */
multidict_iter_clear, /* tp_clear */
(inquiry)multidict_iter_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
Expand Down
98 changes: 48 additions & 50 deletions multidict/_multidict_views.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,15 @@ multidict_view_len(_Multidict_ViewObject *self)
static PyObject *
multidict_view_richcompare(PyObject *self, PyObject *other, int op)
{
PyObject *ret;
PyObject *op_obj = PyLong_FromLong(op);
return PyObject_CallFunctionObjArgs(
if (op_obj == NULL) {
return NULL;
}
ret = PyObject_CallFunctionObjArgs(
viewbaseset_richcmp_func, self, other, op_obj, NULL);
Py_DECREF(op_obj);
return ret;
}

static PyObject *
Expand Down Expand Up @@ -165,11 +171,14 @@ multidict_itemsview_new(PyObject *md)
static PyObject *
multidict_itemsview_iter(_Multidict_ViewObject *self)
{
PyObject *iter;
PyObject *impl = _PyObject_CallMethodId(self->md, &PyId_impl, NULL);
if (impl == NULL) {
return NULL;
}
return multidict_items_iter_new(impl);
iter = multidict_items_iter_new(impl);
Py_DECREF(impl);
return iter;
}

static PyObject *
Expand Down Expand Up @@ -211,6 +220,7 @@ multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
*bval = NULL,
*iter = NULL,
*item = NULL;
int ret1, ret2;

if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2) {
return 0;
Expand All @@ -228,14 +238,25 @@ multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
akey = PyTuple_GET_ITEM(item, 0);
aval = PyTuple_GET_ITEM(item, 1);

if (PyObject_RichCompareBool(akey, bkey, Py_EQ) > 0 &&
PyObject_RichCompareBool(aval, bval, Py_EQ) > 0)
ret1 = PyObject_RichCompareBool(akey, bkey, Py_EQ);
if (ret1 < 0) {
Py_DECREF(iter);
Py_DECREF(item);
return -1;
}
ret2 = PyObject_RichCompareBool(aval, bval, Py_EQ);
if (ret2 < 0) {
Py_DECREF(iter);
Py_DECREF(item);
return -1;
}
if (ret1 > 0 && ret2 > 0)
{
Py_DECREF(iter);
Py_DECREF(item);
return 1;
}

Py_DECREF(item);
}

Expand Down Expand Up @@ -276,13 +297,13 @@ static PyTypeObject multidict_itemsview_type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
multidict_view_traverse, /* tp_traverse */
multidict_view_clear, /* tp_clear */
(traverseproc)multidict_view_traverse, /* tp_traverse */
(inquiry)multidict_view_clear, /* tp_clear */
multidict_view_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)multidict_itemsview_iter, /* tp_iter */
Expand Down Expand Up @@ -310,11 +331,14 @@ multidict_keysview_new(PyObject *md)
static PyObject *
multidict_keysview_iter(_Multidict_ViewObject *self)
{
PyObject *iter;
PyObject *impl = _PyObject_CallMethodId(self->md, &PyId_impl, NULL);
if (impl == NULL) {
return NULL;
}
return multidict_keys_iter_new(impl);
iter = multidict_keys_iter_new(impl);
Py_DECREF(impl);
return iter;
}

static PyObject *
Expand Down Expand Up @@ -385,13 +409,13 @@ static PyTypeObject multidict_keysview_type = {
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
multidict_view_traverse, /* tp_traverse */
multidict_view_clear, /* tp_clear */
(traverseproc)multidict_view_traverse, /* tp_traverse */
(inquiry)multidict_view_clear, /* tp_clear */
multidict_view_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)multidict_keysview_iter, /* tp_iter */
Expand Down Expand Up @@ -419,11 +443,14 @@ multidict_valuesview_new(PyObject *md)
static PyObject *
multidict_valuesview_iter(_Multidict_ViewObject *self)
{
PyObject *iter;
PyObject *impl = _PyObject_CallMethodId(self->md, &PyId_impl, NULL);
if (impl == NULL) {
return NULL;
}
return multidict_values_iter_new(impl);
iter = multidict_values_iter_new(impl);
Py_DECREF(impl);
return iter;
}

static PyObject *
Expand All @@ -433,35 +460,6 @@ multidict_valuesview_repr(_Multidict_ViewObject *self)
valuesview_repr_func, self, NULL);
}

static int
multidict_valuesview_contains(_Multidict_ViewObject *self, PyObject *value)
{
PyObject *iter = NULL,
*item = NULL;

iter = multidict_valuesview_iter(self);
if (iter == NULL) {
return 0;
}

while ((item = PyIter_Next(iter)) != NULL) {
if (PyObject_RichCompareBool(item, value, Py_EQ)) {
Py_DECREF(iter);
Py_DECREF(item);
return 1;
}
Py_DECREF(item);
}

Py_DECREF(iter);

if (PyErr_Occurred()) {
return -1;
}

return 0;
}

static PySequenceMethods multidict_valuesview_as_sequence = {
(lenfunc)multidict_view_len, /* sq_length */
0, /* sq_concat */
Expand All @@ -470,7 +468,7 @@ static PySequenceMethods multidict_valuesview_as_sequence = {
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)multidict_valuesview_contains, /* sq_contains */
(objobjproc)0, /* sq_contains */
};

static PyTypeObject multidict_valuesview_type = {
Expand All @@ -484,19 +482,19 @@ static PyTypeObject multidict_valuesview_type = {
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)multidict_valuesview_repr, /* tp_repr */
&multidict_view_as_number, /* tp_as_number */
0, /* tp_as_number */
&multidict_valuesview_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
multidict_view_traverse, /* tp_traverse */
multidict_view_clear, /* tp_clear */
(traverseproc)multidict_view_traverse, /* tp_traverse */
(inquiry)multidict_view_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)multidict_valuesview_iter, /* tp_iter */
Expand Down Expand Up @@ -530,7 +528,7 @@ multidict_views_init()

GET_MOD_ATTR(itemsview_repr_func, "_itemsview_isdisjoint");
GET_MOD_ATTR(itemsview_repr_func, "_itemsview_repr");

GET_MOD_ATTR(keysview_repr_func, "_keysview_repr");
GET_MOD_ATTR(keysview_isdisjoint_func, "_keysview_isdisjoint");

Expand All @@ -539,10 +537,10 @@ multidict_views_init()
if (multidict_iter_init() < 0) {
goto fail;
}

if (PyType_Ready(&multidict_itemsview_type) < 0 ||
PyType_Ready(&multidict_valuesview_type) < 0 ||
PyType_Ready(&multidict_keysview_type) < 0)
PyType_Ready(&multidict_keysview_type) < 0)
{
goto fail;
}
Expand Down
5 changes: 3 additions & 2 deletions multidict/_pair_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pair_list_resize(pair_list_t *list, Py_ssize_t new_capacity)
return 0;
}

new_pairs = PyMem_Resize(list->pairs, pair_t, new_capacity);
new_pairs = PyMem_Resize(list->pairs, pair_t, (size_t)new_capacity);

if (NULL == new_pairs) {
// if not enought mem for realloc we do nothing, just return false
Expand Down Expand Up @@ -294,9 +294,10 @@ pair_list_del_at(pair_list_t *list, Py_ssize_t pos)
}

tail = list->size - pos;
// TODO: raise an error if tail < 0
memmove((void *)pair_list_get(list, pos),
(void *)pair_list_get(list, pos + 1),
sizeof(pair_t) * tail);
sizeof(pair_t) * (size_t)tail);

if (list->capacity - list->size > MIN_LIST_CAPACITY) {
return pair_list_resize(list, list->capacity - MIN_LIST_CAPACITY);
Expand Down

0 comments on commit d957636

Please sign in to comment.