]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Backported fix to [521782] unreliable file.read() error handling.
authorGustavo Niemeyer <gustavo@niemeyer.net>
Tue, 4 Mar 2003 00:50:24 +0000 (00:50 +0000)
committerGustavo Niemeyer <gustavo@niemeyer.net>
Tue, 4 Mar 2003 00:50:24 +0000 (00:50 +0000)
Doc/lib/libstdtypes.tex
Misc/NEWS
Objects/fileobject.c

index fcc3361593b4e613f975ea94cb260b2517adcfb4..eff8ff40b8ccf621e4a53f7219419b8175e62b11 100644 (file)
@@ -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}}
index e81e87a2f716daaa5d5df5306df7c0e28fd8c1ab..aaecd01d9e1e7f1e97bdc39f8ec2c11b1eed66f6 100644 (file)
--- 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
index 58af9ce8b28fe1cbe2e5fc5cc7afb883bc217b0f..b38dbb5c4d4d8e7a50580f19dfc2c87471af6cb1 100644 (file)
@@ -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"