summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorAntoine Pitrou <antoine@python.org>2020-02-23 22:33:53 (GMT)
committerGitHub <noreply@github.com>2020-02-23 22:33:53 (GMT)
commit9f37872e307734666a7169f7be6e3370d3068282 (patch)
tree47f754a231cd7b028f70577207296847381543b0 /Modules
parentb76518d43fb82ed9e5d27025d18c90a23d525c90 (diff)
downloadcpython-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.c41
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);