self.f.writelines('')
self._test_close_open_io(io_func)
+ def test_iteration_torture(self):
+ # bpo-31530: Crash when concurrently iterate over a file.
+ with open(self.filename, "wb") as fp:
+ for i in xrange(2**20):
+ fp.write(b"0"*50 + b"\n")
+ with open(self.filename, "rb") as f:
+ def iterate():
+ try:
+ for l in f:
+ pass
+ except IOError:
+ pass
+ self._run_workers(iterate, 10)
+
+ def test_iteration_seek(self):
+ # bpo-31530: Crash when concurrently seek and iterate over a file.
+ with open(self.filename, "wb") as fp:
+ for i in xrange(10000):
+ fp.write(b"0"*50 + b"\n")
+ with open(self.filename, "rb") as f:
+ it = iter([1] + [0]*10) # one thread reads, others seek
+ def iterate():
+ try:
+ if next(it):
+ for l in f:
+ pass
+ else:
+ for i in range(100):
+ f.seek(i*100, 0)
+ except IOError:
+ pass
+ self._run_workers(iterate, 10)
@unittest.skipUnless(os.name == 'posix', 'test requires a posix system.')
class TestFileSignalEINTR(unittest.TestCase):
if (Py_REFCNT(f) > 0) {
PyErr_SetString(PyExc_IOError,
"close() called during concurrent "
- "operation on the same file object.");
+ "operation on the same file object");
} else {
/* This should not happen unless someone is
* carelessly playing with the PyFileObject
* pointer. */
PyErr_SetString(PyExc_SystemError,
"PyFileObject locking error in "
- "destructor (refcnt <= 0 at close).");
+ "destructor (refcnt <= 0 at close)");
}
return NULL;
}
if (f->f_fp == NULL)
return err_closed();
+ if (f->unlocked_count > 0) {
+ PyErr_SetString(PyExc_IOError,
+ "seek() called during concurrent "
+ "operation on the same file object");
+ return NULL;
+ }
drop_readahead(f);
whence = 0;
if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &whence))
{
Py_ssize_t chunksize;
+ assert(f->unlocked_count == 0);
if (f->f_buf != NULL) {
if( (f->f_bufend - f->f_bufptr) >= 1)
return 0;
char *buf;
Py_ssize_t len;
+ if (f->unlocked_count > 0) {
+ PyErr_SetString(PyExc_IOError,
+ "next() called during concurrent "
+ "operation on the same file object");
+ return NULL;
+ }
if (f->f_buf == NULL)
if (readahead(f, bufsize) < 0)
return NULL;
}
else {
PyErr_SetString(PyExc_TypeError,
- "argument must be an int, or have a fileno() method.");
+ "argument must be an int, or have a fileno() method");
return -1;
}