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.
diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex
index a104d85..6dee0c9 100644
--- a/Doc/lib/libstdtypes.tex
+++ b/Doc/lib/libstdtypes.tex
@@ -1205,7 +1205,9 @@
   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 772ae95..3c7bf75 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -335,6 +335,9 @@
   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
 -----------------
 
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 86620ff..612cefd 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -741,6 +741,20 @@
 	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 @@
 		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(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"