diff options
author | mathieui <mathieui@mathieui.net> | 2014-04-27 21:33:00 +0200 |
---|---|---|
committer | mathieui <mathieui@mathieui.net> | 2014-04-27 21:38:29 +0200 |
commit | 3fb3d8db3d566f231ea6ff6afd559a0185d8bff7 (patch) | |
tree | cb4d084f003401c4403e602d39c0333361fae23d /src/pooptmodule.c | |
parent | 5999b71c416f02dc11803bf52a406b9109ddc3c1 (diff) | |
download | poezio-3fb3d8db3d566f231ea6ff6afd559a0185d8bff7.tar.gz poezio-3fb3d8db3d566f231ea6ff6afd559a0185d8bff7.tar.bz2 poezio-3fb3d8db3d566f231ea6ff6afd559a0185d8bff7.tar.xz poezio-3fb3d8db3d566f231ea6ff6afd559a0185d8bff7.zip |
Fix memleaks in pooptmodule.cut_text (ref #1914)
- we need to decrement the refcount after giving the tuple to the
retlist in order to transfer ownership
The example script below will quickly take gigabytes of ram with the
old module, while the new will not take noticeably more memory.
The leak is not very visible on launch, because we “only” leaked each
tuple returned, and (int, int) is not heavy. However, after weeks of
use and many messages, the memory still isn’t freed and it shows.
import poopt
import gc
a = 'coucouco ' * 1000
for i in range(100000):
if not (i % 10000):
print(i)
poopt.cut_text(a, 50)
Diffstat (limited to 'src/pooptmodule.c')
-rw-r--r-- | src/pooptmodule.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/src/pooptmodule.c b/src/pooptmodule.c index 4dab1088..69fb7f6f 100644 --- a/src/pooptmodule.c +++ b/src/pooptmodule.c @@ -63,6 +63,8 @@ static PyObject* poopt_cut_text(PyObject* self, PyObject* args) { /* The list of tuples that we return */ PyObject* retlist = PyList_New(0); + /* The temporary name for the tuples */ + PyObject* tmp; /* Get the python arguments */ const size_t width; @@ -146,8 +148,13 @@ static PyObject* poopt_cut_text(PyObject* self, PyObject* args) if (wc == (wchar_t)'\n') { spos++; - if (PyList_Append(retlist, Py_BuildValue("II", start_pos, spos)) == -1) + tmp = Py_BuildValue("II", start_pos, spos); + if (PyList_Append(retlist, tmp) == -1) + { + Py_XDECREF(tmp); return NULL; + } + Py_XDECREF(tmp); /* And then initiate a new line */ start_pos = spos; last_space = -1; @@ -164,8 +171,13 @@ static PyObject* poopt_cut_text(PyObject* self, PyObject* args) { /* If possible, cut on a space */ if (last_space != -1) { - if (PyList_Append(retlist, Py_BuildValue("II", start_pos, last_space)) == -1) + tmp = Py_BuildValue("II", start_pos, last_space); + if (PyList_Append(retlist, tmp) == -1) + { + Py_XDECREF(tmp); return NULL; + } + Py_XDECREF(tmp); start_pos = last_space + 1; last_space = -1; columns -= (cols_until_space + 1); @@ -173,8 +185,13 @@ static PyObject* poopt_cut_text(PyObject* self, PyObject* args) else { /* Otherwise, cut in the middle of a word */ - if (PyList_Append(retlist, Py_BuildValue("II", start_pos, spos)) == -1) + tmp = Py_BuildValue("II", start_pos, spos); + if (PyList_Append(retlist, tmp) == -1) + { + Py_XDECREF(tmp); return NULL; + } + Py_XDECREF(tmp); start_pos = spos; columns = 0; } @@ -194,8 +211,13 @@ static PyObject* poopt_cut_text(PyObject* self, PyObject* args) spos++; } /* We are at the end of the string, append the last line, not finished */ - if (PyList_Append(retlist, Py_BuildValue("II", start_pos, spos)) == -1) + tmp = Py_BuildValue("II", start_pos, spos); + if (PyList_Append(retlist, tmp) == -1) + { + Py_XDECREF(tmp); return NULL; + } + Py_XDECREF(tmp); return retlist; } |