Skip to content

Commit 78761cf

Browse files
bdracoasvetlov
andauthored
Fix memory leak creating new istr objects (#1133)
Fixes leak 1 from #1131 (comment) (`IStr_New` path) see #1131 (comment) #1131 (comment) #1131 (comment) This also seems to fix the perf regression in popitem from #1097 (comment) https://codspeed.io/aio-libs/multidict/branches/istr-keys introduced #1097 fixes #1131 --------- Co-authored-by: Andrew Svetlov <[email protected]>
1 parent e1dee30 commit 78761cf

File tree

2 files changed

+18
-56
lines changed

2 files changed

+18
-56
lines changed

CHANGES/1133.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed a memory leak creating new :class:`~multidict.istr` objects -- by :user:`bdraco`.
2+
3+
The leak was introduced in 6.3.0

multidict/_multilib/istr.h

Lines changed: 15 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,20 @@ istr_dealloc(istrobject *self)
2727
}
2828

2929
static inline PyObject *
30-
istr_new_with_state(PyTypeObject *type, PyObject *args, PyObject *kwds,
31-
mod_state *state)
30+
istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
3231
{
33-
if (state == NULL) {
34-
PyObject *mod = PyType_GetModuleByDef(type, &multidict_module);
35-
if (mod == NULL) {
36-
return NULL;
37-
}
38-
state = get_mod_state(mod);
32+
PyObject *mod = PyType_GetModuleByDef(type, &multidict_module);
33+
if (mod == NULL) {
34+
return NULL;
3935
}
36+
mod_state *state = get_mod_state(mod);
4037

4138
PyObject *x = NULL;
4239
static char *kwlist[] = {"object", "encoding", "errors", 0};
4340
PyObject *encoding = NULL;
4441
PyObject *errors = NULL;
4542
PyObject *canonical = NULL;
46-
PyObject * ret = NULL;
47-
if (kwds != NULL) {
48-
int cmp = PyDict_Pop(kwds, state->str_canonical, &canonical);
49-
if (cmp < 0) {
50-
return NULL;
51-
} else if (cmp > 0) {
52-
Py_INCREF(canonical);
53-
}
54-
}
43+
PyObject *ret = NULL;
5544

5645
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:str",
5746
kwlist, &x, &encoding, &errors)) {
@@ -65,20 +54,9 @@ istr_new_with_state(PyTypeObject *type, PyObject *args, PyObject *kwds,
6554
if (!ret) {
6655
goto fail;
6756
}
68-
69-
if (canonical == NULL) {
70-
canonical = PyObject_CallMethodNoArgs(ret, state->str_lower);
71-
if (!canonical) {
72-
goto fail;
73-
}
74-
}
75-
if (!PyUnicode_CheckExact(canonical)) {
76-
PyObject *tmp = PyUnicode_FromObject(canonical);
77-
Py_CLEAR(canonical);
78-
if (tmp == NULL) {
79-
goto fail;
80-
}
81-
canonical = tmp;
57+
canonical = PyObject_CallMethodNoArgs(ret, state->str_lower);
58+
if (!canonical) {
59+
goto fail;
8260
}
8361
((istrobject*)ret)->canonical = canonical;
8462
((istrobject*)ret)->state = state;
@@ -88,12 +66,6 @@ istr_new_with_state(PyTypeObject *type, PyObject *args, PyObject *kwds,
8866
return NULL;
8967
}
9068

91-
static inline PyObject *
92-
istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
93-
{
94-
return istr_new_with_state(type, args, kwds, NULL);
95-
}
96-
9769
static inline PyObject *
9870
istr_reduce(PyObject *self)
9971
{
@@ -147,33 +119,20 @@ static inline PyObject *
147119
IStr_New(mod_state *state, PyObject *str, PyObject *canonical)
148120
{
149121
PyObject *args = NULL;
150-
PyObject *kwds = NULL;
151122
PyObject *res = NULL;
152-
153123
args = PyTuple_Pack(1, str);
154124
if (args == NULL) {
155125
goto ret;
156126
}
157-
158-
if (canonical != NULL) {
159-
kwds = PyDict_New();
160-
if (kwds == NULL) {
161-
goto ret;
162-
}
163-
if (!PyUnicode_CheckExact(canonical)) {
164-
PyErr_SetString(PyExc_TypeError,
165-
"'canonical' argument should be exactly str");
166-
goto ret;
167-
}
168-
if (PyDict_SetItem(kwds, state->str_canonical, canonical) < 0) {
169-
goto ret;
170-
}
127+
res = PyUnicode_Type.tp_new(state->IStrType, args, NULL);
128+
if (!res) {
129+
goto ret;
171130
}
172-
173-
res = istr_new_with_state(state->IStrType, args, kwds, state);
131+
Py_INCREF(canonical);
132+
((istrobject*)res)->canonical = canonical;
133+
((istrobject*)res)->state = state;
174134
ret:
175135
Py_CLEAR(args);
176-
Py_CLEAR(kwds);
177136
return res;
178137
}
179138

0 commit comments

Comments
 (0)