summaryrefslogtreecommitdiffstats
path: root/Objects/fileobject.c
diff options
context:
space:
mode:
authorNir Soffer <nirsof@gmail.com>2017-12-07 20:25:39 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2017-12-07 20:25:39 (GMT)
commit830daae1c82ed33deef0086b7b6323e5be0b0cc8 (patch)
tree0c11e6b6281ec736bbae427c7100e7d8af65b63f /Objects/fileobject.c
parent12fa6b1e2ff8112b0a9f61949c3d5252a75bf909 (diff)
downloadcpython-830daae1c82ed33deef0086b7b6323e5be0b0cc8.zip
cpython-830daae1c82ed33deef0086b7b6323e5be0b0cc8.tar.gz
cpython-830daae1c82ed33deef0086b7b6323e5be0b0cc8.tar.bz2
[2.7] bpo-32186: Release the GIL during fstat and lseek calls (#4651)
In fileio, there were 3 fstat() calls and one lseek() call that did not release the GIL during the call. This can cause all threads to hang for unlimited time when using io.FileIO with inaccessible NFS server. Same issue seen in fileio exists also in fileobject, fixed in the same way.
Diffstat (limited to 'Objects/fileobject.c')
-rw-r--r--Objects/fileobject.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 2f63c37..8d1c581 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -121,10 +121,15 @@ dircheck(PyFileObject* f)
{
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
struct stat buf;
+ int res;
if (f->f_fp == NULL)
return f;
- if (fstat(fileno(f->f_fp), &buf) == 0 &&
- S_ISDIR(buf.st_mode)) {
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(fileno(f->f_fp), &buf);
+ Py_END_ALLOW_THREADS
+
+ if (res == 0 && S_ISDIR(buf.st_mode)) {
char *msg = strerror(EISDIR);
PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)",
EISDIR, msg, f->f_name);
@@ -1010,7 +1015,13 @@ new_buffersize(PyFileObject *f, size_t currentsize)
#ifdef HAVE_FSTAT
off_t pos, end;
struct stat st;
- if (fstat(fileno(f->f_fp), &st) == 0) {
+ int res;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(fileno(f->f_fp), &st);
+ Py_END_ALLOW_THREADS
+
+ if (res == 0) {
end = st.st_size;
/* The following is not a bug: we really need to call lseek()
*and* ftell(). The reason is that some stdio libraries
@@ -1021,7 +1032,11 @@ new_buffersize(PyFileObject *f, size_t currentsize)
works. We can't use the lseek() value either, because we
need to take the amount of buffered data into account.
(Yet another reason why stdio stinks. :-) */
+
+ Py_BEGIN_ALLOW_THREADS
pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR);
+ Py_END_ALLOW_THREADS
+
if (pos >= 0) {
pos = ftell(f->f_fp);
}