@@ -1373,13 +1373,42 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n)
13731373 }
13741374
13751375 /* Read from file */
1376- if (!self -> readinto ) {
1376+ if (!self -> read ) {
1377+ /* We're unpickling memory, this means the input is truncated */
13771378 return bad_readline ();
13781379 }
13791380 if (_Unpickler_SkipConsumed (self ) < 0 ) {
13801381 return -1 ;
13811382 }
13821383
1384+ if (!self -> readinto ) {
1385+ /* readinto() not supported on file-like object, fall back to read()
1386+ * and copy into destination buffer (bpo-39681) */
1387+ PyObject * len = PyLong_FromSsize_t (n );
1388+ if (len == NULL ) {
1389+ return -1 ;
1390+ }
1391+ PyObject * data = _Pickle_FastCall (self -> read , len );
1392+ if (data == NULL ) {
1393+ return -1 ;
1394+ }
1395+ if (!PyBytes_Check (data )) {
1396+ PyErr_Format (PyExc_ValueError ,
1397+ "read() returned non-bytes object (%R)" ,
1398+ Py_TYPE (data ));
1399+ Py_DECREF (data );
1400+ return -1 ;
1401+ }
1402+ Py_ssize_t read_size = PyBytes_GET_SIZE (data );
1403+ if (read_size < n ) {
1404+ Py_DECREF (data );
1405+ return bad_readline ();
1406+ }
1407+ memcpy (buf , PyBytes_AS_STRING (data ), n );
1408+ Py_DECREF (data );
1409+ return n ;
1410+ }
1411+
13831412 /* Call readinto() into user buffer */
13841413 PyObject * buf_obj = PyMemoryView_FromMemory (buf , n , PyBUF_WRITE );
13851414 if (buf_obj == NULL ) {
@@ -1608,17 +1637,19 @@ _Unpickler_SetInputStream(UnpicklerObject *self, PyObject *file)
16081637 _Py_IDENTIFIER (readinto );
16091638 _Py_IDENTIFIER (readline );
16101639
1640+ /* Optional file methods */
16111641 if (_PyObject_LookupAttrId (file , & PyId_peek , & self -> peek ) < 0 ) {
16121642 return -1 ;
16131643 }
1644+ if (_PyObject_LookupAttrId (file , & PyId_readinto , & self -> readinto ) < 0 ) {
1645+ return -1 ;
1646+ }
16141647 (void )_PyObject_LookupAttrId (file , & PyId_read , & self -> read );
1615- (void )_PyObject_LookupAttrId (file , & PyId_readinto , & self -> readinto );
16161648 (void )_PyObject_LookupAttrId (file , & PyId_readline , & self -> readline );
1617- if (!self -> readline || !self -> readinto || ! self -> read ) {
1649+ if (!self -> readline || !self -> read ) {
16181650 if (!PyErr_Occurred ()) {
16191651 PyErr_SetString (PyExc_TypeError ,
1620- "file must have 'read', 'readinto' and "
1621- "'readline' attributes" );
1652+ "file must have 'read' and 'readline' attributes" );
16221653 }
16231654 Py_CLEAR (self -> read );
16241655 Py_CLEAR (self -> readinto );
0 commit comments