On 8/22/07, Hrvoje Nikšić <[EMAIL PROTECTED]> wrote: > On Tue, 2007-08-21 at 09:14 -0700, Neal Norwitz wrote: > > The patch is insufficient to prevent all types of crashes that occur > > when accessing a file from 2 threads (closing in one and doing > > whatever in another). > > You are right. I wouldn't go so far to say the file object > thread-unsafe, but it certainly has lurking bugs with calling close > while other threads are running. BTW your mail doesn't seem to contain > the actual patch.
Sorry about that. I thought something was up when gmail didn't automatically upload it while I was writing the message. It looks like it took this time. (The attached patch isn't complete, but catches most cases.) n
Index: Objects/fileobject.c =================================================================== --- Objects/fileobject.c (revision 57244) +++ Objects/fileobject.c (working copy) @@ -439,13 +439,16 @@ { int sts = 0; if (f->f_fp != NULL) { + /* Invalidate f->f_fp *before* closing, so we don't attempt + to close it twice in separate threads. */ + FILE *tmp_fp = f->f_fp; + f->f_fp = NULL; if (f->f_close != NULL) { Py_BEGIN_ALLOW_THREADS errno = 0; - sts = (*f->f_close)(f->f_fp); + sts = (*f->f_close)(tmp_fp); Py_END_ALLOW_THREADS } - f->f_fp = NULL; } PyMem_Free(f->f_setbuf); f->f_setbuf = NULL; @@ -539,7 +542,7 @@ file_seek(PyFileObject *f, PyObject *args) { int whence; - int ret; + int ret = 0; Py_off_t offset; PyObject *offobj; @@ -560,8 +563,11 @@ Py_BEGIN_ALLOW_THREADS errno = 0; - ret = _portable_fseek(f->f_fp, offset, whence); + if (f->f_fp != NULL) + ret = _portable_fseek(f->f_fp, offset, whence); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (ret != 0) { PyErr_SetFromErrno(PyExc_IOError); @@ -580,8 +586,8 @@ { Py_off_t newsize; PyObject *newsizeobj = NULL; - Py_off_t initialpos; - int ret; + Py_off_t initialpos = 0; + int ret = 0; if (f->f_fp == NULL) return err_closed(); @@ -597,8 +603,11 @@ */ Py_BEGIN_ALLOW_THREADS errno = 0; - initialpos = _portable_ftell(f->f_fp); + if (f->f_fp != NULL) + initialpos = _portable_ftell(f->f_fp); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (initialpos == -1) goto onioerror; @@ -625,8 +634,11 @@ */ Py_BEGIN_ALLOW_THREADS errno = 0; - ret = fflush(f->f_fp); + if (f->f_fp != NULL) + ret = fflush(f->f_fp); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (ret != 0) goto onioerror; @@ -639,30 +651,40 @@ /* Have to move current pos to desired endpoint on Windows. */ Py_BEGIN_ALLOW_THREADS errno = 0; - ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; + if (f->f_fp != NULL) + ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (ret) goto onioerror; /* Truncate. Note that this may grow the file! */ Py_BEGIN_ALLOW_THREADS errno = 0; - hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); - ret = hFile == (HANDLE)-1; - if (ret == 0) { - ret = SetEndOfFile(hFile) == 0; - if (ret) - errno = EACCES; + if (f->f_fp != NULL) { + hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); + ret = hFile == (HANDLE)-1; + if (ret == 0) { + ret = SetEndOfFile(hFile) == 0; + if (ret) + errno = EACCES; + } } Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (ret) goto onioerror; } #else Py_BEGIN_ALLOW_THREADS errno = 0; - ret = ftruncate(fileno(f->f_fp), newsize); + if (f->f_fp != NULL) + ret = ftruncate(fileno(f->f_fp), newsize); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (ret != 0) goto onioerror; #endif /* !MS_WINDOWS */ @@ -670,8 +692,11 @@ /* Restore original file position. */ Py_BEGIN_ALLOW_THREADS errno = 0; - ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0; + if (f->f_fp != NULL) + ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0; Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (ret) goto onioerror; @@ -688,14 +713,17 @@ static PyObject * file_tell(PyFileObject *f) { - Py_off_t pos; + Py_off_t pos = 0; if (f->f_fp == NULL) return err_closed(); Py_BEGIN_ALLOW_THREADS errno = 0; - pos = _portable_ftell(f->f_fp); + if (f->f_fp != NULL) + pos = _portable_ftell(f->f_fp); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (pos == -1) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); @@ -727,14 +755,17 @@ static PyObject * file_flush(PyFileObject *f) { - int res; + int res = 0; if (f->f_fp == NULL) return err_closed(); Py_BEGIN_ALLOW_THREADS errno = 0; - res = fflush(f->f_fp); + if (f->f_fp != NULL) + res = fflush(f->f_fp); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (res != 0) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); @@ -747,12 +778,15 @@ static PyObject * file_isatty(PyFileObject *f) { - long res; + long res = 0; if (f->f_fp == NULL) return err_closed(); Py_BEGIN_ALLOW_THREADS - res = isatty((int)fileno(f->f_fp)); + if (f->f_fp != NULL) + res = isatty((int)fileno(f->f_fp)); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); return PyBool_FromLong(res); } @@ -826,7 +860,7 @@ file_read(PyFileObject *f, PyObject *args) { long bytesrequested = -1; - size_t bytesread, buffersize, chunksize; + size_t bytesread, buffersize, chunksize = 0; PyObject *v; if (f->f_fp == NULL) @@ -854,9 +888,14 @@ for (;;) { Py_BEGIN_ALLOW_THREADS errno = 0; - chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread, - buffersize - bytesread, f->f_fp, (PyObject *)f); + if (f->f_fp != NULL) + chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread, + buffersize - bytesread, f->f_fp, (PyObject *)f); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) { + Py_DECREF(v); + return err_closed(); + } if (chunksize == 0) { if (!ferror(f->f_fp)) break; @@ -895,7 +934,7 @@ { char *ptr; Py_ssize_t ntodo; - Py_ssize_t ndone, nnow; + Py_ssize_t ndone, nnow = 0; if (f->f_fp == NULL) return err_closed(); @@ -910,9 +949,13 @@ while (ntodo > 0) { Py_BEGIN_ALLOW_THREADS errno = 0; - nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp, + if (f->f_fp != NULL) + nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, + f->f_fp, (PyObject *)f); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (nnow == 0) { if (!ferror(f->f_fp)) break; @@ -1379,7 +1422,7 @@ size_t buffersize = SMALLCHUNK; PyObject *big_buffer = NULL; size_t nfilled = 0; - size_t nread; + size_t nread = 0; size_t totalread = 0; char *p, *q, *end; int err; @@ -1402,9 +1445,13 @@ else { Py_BEGIN_ALLOW_THREADS errno = 0; - nread = Py_UniversalNewlineFread(buffer+nfilled, - buffersize-nfilled, f->f_fp, (PyObject *)f); + if (f->f_fp != NULL) + nread = Py_UniversalNewlineFread(buffer+nfilled, + buffersize-nfilled, + f->f_fp, (PyObject *)f); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); shortread = (nread < buffersize-nfilled); } if (nread == 0) { @@ -1499,7 +1546,7 @@ file_write(PyFileObject *f, PyObject *args) { char *s; - Py_ssize_t n, n2; + Py_ssize_t n, n2 = 0; if (f->f_fp == NULL) return err_closed(); if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n)) @@ -1507,8 +1554,11 @@ f->f_softspace = 0; Py_BEGIN_ALLOW_THREADS errno = 0; - n2 = fwrite(s, 1, n, f->f_fp); + if (f->f_fp != NULL) + n2 = fwrite(s, 1, n, f->f_fp); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) + return err_closed(); if (n2 != n) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); @@ -1842,7 +1892,7 @@ static int readahead(PyFileObject *f, int bufsize) { - Py_ssize_t chunksize; + Py_ssize_t chunksize = 0; if (f->f_buf != NULL) { if( (f->f_bufend - f->f_bufptr) >= 1) @@ -1856,9 +1906,15 @@ } Py_BEGIN_ALLOW_THREADS errno = 0; - chunksize = Py_UniversalNewlineFread( - f->f_buf, bufsize, f->f_fp, (PyObject *)f); + if (f->f_fp != NULL) + chunksize = Py_UniversalNewlineFread( + f->f_buf, bufsize, f->f_fp, (PyObject *)f); Py_END_ALLOW_THREADS + if (f->f_fp == NULL) { + err_closed(); + drop_readahead(f); + return -1; + } if (chunksize == 0) { if (ferror(f->f_fp)) { PyErr_SetFromErrno(PyExc_IOError);
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com