Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 786ddb2

Browse files
committed
Fixed bug
[#521782] unreliable file.read() error handling * Objects/fileobject.c (file_read): Clear errors before leaving the loop in all situations, and also check if some data was read before exiting the loop with an EWOULDBLOCK exception. * Doc/lib/libstdtypes.tex * Objects/fileobject.c Document that sometimes a read() operation can return less data than what the user asked, if running in non-blocking mode. * Misc/NEWS Document the fix.
1 parent 17c5a33 commit 786ddb2

3 files changed

Lines changed: 36 additions & 4 deletions

File tree

Doc/lib/libstdtypes.tex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,7 +1205,9 @@ \subsection{File Objects
12051205
certain files, like ttys, it makes sense to continue reading after
12061206
an \EOF{} is hit.) Note that this method may call the underlying
12071207
C function \cfunction{fread()} more than once in an effort to
1208-
acquire as close to \var{size} bytes as possible.
1208+
acquire as close to \var{size} bytes as possible. Also note that
1209+
when in non-blocking mode, less data than what was requested may
1210+
be returned, even if no \var{size} parameter was given.
12091211
\end{methoddesc}
12101212

12111213
\begin{methoddesc}[file]{readline}{\optional{size}}

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ Core and builtins
335335
general left to right evaluation order rule. Now {f1(): f2()} will
336336
evaluate f1 first.
337337

338+
- Fixed bug #521782: when a file was in non-blocking mode, file.read()
339+
could silently lose data or wrongly throw an unknown error.
340+
338341
Extension modules
339342
-----------------
340343

Objects/fileobject.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,20 @@ new_buffersize(PyFileObject *f, size_t currentsize)
741741
return currentsize + SMALLCHUNK;
742742
}
743743

744+
#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
745+
#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK || (x) == EAGAIN)
746+
#else
747+
#ifdef EWOULDBLOCK
748+
#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK)
749+
#else
750+
#ifdef EAGAIN
751+
#define BLOCKED_ERRNO(x) ((x) == EAGAIN)
752+
#else
753+
#define BLOCKED_ERRNO(x) 0
754+
#endif
755+
#endif
756+
#endif
757+
744758
static PyObject *
745759
file_read(PyFileObject *f, PyObject *args)
746760
{
@@ -774,18 +788,29 @@ file_read(PyFileObject *f, PyObject *args)
774788
if (chunksize == 0) {
775789
if (!ferror(f->f_fp))
776790
break;
777-
PyErr_SetFromErrno(PyExc_IOError);
778791
clearerr(f->f_fp);
792+
/* When in non-blocking mode, data shouldn't
793+
* be discarded if a blocking signal was
794+
* received. That will also happen if
795+
* chunksize != 0, but bytesread < buffersize. */
796+
if (bytesread > 0 && BLOCKED_ERRNO(errno))
797+
break;
798+
PyErr_SetFromErrno(PyExc_IOError);
779799
Py_DECREF(v);
780800
return NULL;
781801
}
782802
bytesread += chunksize;
783-
if (bytesread < buffersize)
803+
if (bytesread < buffersize) {
804+
clearerr(f->f_fp);
784805
break;
806+
}
785807
if (bytesrequested < 0) {
786808
buffersize = new_buffersize(f, buffersize);
787809
if (_PyString_Resize(&v, buffersize) < 0)
788810
return NULL;
811+
} else {
812+
assert(bytesread == bytesrequested);
813+
break;
789814
}
790815
}
791816
if (bytesread != buffersize)
@@ -1518,7 +1543,9 @@ PyDoc_STRVAR(readline_doc,
15181543
PyDoc_STRVAR(read_doc,
15191544
"read([size]) -> read at most size bytes, returned as a string.\n"
15201545
"\n"
1521-
"If the size argument is negative or omitted, read until EOF is reached.");
1546+
"If the size argument is negative or omitted, read until EOF is reached.\n"
1547+
"Notice that when in non-blocking mode, less data than what was requested\n"
1548+
"may be returned, even if no size parameter was given.");
15221549

15231550
PyDoc_STRVAR(write_doc,
15241551
"write(str) -> None. Write string str to file.\n"

0 commit comments

Comments
 (0)