Kaydet (Commit) 9edd2bd3 authored tarafından Benjamin Peterson's avatar Benjamin Peterson

Fix #3651 various memory leaks when using the buffer interface

by Amaury Forgeot d'Arc
Reviewer: Antoine Pitrou
üst 4b24a42f
...@@ -143,7 +143,7 @@ typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); ...@@ -143,7 +143,7 @@ typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
/* buffer interface */ /* buffer interface */
typedef struct bufferinfo { typedef struct bufferinfo {
void *buf; void *buf;
PyObject *obj; /* borrowed reference */ PyObject *obj; /* owned reference */
Py_ssize_t len; Py_ssize_t len;
Py_ssize_t itemsize; /* This is Py_ssize_t so it can be Py_ssize_t itemsize; /* This is Py_ssize_t so it can be
pointed to by strides in simple case.*/ pointed to by strides in simple case.*/
......
...@@ -21,6 +21,10 @@ Core and Builtins ...@@ -21,6 +21,10 @@ Core and Builtins
- Issue #3663: Py_None was decref'd when printing SyntaxErrors. - 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. - Issue #3657: Fix uninitialized memory read when pickling longs.
Found by valgrind. Found by valgrind.
......
...@@ -231,6 +231,7 @@ binascii_a2b_uu(PyObject *self, PyObject *args) ...@@ -231,6 +231,7 @@ binascii_a2b_uu(PyObject *self, PyObject *args)
*/ */
if ( this_ch < ' ' || this_ch > (' ' + 64)) { if ( this_ch < ' ' || this_ch > (' ' + 64)) {
PyErr_SetString(Error, "Illegal char"); PyErr_SetString(Error, "Illegal char");
PyBuffer_Release(&pascii);
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
...@@ -259,6 +260,7 @@ binascii_a2b_uu(PyObject *self, PyObject *args) ...@@ -259,6 +260,7 @@ binascii_a2b_uu(PyObject *self, PyObject *args)
if ( this_ch != ' ' && this_ch != ' '+64 && if ( this_ch != ' ' && this_ch != ' '+64 &&
this_ch != '\n' && this_ch != '\r' ) { this_ch != '\n' && this_ch != '\r' ) {
PyErr_SetString(Error, "Trailing garbage"); PyErr_SetString(Error, "Trailing garbage");
PyBuffer_Release(&pascii);
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
...@@ -805,6 +807,7 @@ binascii_rledecode_hqx(PyObject *self, PyObject *args) ...@@ -805,6 +807,7 @@ binascii_rledecode_hqx(PyObject *self, PyObject *args)
** of the string only). This is a programmer error. ** of the string only). This is a programmer error.
*/ */
PyErr_SetString(Error, "Orphaned RLE code at start"); PyErr_SetString(Error, "Orphaned RLE code at start");
PyBuffer_Release(&pin);
Py_DECREF(rv); Py_DECREF(rv);
return NULL; return NULL;
} }
......
...@@ -260,6 +260,7 @@ PyObject_AsCharBuffer(PyObject *obj, ...@@ -260,6 +260,7 @@ PyObject_AsCharBuffer(PyObject *obj,
*buffer_len = view.len; *buffer_len = view.len;
if (pb->bf_releasebuffer != NULL) if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(obj, &view); (*pb->bf_releasebuffer)(obj, &view);
Py_XDECREF(view.obj);
return 0; return 0;
} }
...@@ -305,6 +306,7 @@ int PyObject_AsReadBuffer(PyObject *obj, ...@@ -305,6 +306,7 @@ int PyObject_AsReadBuffer(PyObject *obj,
*buffer_len = view.len; *buffer_len = view.len;
if (pb->bf_releasebuffer != NULL) if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(obj, &view); (*pb->bf_releasebuffer)(obj, &view);
Py_XDECREF(view.obj);
return 0; return 0;
} }
...@@ -332,6 +334,7 @@ int PyObject_AsWriteBuffer(PyObject *obj, ...@@ -332,6 +334,7 @@ int PyObject_AsWriteBuffer(PyObject *obj,
*buffer_len = view.len; *buffer_len = view.len;
if (pb->bf_releasebuffer != NULL) if (pb->bf_releasebuffer != NULL)
(*pb->bf_releasebuffer)(obj, &view); (*pb->bf_releasebuffer)(obj, &view);
Py_XDECREF(view.obj);
return 0; return 0;
} }
......
...@@ -1245,7 +1245,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, ...@@ -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 /* Caller is interested in Py_buffer, and the object
supports it directly. */ supports it directly. */
format++; format++;
if (pb->bf_getbuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
PyErr_Clear(); PyErr_Clear();
return converterr("read-write buffer", arg, msgbuf, bufsize); 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, ...@@ -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. */ /* Here we have processed w*, only w and w# remain. */
if (pb == NULL || if (pb == NULL ||
pb->bf_getbuffer == NULL || pb->bf_getbuffer == NULL ||
((temp = (*pb->bf_getbuffer)(arg, &view, ((temp = PyObject_GetBuffer(arg, &view,
PyBUF_SIMPLE)) != 0) || PyBUF_SIMPLE)) != 0) ||
view.readonly == 1) { view.readonly == 1) {
if (temp==0 && pb->bf_releasebuffer != NULL) { if (temp==0) {
(*pb->bf_releasebuffer)(arg, &view); PyBuffer_Release(&view);
} }
return converterr("single-segment read-write buffer", return converterr("single-segment read-write buffer",
arg, msgbuf, bufsize); arg, msgbuf, bufsize);
...@@ -1295,7 +1295,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, ...@@ -1295,7 +1295,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
"bytes or read-only character buffer", "bytes or read-only character buffer",
arg, msgbuf, bufsize); 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", return converterr("string or single-segment read-only buffer",
arg, msgbuf, bufsize); arg, msgbuf, bufsize);
...@@ -1306,6 +1306,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, ...@@ -1306,6 +1306,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
"string or pinned buffer", "string or pinned buffer",
arg, msgbuf, bufsize); arg, msgbuf, bufsize);
PyBuffer_Release(&view);
if (count < 0) if (count < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize); return converterr("(unspecified)", arg, msgbuf, bufsize);
{ {
...@@ -1340,14 +1342,13 @@ convertbuffer(PyObject *arg, void **p, char **errmsg) ...@@ -1340,14 +1342,13 @@ convertbuffer(PyObject *arg, void **p, char **errmsg)
return -1; 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"; *errmsg = "bytes or single-segment read-only buffer";
return -1; return -1;
} }
count = view.len; count = view.len;
*p = view.buf; *p = view.buf;
if (pb->bf_releasebuffer != NULL) PyBuffer_Release(&view);
(*pb->bf_releasebuffer)(arg, &view);
return count; return count;
} }
...@@ -1364,7 +1365,7 @@ getbuffer(PyObject *arg, Py_buffer *view, char **errmsg) ...@@ -1364,7 +1365,7 @@ getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
return -1; return -1;
} }
if (pb->bf_getbuffer) { if (pb->bf_getbuffer) {
if (pb->bf_getbuffer(arg, view, 0) < 0) { if (PyObject_GetBuffer(arg, view, 0) < 0) {
*errmsg = "convertible to a buffer"; *errmsg = "convertible to a buffer";
return -1; return -1;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment