Skip to content

Commit d957636

Browse files
authored
Fix memory leak (#306)
1 parent 8e4275d commit d957636

5 files changed

Lines changed: 60 additions & 56 deletions

File tree

docs/changes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
.. _changes:
22

3+
4.5.1 (2018-11-22)
4+
------------------
5+
6+
* Fix a memory leak introduced by 4.5.0 release (:pr:`306`)
7+
38
4.5.0 (2018-11-19)
49
------------------
510

multidict/_multidict.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ cdef class _Base:
3232

3333
def impl(self):
3434
return self._impl
35-
35+
3636
def getall(self, key, default=_marker):
3737
"""Return a list of all values matching the key."""
3838
try:

multidict/_multidict_iter.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ static PyTypeObject multidict_items_iter_type = {
193193
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
194194
0, /* tp_doc */
195195
(traverseproc)multidict_iter_traverse, /* tp_traverse */
196-
multidict_iter_clear, /* tp_clear */
196+
(inquiry)multidict_iter_clear, /* tp_clear */
197197
0, /* tp_richcompare */
198198
0, /* tp_weaklistoffset */
199199
PyObject_SelfIter, /* tp_iter */
@@ -223,7 +223,7 @@ static PyTypeObject multidict_values_iter_type = {
223223
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
224224
0, /* tp_doc */
225225
(traverseproc)multidict_iter_traverse, /* tp_traverse */
226-
multidict_iter_clear, /* tp_clear */
226+
(inquiry)multidict_iter_clear, /* tp_clear */
227227
0, /* tp_richcompare */
228228
0, /* tp_weaklistoffset */
229229
PyObject_SelfIter, /* tp_iter */
@@ -253,7 +253,7 @@ static PyTypeObject multidict_keys_iter_type = {
253253
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
254254
0, /* tp_doc */
255255
(traverseproc)multidict_iter_traverse, /* tp_traverse */
256-
multidict_iter_clear, /* tp_clear */
256+
(inquiry)multidict_iter_clear, /* tp_clear */
257257
0, /* tp_richcompare */
258258
0, /* tp_weaklistoffset */
259259
PyObject_SelfIter, /* tp_iter */

multidict/_multidict_views.c

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,15 @@ multidict_view_len(_Multidict_ViewObject *self)
9494
static PyObject *
9595
multidict_view_richcompare(PyObject *self, PyObject *other, int op)
9696
{
97+
PyObject *ret;
9798
PyObject *op_obj = PyLong_FromLong(op);
98-
return PyObject_CallFunctionObjArgs(
99+
if (op_obj == NULL) {
100+
return NULL;
101+
}
102+
ret = PyObject_CallFunctionObjArgs(
99103
viewbaseset_richcmp_func, self, other, op_obj, NULL);
104+
Py_DECREF(op_obj);
105+
return ret;
100106
}
101107

102108
static PyObject *
@@ -165,11 +171,14 @@ multidict_itemsview_new(PyObject *md)
165171
static PyObject *
166172
multidict_itemsview_iter(_Multidict_ViewObject *self)
167173
{
174+
PyObject *iter;
168175
PyObject *impl = _PyObject_CallMethodId(self->md, &PyId_impl, NULL);
169176
if (impl == NULL) {
170177
return NULL;
171178
}
172-
return multidict_items_iter_new(impl);
179+
iter = multidict_items_iter_new(impl);
180+
Py_DECREF(impl);
181+
return iter;
173182
}
174183

175184
static PyObject *
@@ -211,6 +220,7 @@ multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
211220
*bval = NULL,
212221
*iter = NULL,
213222
*item = NULL;
223+
int ret1, ret2;
214224

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

231-
if (PyObject_RichCompareBool(akey, bkey, Py_EQ) > 0 &&
232-
PyObject_RichCompareBool(aval, bval, Py_EQ) > 0)
241+
ret1 = PyObject_RichCompareBool(akey, bkey, Py_EQ);
242+
if (ret1 < 0) {
243+
Py_DECREF(iter);
244+
Py_DECREF(item);
245+
return -1;
246+
}
247+
ret2 = PyObject_RichCompareBool(aval, bval, Py_EQ);
248+
if (ret2 < 0) {
249+
Py_DECREF(iter);
250+
Py_DECREF(item);
251+
return -1;
252+
}
253+
if (ret1 > 0 && ret2 > 0)
233254
{
234255
Py_DECREF(iter);
235256
Py_DECREF(item);
236257
return 1;
237258
}
238-
259+
239260
Py_DECREF(item);
240261
}
241262

@@ -276,13 +297,13 @@ static PyTypeObject multidict_itemsview_type = {
276297
0, /* tp_hash */
277298
0, /* tp_call */
278299
0, /* tp_str */
279-
0, /* tp_getattro */
300+
PyObject_GenericGetAttr, /* tp_getattro */
280301
0, /* tp_setattro */
281302
0, /* tp_as_buffer */
282303
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
283304
0, /* tp_doc */
284-
multidict_view_traverse, /* tp_traverse */
285-
multidict_view_clear, /* tp_clear */
305+
(traverseproc)multidict_view_traverse, /* tp_traverse */
306+
(inquiry)multidict_view_clear, /* tp_clear */
286307
multidict_view_richcompare, /* tp_richcompare */
287308
0, /* tp_weaklistoffset */
288309
(getiterfunc)multidict_itemsview_iter, /* tp_iter */
@@ -310,11 +331,14 @@ multidict_keysview_new(PyObject *md)
310331
static PyObject *
311332
multidict_keysview_iter(_Multidict_ViewObject *self)
312333
{
334+
PyObject *iter;
313335
PyObject *impl = _PyObject_CallMethodId(self->md, &PyId_impl, NULL);
314336
if (impl == NULL) {
315337
return NULL;
316338
}
317-
return multidict_keys_iter_new(impl);
339+
iter = multidict_keys_iter_new(impl);
340+
Py_DECREF(impl);
341+
return iter;
318342
}
319343

320344
static PyObject *
@@ -385,13 +409,13 @@ static PyTypeObject multidict_keysview_type = {
385409
0, /* tp_hash */
386410
0, /* tp_call */
387411
0, /* tp_str */
388-
0, /* tp_getattro */
412+
PyObject_GenericGetAttr, /* tp_getattro */
389413
0, /* tp_setattro */
390414
0, /* tp_as_buffer */
391415
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
392416
0, /* tp_doc */
393-
multidict_view_traverse, /* tp_traverse */
394-
multidict_view_clear, /* tp_clear */
417+
(traverseproc)multidict_view_traverse, /* tp_traverse */
418+
(inquiry)multidict_view_clear, /* tp_clear */
395419
multidict_view_richcompare, /* tp_richcompare */
396420
0, /* tp_weaklistoffset */
397421
(getiterfunc)multidict_keysview_iter, /* tp_iter */
@@ -419,11 +443,14 @@ multidict_valuesview_new(PyObject *md)
419443
static PyObject *
420444
multidict_valuesview_iter(_Multidict_ViewObject *self)
421445
{
446+
PyObject *iter;
422447
PyObject *impl = _PyObject_CallMethodId(self->md, &PyId_impl, NULL);
423448
if (impl == NULL) {
424449
return NULL;
425450
}
426-
return multidict_values_iter_new(impl);
451+
iter = multidict_values_iter_new(impl);
452+
Py_DECREF(impl);
453+
return iter;
427454
}
428455

429456
static PyObject *
@@ -433,35 +460,6 @@ multidict_valuesview_repr(_Multidict_ViewObject *self)
433460
valuesview_repr_func, self, NULL);
434461
}
435462

436-
static int
437-
multidict_valuesview_contains(_Multidict_ViewObject *self, PyObject *value)
438-
{
439-
PyObject *iter = NULL,
440-
*item = NULL;
441-
442-
iter = multidict_valuesview_iter(self);
443-
if (iter == NULL) {
444-
return 0;
445-
}
446-
447-
while ((item = PyIter_Next(iter)) != NULL) {
448-
if (PyObject_RichCompareBool(item, value, Py_EQ)) {
449-
Py_DECREF(iter);
450-
Py_DECREF(item);
451-
return 1;
452-
}
453-
Py_DECREF(item);
454-
}
455-
456-
Py_DECREF(iter);
457-
458-
if (PyErr_Occurred()) {
459-
return -1;
460-
}
461-
462-
return 0;
463-
}
464-
465463
static PySequenceMethods multidict_valuesview_as_sequence = {
466464
(lenfunc)multidict_view_len, /* sq_length */
467465
0, /* sq_concat */
@@ -470,7 +468,7 @@ static PySequenceMethods multidict_valuesview_as_sequence = {
470468
0, /* sq_slice */
471469
0, /* sq_ass_item */
472470
0, /* sq_ass_slice */
473-
(objobjproc)multidict_valuesview_contains, /* sq_contains */
471+
(objobjproc)0, /* sq_contains */
474472
};
475473

476474
static PyTypeObject multidict_valuesview_type = {
@@ -484,19 +482,19 @@ static PyTypeObject multidict_valuesview_type = {
484482
0, /* tp_setattr */
485483
0, /* tp_reserved */
486484
(reprfunc)multidict_valuesview_repr, /* tp_repr */
487-
&multidict_view_as_number, /* tp_as_number */
485+
0, /* tp_as_number */
488486
&multidict_valuesview_as_sequence, /* tp_as_sequence */
489487
0, /* tp_as_mapping */
490488
0, /* tp_hash */
491489
0, /* tp_call */
492490
0, /* tp_str */
493-
0, /* tp_getattro */
491+
PyObject_GenericGetAttr, /* tp_getattro */
494492
0, /* tp_setattro */
495493
0, /* tp_as_buffer */
496494
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
497495
0, /* tp_doc */
498-
multidict_view_traverse, /* tp_traverse */
499-
multidict_view_clear, /* tp_clear */
496+
(traverseproc)multidict_view_traverse, /* tp_traverse */
497+
(inquiry)multidict_view_clear, /* tp_clear */
500498
0, /* tp_richcompare */
501499
0, /* tp_weaklistoffset */
502500
(getiterfunc)multidict_valuesview_iter, /* tp_iter */
@@ -530,7 +528,7 @@ multidict_views_init()
530528

531529
GET_MOD_ATTR(itemsview_repr_func, "_itemsview_isdisjoint");
532530
GET_MOD_ATTR(itemsview_repr_func, "_itemsview_repr");
533-
531+
534532
GET_MOD_ATTR(keysview_repr_func, "_keysview_repr");
535533
GET_MOD_ATTR(keysview_isdisjoint_func, "_keysview_isdisjoint");
536534

@@ -539,10 +537,10 @@ multidict_views_init()
539537
if (multidict_iter_init() < 0) {
540538
goto fail;
541539
}
542-
540+
543541
if (PyType_Ready(&multidict_itemsview_type) < 0 ||
544542
PyType_Ready(&multidict_valuesview_type) < 0 ||
545-
PyType_Ready(&multidict_keysview_type) < 0)
543+
PyType_Ready(&multidict_keysview_type) < 0)
546544
{
547545
goto fail;
548546
}

multidict/_pair_list.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ pair_list_resize(pair_list_t *list, Py_ssize_t new_capacity)
124124
return 0;
125125
}
126126

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

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

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

301302
if (list->capacity - list->size > MIN_LIST_CAPACITY) {
302303
return pair_list_resize(list, list->capacity - MIN_LIST_CAPACITY);

0 commit comments

Comments
 (0)