From: Gustavo Niemeyer Date: Tue, 4 Mar 2003 00:50:24 +0000 (+0000) Subject: Backported fix to [521782] unreliable file.read() error handling. X-Git-Tag: v2.2.3c1~117 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fac559c5334afc8e44cf45555082be1f165a02e6;p=thirdparty%2FPython%2Fcpython.git Backported fix to [521782] unreliable file.read() error handling. --- diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex index fcc3361593b4..eff8ff40b8cc 100644 --- a/Doc/lib/libstdtypes.tex +++ b/Doc/lib/libstdtypes.tex @@ -1163,7 +1163,9 @@ Files have the following methods: certain files, like ttys, it makes sense to continue reading after an \EOF{} is hit.) Note that this method may call the underlying C function \cfunction{fread()} more than once in an effort to - acquire as close to \var{size} bytes as possible. + acquire as close to \var{size} bytes as possible. Also note that + when in non-blocking mode, less data than what was requested may + be returned, even if no \var{size} parameter was given. \end{methoddesc} \begin{methoddesc}[file]{readline}{\optional{size}} diff --git a/Misc/NEWS b/Misc/NEWS index e81e87a2f716..aaecd01d9e1e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -295,6 +295,9 @@ Core and builtins supply a __doc__ descriptor that returns something different for a class than for instances of that class. +- Fixed bug #521782: when a file was in non-blocking mode, file.read() + could silently lose data or wrongly throw an unknown error. + Extension modules - In readline.c: change completion to avoid appending a space diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 58af9ce8b28f..b38dbb5c4d4d 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -568,6 +568,20 @@ new_buffersize(PyFileObject *f, size_t currentsize) return currentsize + SMALLCHUNK; } +#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN +#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK || (x) == EAGAIN) +#else +#ifdef EWOULDBLOCK +#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK) +#else +#ifdef EAGAIN +#define BLOCKED_ERRNO(x) ((x) == EAGAIN) +#else +#define BLOCKED_ERRNO(x) 0 +#endif +#endif +#endif + static PyObject * file_read(PyFileObject *f, PyObject *args) { @@ -601,18 +615,29 @@ file_read(PyFileObject *f, PyObject *args) if (chunksize == 0) { if (!ferror(f->f_fp)) break; - PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); + /* When in non-blocking mode, data shouldn't + * be discarded if a blocking signal was + * received. That will also happen if + * chunksize != 0, but bytesread < buffersize. */ + if (bytesread > 0 && BLOCKED_ERRNO(errno)) + break; + PyErr_SetFromErrno(PyExc_IOError); Py_DECREF(v); return NULL; } bytesread += chunksize; - if (bytesread < buffersize) + if (bytesread < buffersize) { + clearerr(f->f_fp); break; + } if (bytesrequested < 0) { buffersize = new_buffersize(f, buffersize); if (_PyString_Resize(&v, buffersize) < 0) return NULL; + } else { + /* Got what was requested. */ + break; } } if (bytesread != buffersize) @@ -1321,7 +1346,9 @@ static char readline_doc[] = static char read_doc[] = "read([size]) -> read at most size bytes, returned as a string.\n" "\n" -"If the size argument is negative or omitted, read until EOF is reached."; +"If the size argument is negative or omitted, read until EOF is reached.\n" +"Notice that when in non-blocking mode, less data than what was requested\n" +"may be returned, even if no size parameter was given."; static char write_doc[] = "write(str) -> None. Write string str to file.\n"