From 9edd2bd35cfc5f33b53c5def02cac23e7bb6e84b Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 27 Aug 2008 00:31:37 +0000 Subject: Fix #3651 various memory leaks when using the buffer interface by Amaury Forgeot d'Arc Reviewer: Antoine Pitrou --- Include/object.h | 2 +- Misc/NEWS | 4 ++++ Modules/binascii.c | 3 +++ Objects/abstract.c | 3 +++ Python/getargs.c | 21 +++++++++++---------- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Include/object.h b/Include/object.h index 60584a0..bddfb6f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -143,7 +143,7 @@ typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); /* buffer interface */ typedef struct bufferinfo { void *buf; - PyObject *obj; /* borrowed reference */ + PyObject *obj; /* owned reference */ Py_ssize_t len; Py_ssize_t itemsize; /* This is Py_ssize_t so it can be pointed to by strides in simple case.*/ diff --git a/Misc/NEWS b/Misc/NEWS index e001936..3927f9b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,10 @@ Core and Builtins - Issue #3663: Py_None was decref'd when printing SyntaxErrors. +- Issue #3651: Fix various memory leaks when using the buffer + interface, or when the "s#" code of PyArg_ParseTuple is given a + bytes object. + - Issue #3657: Fix uninitialized memory read when pickling longs. Found by valgrind. diff --git a/Modules/binascii.c b/Modules/binascii.c index 82c1423..c6e0362 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -231,6 +231,7 @@ binascii_a2b_uu(PyObject *self, PyObject *args) */ if ( this_ch < ' ' || this_ch > (' ' + 64)) { PyErr_SetString(Error, "Illegal char"); + PyBuffer_Release(&pascii); Py_DECREF(rv); return NULL; } @@ -259,6 +260,7 @@ binascii_a2b_uu(PyObject *self, PyObject *args) if ( this_ch != ' ' && this_ch != ' '+64 && this_ch != '\n' && this_ch != '\r' ) { PyErr_SetString(Error, "Trailing garbage"); + PyBuffer_Release(&pascii); Py_DECREF(rv); return NULL; } @@ -805,6 +807,7 @@ binascii_rledecode_hqx(PyObject *self, PyObject *args) ** of the string only). This is a programmer error. */ PyErr_SetString(Error, "Orphaned RLE code at start"); + PyBuffer_Release(&pin); Py_DECREF(rv); return NULL; } diff --git a/Objects/abstract.c b/Objects/abstract.c index ac61011..39cb803 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -260,6 +260,7 @@ PyObject_AsCharBuffer(PyObject *obj, *buffer_len = view.len; if (pb->bf_releasebuffer != NULL) (*pb->bf_releasebuffer)(obj, &view); + Py_XDECREF(view.obj); return 0; } @@ -305,6 +306,7 @@ int PyObject_AsReadBuffer(PyObject *obj, *buffer_len = view.len; if (pb->bf_releasebuffer != NULL) (*pb->bf_releasebuffer)(obj, &view); + Py_XDECREF(view.obj); return 0; } @@ -332,6 +334,7 @@ int PyObject_AsWriteBuffer(PyObject *obj, *buffer_len = view.len; if (pb->bf_releasebuffer != NULL) (*pb->bf_releasebuffer)(obj, &view); + Py_XDECREF(view.obj); return 0; } diff --git a/Python/getargs.c b/Python/getargs.c index b7beb37..13c3f4b 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1245,7 +1245,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, /* Caller is interested in Py_buffer, and the object supports it directly. */ format++; - if (pb->bf_getbuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { + if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { PyErr_Clear(); return converterr("read-write buffer", arg, msgbuf, bufsize); } @@ -1257,11 +1257,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, /* Here we have processed w*, only w and w# remain. */ if (pb == NULL || pb->bf_getbuffer == NULL || - ((temp = (*pb->bf_getbuffer)(arg, &view, - PyBUF_SIMPLE)) != 0) || + ((temp = PyObject_GetBuffer(arg, &view, + PyBUF_SIMPLE)) != 0) || view.readonly == 1) { - if (temp==0 && pb->bf_releasebuffer != NULL) { - (*pb->bf_releasebuffer)(arg, &view); + if (temp==0) { + PyBuffer_Release(&view); } return converterr("single-segment read-write buffer", arg, msgbuf, bufsize); @@ -1295,7 +1295,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, "bytes or read-only character buffer", arg, msgbuf, bufsize); - if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0) + if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) != 0) return converterr("string or single-segment read-only buffer", arg, msgbuf, bufsize); @@ -1306,6 +1306,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, "string or pinned buffer", arg, msgbuf, bufsize); + PyBuffer_Release(&view); + if (count < 0) return converterr("(unspecified)", arg, msgbuf, bufsize); { @@ -1340,14 +1342,13 @@ convertbuffer(PyObject *arg, void **p, char **errmsg) return -1; } - if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0) { + if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) != 0) { *errmsg = "bytes or single-segment read-only buffer"; return -1; } count = view.len; *p = view.buf; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(arg, &view); + PyBuffer_Release(&view); return count; } @@ -1364,7 +1365,7 @@ getbuffer(PyObject *arg, Py_buffer *view, char **errmsg) return -1; } if (pb->bf_getbuffer) { - if (pb->bf_getbuffer(arg, view, 0) < 0) { + if (PyObject_GetBuffer(arg, view, 0) < 0) { *errmsg = "convertible to a buffer"; return -1; } -- cgit v0.12