diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2008-08-29 18:39:48 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2008-08-29 18:39:48 (GMT) |
commit | d4ae97bc38780aab5f348b73fee67eaab7546441 (patch) | |
tree | 62ef9d69e065bea64123dc4493ee955ac8553499 /Python/getargs.c | |
parent | a27e89bd04d8423dde480a9832400401b38bfc68 (diff) | |
download | cpython-d4ae97bc38780aab5f348b73fee67eaab7546441.zip cpython-d4ae97bc38780aab5f348b73fee67eaab7546441.tar.gz cpython-d4ae97bc38780aab5f348b73fee67eaab7546441.tar.bz2 |
#3668: When PyArg_ParseTuple correctly parses a s* format, but raises an
exception afterwards (for a subsequent parameter), the user code will
not call PyBuffer_Release() and memory will leak.
Reviewed by Amaury Forgeot d'Arc.
Diffstat (limited to 'Python/getargs.c')
-rw-r--r-- | Python/getargs.c | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/Python/getargs.c b/Python/getargs.c index 766a2d7..9d1f0b2 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -139,24 +139,35 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va) /* Handle cleanup of allocated memory in case of exception */ +static void +cleanup_ptr(void *ptr) +{ + PyMem_FREE(ptr); +} + +static void +cleanup_buffer(void *ptr) +{ + PyBuffer_Release((Py_buffer *) ptr); +} + static int -addcleanup(void *ptr, PyObject **freelist) +addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *)) { PyObject *cobj; if (!*freelist) { *freelist = PyList_New(0); if (!*freelist) { - PyMem_FREE(ptr); + destr(ptr); return -1; } } - cobj = PyCObject_FromVoidPtr(ptr, NULL); + cobj = PyCObject_FromVoidPtr(ptr, destr); if (!cobj) { - PyMem_FREE(ptr); + destr(ptr); return -1; } if (PyList_Append(*freelist, cobj)) { - PyMem_FREE(ptr); Py_DECREF(cobj); return -1; } @@ -167,15 +178,15 @@ addcleanup(void *ptr, PyObject **freelist) static int cleanreturn(int retval, PyObject *freelist) { - if (freelist) { - if (retval == 0) { - Py_ssize_t len = PyList_GET_SIZE(freelist), i; - for (i = 0; i < len; i++) - PyMem_FREE(PyCObject_AsVoidPtr( - PyList_GET_ITEM(freelist, i))); - } - Py_DECREF(freelist); + if (freelist && retval != 0) { + /* We were successful, reset the destructors so that they + don't get called. */ + Py_ssize_t len = PyList_GET_SIZE(freelist), i; + for (i = 0; i < len; i++) + ((PyCObject *) PyList_GET_ITEM(freelist, i)) + ->destructor = NULL; } + Py_XDECREF(freelist); return retval; } @@ -798,6 +809,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } + if (addcleanup(p, freelist, cleanup_buffer)) { + return converterr( + "(cleanup problem)", + arg, msgbuf, bufsize); + } format++; } else if (*format == '#') { void **p = (void **)va_arg(*p_va, char **); @@ -875,6 +891,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } + if (addcleanup(p, freelist, cleanup_buffer)) { + return converterr( + "(cleanup problem)", + arg, msgbuf, bufsize); + } format++; } else if (*format == '#') { /* any buffer-like object */ void **p = (void **)va_arg(*p_va, char **); @@ -1051,7 +1072,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, "(memory error)", arg, msgbuf, bufsize); } - if (addcleanup(*buffer, freelist)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1096,7 +1117,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, return converterr("(memory error)", arg, msgbuf, bufsize); } - if (addcleanup(*buffer, freelist)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); @@ -1214,6 +1235,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, PyErr_Clear(); return converterr("read-write buffer", arg, msgbuf, bufsize); } + if (addcleanup(p, freelist, cleanup_buffer)) { + return converterr( + "(cleanup problem)", + arg, msgbuf, bufsize); + } if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) return converterr("contiguous buffer", arg, msgbuf, bufsize); break; |