diff options
author | Antoine Pitrou <antoine@python.org> | 2020-02-23 22:33:53 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-23 22:33:53 (GMT) |
commit | 9f37872e307734666a7169f7be6e3370d3068282 (patch) | |
tree | 47f754a231cd7b028f70577207296847381543b0 /Modules | |
parent | b76518d43fb82ed9e5d27025d18c90a23d525c90 (diff) | |
download | cpython-9f37872e307734666a7169f7be6e3370d3068282.zip cpython-9f37872e307734666a7169f7be6e3370d3068282.tar.gz cpython-9f37872e307734666a7169f7be6e3370d3068282.tar.bz2 |
bpo-39681: Fix C pickle regression with minimal file-like objects (#18592)
Fix a regression where the C pickle module wouldn't allow unpickling from a
file-like object that doesn't expose a readinto() method.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_pickle.c | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 2ba7a16..a750351 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1373,13 +1373,42 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n) } /* Read from file */ - if (!self->readinto) { + if (!self->read) { + /* We're unpickling memory, this means the input is truncated */ return bad_readline(); } if (_Unpickler_SkipConsumed(self) < 0) { return -1; } + if (!self->readinto) { + /* readinto() not supported on file-like object, fall back to read() + * and copy into destination buffer (bpo-39681) */ + PyObject* len = PyLong_FromSsize_t(n); + if (len == NULL) { + return -1; + } + PyObject* data = _Pickle_FastCall(self->read, len); + if (data == NULL) { + return -1; + } + if (!PyBytes_Check(data)) { + PyErr_Format(PyExc_ValueError, + "read() returned non-bytes object (%R)", + Py_TYPE(data)); + Py_DECREF(data); + return -1; + } + Py_ssize_t read_size = PyBytes_GET_SIZE(data); + if (read_size < n) { + Py_DECREF(data); + return bad_readline(); + } + memcpy(buf, PyBytes_AS_STRING(data), n); + Py_DECREF(data); + return n; + } + /* Call readinto() into user buffer */ PyObject *buf_obj = PyMemoryView_FromMemory(buf, n, PyBUF_WRITE); if (buf_obj == NULL) { @@ -1608,17 +1637,19 @@ _Unpickler_SetInputStream(UnpicklerObject *self, PyObject *file) _Py_IDENTIFIER(readinto); _Py_IDENTIFIER(readline); + /* Optional file methods */ if (_PyObject_LookupAttrId(file, &PyId_peek, &self->peek) < 0) { return -1; } + if (_PyObject_LookupAttrId(file, &PyId_readinto, &self->readinto) < 0) { + return -1; + } (void)_PyObject_LookupAttrId(file, &PyId_read, &self->read); - (void)_PyObject_LookupAttrId(file, &PyId_readinto, &self->readinto); (void)_PyObject_LookupAttrId(file, &PyId_readline, &self->readline); - if (!self->readline || !self->readinto || !self->read) { + if (!self->readline || !self->read) { if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, - "file must have 'read', 'readinto' and " - "'readline' attributes"); + "file must have 'read' and 'readline' attributes"); } Py_CLEAR(self->read); Py_CLEAR(self->readinto); |