diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 0eb2a367603cfc..0eac7bc06adf71 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -656,5 +656,30 @@ def __bool__(self): m[0] = MyBool() self.assertEqual(ba[:8], b'\0'*8) + + def test_gh60198(self): + global view + + class File(io.RawIOBase): + def readinto(self, buf): + global view + view = buf + + def readable(self): + return True + + f = io.BufferedReader(File()) + # get view of buffer used by BufferedReader + f.read(1) + # deallocate buffer + del f + + with self.assertRaises(ValueError): + view = view.cast('P') + L = [None] * len(view) + # overwrite first item with NULL + view[0] = 0 + print(L[0]) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-23-07-43-57.gh-issue-60198.fysv2O.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-23-07-43-57.gh-issue-60198.fysv2O.rst new file mode 100644 index 00000000000000..bfb5fdcd241cd3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-23-07-43-57.gh-issue-60198.fysv2O.rst @@ -0,0 +1 @@ +Prevent :class:`memoryview` objects from pointing to free heap memory. Patch by Martin Panter and Furkan Onder. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index bfc3d2558c9e36..d32941ee2f0e2d 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1545,7 +1545,8 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len) Py_buffer buf; PyObject *memobj, *res; Py_ssize_t n; - /* NOTE: the buffer needn't be released as its object is NULL. */ + PyObject *release_res; + /* The buffer will be released when raw.readinto() returns. */ if (PyBuffer_FillInfo(&buf, NULL, start, len, 0, PyBUF_CONTIG) == -1) return -1; memobj = PyMemoryView_FromBuffer(&buf); @@ -1559,7 +1560,15 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len) do { res = PyObject_CallMethodOneArg(self->raw, &_Py_ID(readinto), memobj); } while (res == NULL && _PyIO_trap_eintr()); + PyObject *exc = PyErr_GetRaisedException(); + release_res = PyObject_CallMethod(memobj, "release", NULL); + _PyErr_ChainExceptions1(exc); Py_DECREF(memobj); + if (release_res == NULL) { + Py_XDECREF(res); + return -1; + } + Py_DECREF(release_res); if (res == NULL) return -1; if (res == Py_None) { @@ -1904,7 +1913,8 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len) PyObject *memobj, *res; Py_ssize_t n; int errnum; - /* NOTE: the buffer needn't be released as its object is NULL. */ + PyObject *release_res; + /* The buffer will be released when raw.write() returns. */ if (PyBuffer_FillInfo(&buf, NULL, start, len, 1, PyBUF_CONTIG_RO) == -1) return -1; memobj = PyMemoryView_FromBuffer(&buf); @@ -1920,6 +1930,14 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len) res = PyObject_CallMethodOneArg(self->raw, &_Py_ID(write), memobj); errnum = errno; } while (res == NULL && _PyIO_trap_eintr()); + PyObject *exc = PyErr_GetRaisedException(); + release_res = PyObject_CallMethod(memobj, "release", NULL); + _PyErr_ChainExceptions1(exc); + if (release_res == NULL) { + Py_XDECREF(res); + return -1; + } + Py_DECREF(release_res); Py_DECREF(memobj); if (res == NULL) return -1; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index fe2660c6ce6058..237ecfffe7680b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3190,6 +3190,7 @@ PyUnicode_Decode(const char *s, PyObject *buffer = NULL, *unicode; Py_buffer info; char buflower[11]; /* strlen("iso-8859-1\0") == 11, longest shortcut */ + PyObject *res; if (unicode_check_encoding_errors(encoding, errors) < 0) { return NULL; @@ -3252,6 +3253,14 @@ PyUnicode_Decode(const char *s, if (buffer == NULL) goto onError; unicode = _PyCodec_DecodeText(buffer, encoding, errors); + PyObject *exc = PyErr_GetRaisedException(); + res = PyObject_CallMethod(buffer, "release", NULL); + _PyErr_ChainExceptions1(exc); + if (res == NULL) { + Py_XDECREF(unicode); + goto onError; + } + Py_DECREF(res); if (unicode == NULL) goto onError; if (!PyUnicode_Check(unicode)) {