#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.
This commit is contained in:
parent
a27e89bd04
commit
d4ae97bc38
|
@ -48,6 +48,15 @@ PyAPI_FUNC(void *) PyCObject_Import(char *module_name, char *cobject_name);
|
||||||
/* Modify a C object. Fails (==0) if object has a destructor. */
|
/* Modify a C object. Fails (==0) if object has a destructor. */
|
||||||
PyAPI_FUNC(int) PyCObject_SetVoidPtr(PyObject *self, void *cobj);
|
PyAPI_FUNC(int) PyCObject_SetVoidPtr(PyObject *self, void *cobj);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
void *cobject;
|
||||||
|
void *desc;
|
||||||
|
void (*destructor)(void *);
|
||||||
|
} PyCObject;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,10 @@ What's New in Python 2.6 release candidate 1?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #3668: Fix a memory leak with the "s*" argument parser in
|
||||||
|
PyArg_ParseTuple and friends, which occurred when the argument for "s*"
|
||||||
|
was correctly parsed but parsing of subsequent arguments failed.
|
||||||
|
|
||||||
- Issue #2534: speed up isinstance() and issubclass() by 50-70%, so as to
|
- Issue #2534: speed up isinstance() and issubclass() by 50-70%, so as to
|
||||||
match Python 2.5 speed despite the __instancecheck__ / __subclasscheck__
|
match Python 2.5 speed despite the __instancecheck__ / __subclasscheck__
|
||||||
mechanism. In the process, fix a bug where isinstance() and issubclass(),
|
mechanism. In the process, fix a bug where isinstance() and issubclass(),
|
||||||
|
|
|
@ -9,13 +9,6 @@
|
||||||
typedef void (*destructor1)(void *);
|
typedef void (*destructor1)(void *);
|
||||||
typedef void (*destructor2)(void *, void*);
|
typedef void (*destructor2)(void *, void*);
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD
|
|
||||||
void *cobject;
|
|
||||||
void *desc;
|
|
||||||
void (*destructor)(void *);
|
|
||||||
} PyCObject;
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *))
|
PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *))
|
||||||
{
|
{
|
||||||
|
|
|
@ -139,24 +139,35 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
|
||||||
|
|
||||||
/* Handle cleanup of allocated memory in case of exception */
|
/* 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
|
static int
|
||||||
addcleanup(void *ptr, PyObject **freelist)
|
addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
|
||||||
{
|
{
|
||||||
PyObject *cobj;
|
PyObject *cobj;
|
||||||
if (!*freelist) {
|
if (!*freelist) {
|
||||||
*freelist = PyList_New(0);
|
*freelist = PyList_New(0);
|
||||||
if (!*freelist) {
|
if (!*freelist) {
|
||||||
PyMem_FREE(ptr);
|
destr(ptr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cobj = PyCObject_FromVoidPtr(ptr, NULL);
|
cobj = PyCObject_FromVoidPtr(ptr, destr);
|
||||||
if (!cobj) {
|
if (!cobj) {
|
||||||
PyMem_FREE(ptr);
|
destr(ptr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (PyList_Append(*freelist, cobj)) {
|
if (PyList_Append(*freelist, cobj)) {
|
||||||
PyMem_FREE(ptr);
|
|
||||||
Py_DECREF(cobj);
|
Py_DECREF(cobj);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -167,15 +178,15 @@ addcleanup(void *ptr, PyObject **freelist)
|
||||||
static int
|
static int
|
||||||
cleanreturn(int retval, PyObject *freelist)
|
cleanreturn(int retval, PyObject *freelist)
|
||||||
{
|
{
|
||||||
if (freelist) {
|
if (freelist && retval != 0) {
|
||||||
if (retval == 0) {
|
/* We were successful, reset the destructors so that they
|
||||||
|
don't get called. */
|
||||||
Py_ssize_t len = PyList_GET_SIZE(freelist), i;
|
Py_ssize_t len = PyList_GET_SIZE(freelist), i;
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
PyMem_FREE(PyCObject_AsVoidPtr(
|
((PyCObject *) PyList_GET_ITEM(freelist, i))
|
||||||
PyList_GET_ITEM(freelist, i)));
|
->destructor = NULL;
|
||||||
}
|
|
||||||
Py_DECREF(freelist);
|
|
||||||
}
|
}
|
||||||
|
Py_XDECREF(freelist);
|
||||||
return retval;
|
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)
|
if (getbuffer(arg, p, &buf) < 0)
|
||||||
return converterr(buf, arg, msgbuf, bufsize);
|
return converterr(buf, arg, msgbuf, bufsize);
|
||||||
}
|
}
|
||||||
|
if (addcleanup(p, freelist, cleanup_buffer)) {
|
||||||
|
return converterr(
|
||||||
|
"(cleanup problem)",
|
||||||
|
arg, msgbuf, bufsize);
|
||||||
|
}
|
||||||
format++;
|
format++;
|
||||||
} else if (*format == '#') {
|
} else if (*format == '#') {
|
||||||
void **p = (void **)va_arg(*p_va, char **);
|
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)
|
if (getbuffer(arg, p, &buf) < 0)
|
||||||
return converterr(buf, arg, msgbuf, bufsize);
|
return converterr(buf, arg, msgbuf, bufsize);
|
||||||
}
|
}
|
||||||
|
if (addcleanup(p, freelist, cleanup_buffer)) {
|
||||||
|
return converterr(
|
||||||
|
"(cleanup problem)",
|
||||||
|
arg, msgbuf, bufsize);
|
||||||
|
}
|
||||||
format++;
|
format++;
|
||||||
} else if (*format == '#') { /* any buffer-like object */
|
} else if (*format == '#') { /* any buffer-like object */
|
||||||
void **p = (void **)va_arg(*p_va, char **);
|
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)",
|
"(memory error)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
}
|
}
|
||||||
if (addcleanup(*buffer, freelist)) {
|
if (addcleanup(*buffer, freelist, cleanup_ptr)) {
|
||||||
Py_DECREF(s);
|
Py_DECREF(s);
|
||||||
return converterr(
|
return converterr(
|
||||||
"(cleanup problem)",
|
"(cleanup problem)",
|
||||||
|
@ -1096,7 +1117,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
|
||||||
return converterr("(memory error)",
|
return converterr("(memory error)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
}
|
}
|
||||||
if (addcleanup(*buffer, freelist)) {
|
if (addcleanup(*buffer, freelist, cleanup_ptr)) {
|
||||||
Py_DECREF(s);
|
Py_DECREF(s);
|
||||||
return converterr("(cleanup problem)",
|
return converterr("(cleanup problem)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
|
@ -1214,6 +1235,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
return converterr("read-write buffer", arg, msgbuf, bufsize);
|
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'))
|
if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C'))
|
||||||
return converterr("contiguous buffer", arg, msgbuf, bufsize);
|
return converterr("contiguous buffer", arg, msgbuf, bufsize);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue