]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Fixed bug
authorGustavo Niemeyer <gustavo@niemeyer.net>
Mon, 16 Dec 2002 18:12:53 +0000 (18:12 +0000)
committerGustavo Niemeyer <gustavo@niemeyer.net>
Mon, 16 Dec 2002 18:12:53 +0000 (18:12 +0000)
[#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.

Doc/lib/libstdtypes.tex
Misc/NEWS
Objects/fileobject.c

index a104d85847f0f5c516bb69ef2880afb6d3176c67..6dee0c94d8be2df8d249c81fb4b9d5f5435f0ef2 100644 (file)
@@ -1205,7 +1205,9 @@ flush the read-ahead buffer.
   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 772ae95bdca87fcd545ed9854128bca5dd6f1a09..3c7bf755650df8249e67cfb6567dc1b3a9bf5891 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -335,6 +335,9 @@ Core and builtins
   general left to right evaluation order rule. Now {f1(): f2()} will
   evaluate f1 first.
 
+- 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
 -----------------
 
index 86620ff867ed6e2ec970aea49b63a46a5204e4fe..612cefd8c3e19e613c9485af428f8d881d4224f6 100644 (file)
@@ -741,6 +741,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)
 {
@@ -774,18 +788,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 {
+                       assert(bytesread == bytesrequested);
+                       break;
                }
        }
        if (bytesread != buffersize)
@@ -1518,7 +1543,9 @@ PyDoc_STRVAR(readline_doc,
 PyDoc_STRVAR(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.");
 
 PyDoc_STRVAR(write_doc,
 "write(str) -> None.  Write string str to file.\n"