New submission from David Beazley:

First comment: In the I/O library, there is documented behavior for how things 
work in the presence of non-blocking I/O.  For example, read/write methods 
returning None on raw file objects.  Methods on BufferedIO instances raise a 
BlockingIOError for operations that can't complete. 

However, the implementation of close() is currently broken.  If buffered I/O is 
being used and a file is closed, it's possible that the close will fail due to 
a BlockingIOError occurring as buffered data is flushed to output.  However, in 
this case, the file is closed anyways and there is no possibility to retry.  
Here is an example to illustrate:

>>> from socket import *
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s.connect(('somehost', port))
>>> s.setblocking(False)
>>> f = s.makefile('wb', buffering=10000000)   # Large buffer
>>> f.write(b'x'*1000000)
>>>

Now, watch carefully

>>> f
<_io.BufferedWriter name=4>
>>> f.closed
False
>>> f.close()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
BlockingIOError: [Errno 35] write could not complete without blocking
>>> f
<_io.BufferedWriter name=-1>
>>> f.closed
True
>>>

I believe this can be fixed by changing a single line in 
Modules/_io/bufferedio.c:

--- bufferedio_orig.c   2015-10-25 16:40:22.000000000 -0500
+++ bufferedio.c        2015-10-25 16:40:35.000000000 -0500
@@ -530,10 +530,10 @@
     res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
     if (!ENTER_BUFFERED(self))
         return NULL;
-    if (res == NULL)
-        PyErr_Fetch(&exc, &val, &tb);
-    else
-        Py_DECREF(res);
+    if (res == NULL) 
+      goto end;
+    else 
+      Py_DECREF(res);
 
     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL);

With this patch, the close() method can be retried as appropriate until all 
buffered data is successfully written.

----------
components: IO
messages: 253438
nosy: dabeaz
priority: normal
severity: normal
status: open
title: close() behavior on non-blocking BufferedIO objects with sockets
type: behavior
versions: Python 3.5

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue25476>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to