diff options
Diffstat (limited to 'Modules/_io')
| -rw-r--r-- | Modules/_io/_iomodule.c | 35 | ||||
| -rw-r--r-- | Modules/_io/_iomodule.h | 4 | ||||
| -rw-r--r-- | Modules/_io/bufferedio.c | 85 | ||||
| -rw-r--r-- | Modules/_io/fileio.c | 203 | ||||
| -rw-r--r-- | Modules/_io/iobase.c | 125 | ||||
| -rw-r--r-- | Modules/_io/textio.c | 105 |
6 files changed, 352 insertions, 205 deletions
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 4a7e758..9866fbe 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -126,8 +126,7 @@ PyDoc_STRVAR(open_doc, "'b' binary mode\n" "'t' text mode (default)\n" "'+' open a disk file for updating (reading and writing)\n" -"'U' universal newline mode (for backwards compatibility; unneeded\n" -" for new code)\n" +"'U' universal newline mode (deprecated)\n" "========= ===============================================================\n" "\n" "The default mode is 'rt' (open for reading text). For binary random\n" @@ -143,6 +142,10 @@ PyDoc_STRVAR(open_doc, "returned as strings, the bytes having been first decoded using a\n" "platform-dependent encoding or using the specified encoding if given.\n" "\n" +"'U' mode is deprecated and will raise an exception in future versions\n" +"of Python. It has no effect in Python 3. Use newline to control\n" +"universal newlines mode.\n" +"\n" "buffering is an optional integer used to set the buffering policy.\n" "Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n" "line buffering (only usable in text mode), and an integer > 1 to indicate\n" @@ -310,6 +313,9 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) "can't use U and writing mode at once"); return NULL; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "'U' mode is deprecated", 1) < 0) + return NULL; reading = 1; } @@ -533,6 +539,31 @@ _PyIO_ConvertSsize_t(PyObject *obj, void *result) { } +PyObject * +_PyIO_get_locale_module(_PyIO_State *state) +{ + PyObject *mod; + if (state->locale_module != NULL) { + assert(PyWeakref_CheckRef(state->locale_module)); + mod = PyWeakref_GET_OBJECT(state->locale_module); + if (mod != Py_None) { + Py_INCREF(mod); + return mod; + } + Py_CLEAR(state->locale_module); + } + mod = PyImport_ImportModule("_bootlocale"); + if (mod == NULL) + return NULL; + state->locale_module = PyWeakref_NewRef(mod, NULL); + if (state->locale_module == NULL) { + Py_DECREF(mod); + return NULL; + } + return mod; +} + + static int iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { _PyIO_State *state = IO_MOD_STATE(mod); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 0fe90a3..b90a658 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -77,7 +77,7 @@ extern int _PyIO_trap_eintr(void); long with "%lld" even when both long and long long have the same precision. */ -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS /* Windows uses long long for offsets */ typedef PY_LONG_LONG Py_off_t; @@ -137,6 +137,8 @@ typedef struct { #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) #define IO_STATE IO_MOD_STATE(PyState_FindModule(&_PyIO_Module)) +extern PyObject *_PyIO_get_locale_module(_PyIO_State *); + extern PyObject *_PyIO_str_close; extern PyObject *_PyIO_str_closed; extern PyObject *_PyIO_str_decode; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 3afe7b1..a04b48d 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -52,7 +52,6 @@ bufferediobase_readinto(PyObject *self, PyObject *args) Py_buffer buf; Py_ssize_t len; PyObject *data; - _Py_IDENTIFIER(read); if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) { return NULL; @@ -190,7 +189,8 @@ PyTypeObject PyBufferedIOBase_Type = { 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferediobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -209,6 +209,16 @@ PyTypeObject PyBufferedIOBase_Type = { 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -220,7 +230,7 @@ typedef struct { int detached; int readable; int writable; - int deallocating; + char finalizing; /* True if this is a vanilla Buffered object (rather than a user derived class) *and* the raw stream is a vanilla FileIO object. */ @@ -384,8 +394,8 @@ _enter_buffered_busy(buffered *self) static void buffered_dealloc(buffered *self) { - self->deallocating = 1; - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) + self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); self->ok = 0; @@ -428,8 +438,6 @@ buffered_traverse(buffered *self, visitproc visit, void *arg) static int buffered_clear(buffered *self) { - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) - return -1; self->ok = 0; Py_CLEAR(self->raw); Py_CLEAR(self->dict); @@ -508,7 +516,7 @@ buffered_close(buffered *self, PyObject *args) goto end; } - if (self->deallocating) { + if (self->finalizing) { PyObject *r = buffered_dealloc_warn(self, (PyObject *) self); if (r) Py_DECREF(r); @@ -527,6 +535,11 @@ buffered_close(buffered *self, PyObject *args) res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL); + if (self->buffer) { + PyMem_Free(self->buffer); + self->buffer = NULL; + } + if (exc != NULL) { if (res != NULL) { Py_CLEAR(res); @@ -658,6 +671,11 @@ static void _set_BlockingIOError(char *msg, Py_ssize_t written) { PyObject *err; +#ifdef Py_DEBUG + /* in debug mode, PyEval_EvalFrameEx() fails with an assertion error + if an exception is set when it is called */ + PyErr_Clear(); +#endif err = PyObject_CallFunction(PyExc_BlockingIOError, "isn", errno, msg, written); if (err) @@ -1739,6 +1757,7 @@ static PyMethodDef bufferedreader_methods[] = { static PyMemberDef bufferedreader_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -1771,7 +1790,7 @@ PyTypeObject PyBufferedReader_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedreader_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -1790,6 +1809,16 @@ PyTypeObject PyBufferedReader_Type = { (initproc)bufferedreader_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2120,6 +2149,7 @@ static PyMethodDef bufferedwriter_methods[] = { static PyMemberDef bufferedwriter_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -2152,7 +2182,7 @@ PyTypeObject PyBufferedWriter_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedwriter_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -2171,6 +2201,16 @@ PyTypeObject PyBufferedWriter_Type = { (initproc)bufferedwriter_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2406,7 +2446,7 @@ PyTypeObject PyBufferedRWPair_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ bufferedrwpair_doc, /* tp_doc */ (traverseproc)bufferedrwpair_traverse, /* tp_traverse */ (inquiry)bufferedrwpair_clear, /* tp_clear */ @@ -2425,6 +2465,16 @@ PyTypeObject PyBufferedRWPair_Type = { (initproc)bufferedrwpair_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -2512,6 +2562,7 @@ static PyMethodDef bufferedrandom_methods[] = { static PyMemberDef bufferedrandom_members[] = { {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, {NULL} }; @@ -2544,7 +2595,7 @@ PyTypeObject PyBufferedRandom_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ bufferedrandom_doc, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ @@ -2563,4 +2614,14 @@ PyTypeObject PyBufferedRandom_Type = { (initproc)bufferedrandom_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index f3ce776..0e1e709 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -52,13 +52,15 @@ typedef struct { unsigned int appending : 1; signed int seekable : 2; /* -1 means unknown */ unsigned int closefd : 1; - unsigned int deallocating: 1; + char finalizing; PyObject *weakreflist; PyObject *dict; } fileio; PyTypeObject PyFileIO_Type; +_Py_IDENTIFIER(name); + #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type)) int @@ -129,7 +131,7 @@ fileio_close(fileio *self) self->fd = -1; Py_RETURN_NONE; } - if (self->deallocating) { + if (self->finalizing) { PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); if (r) Py_DECREF(r); @@ -204,6 +206,9 @@ check_fd(int fd) return 0; } +#ifdef O_CLOEXEC +extern int _Py_open_cloexec_works; +#endif static int fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) @@ -223,6 +228,11 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) int fd = -1; int closefd = 1; int fd_is_own = 0; +#ifdef O_CLOEXEC + int *atomic_flag_works = &_Py_open_cloexec_works; +#elif !defined(MS_WINDOWS) + int *atomic_flag_works = NULL; +#endif assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -343,6 +353,12 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) flags |= O_BINARY; #endif +#ifdef MS_WINDOWS + flags |= O_NOINHERIT; +#elif defined(O_CLOEXEC) + flags |= O_CLOEXEC; +#endif + if (fd >= 0) { if (check_fd(fd)) goto error; @@ -366,10 +382,18 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) else #endif self->fd = open(name, flags, 0666); + Py_END_ALLOW_THREADS - } else { - PyObject *fdobj = PyObject_CallFunction( - opener, "Oi", nameobj, flags); + } + else { + PyObject *fdobj; + +#ifndef MS_WINDOWS + /* the opener may clear the atomic flag */ + atomic_flag_works = NULL; +#endif + + fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags); if (fdobj == NULL) goto error; if (!PyLong_Check(fdobj)) { @@ -388,14 +412,14 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) fd_is_own = 1; if (self->fd < 0) { -#ifdef MS_WINDOWS - if (widename != NULL) - PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); - else -#endif - PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); goto error; } + +#ifndef MS_WINDOWS + if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0) + goto error; +#endif } if (dircheck(self, nameobj) < 0) goto error; @@ -405,7 +429,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) _setmode(self->fd, O_BINARY); #endif - if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0) + if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0) goto error; if (self->appending) { @@ -449,7 +473,7 @@ fileio_clear(fileio *self) static void fileio_dealloc(fileio *self) { - self->deallocating = 1; + self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); @@ -535,7 +559,7 @@ fileio_readinto(fileio *self, PyObject *args) len = pbuf.len; Py_BEGIN_ALLOW_THREADS errno = 0; -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS if (len > INT_MAX) len = INT_MAX; n = read(self->fd, pbuf.buf, (int)len); @@ -558,33 +582,27 @@ fileio_readinto(fileio *self, PyObject *args) return PyLong_FromSsize_t(n); } +#ifndef HAVE_FSTAT + +static PyObject * +fileio_readall(fileio *self) +{ + _Py_IDENTIFIER(readall); + return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_readall, "O", self); +} + +#else + static size_t -new_buffersize(fileio *self, size_t currentsize -#ifdef HAVE_FSTAT - , Py_off_t pos, Py_off_t end -#endif - ) +new_buffersize(fileio *self, size_t currentsize) { size_t addend; -#ifdef HAVE_FSTAT - if (end != (Py_off_t)-1) { - /* Files claiming a size smaller than SMALLCHUNK may - actually be streaming pseudo-files. In this case, we - apply the more aggressive algorithm below. - */ - if (end >= SMALLCHUNK && end >= pos && pos >= 0) { - /* Add 1 so if the file were to grow we'd notice. */ - Py_off_t bufsize = currentsize + end - pos + 1; - if (bufsize < PY_SSIZE_T_MAX) - return (size_t)bufsize; - else - return PY_SSIZE_T_MAX; - } - } -#endif + /* Expand the buffer by an amount proportional to the current size, giving us amortized linear-time behavior. For bigger sizes, use a less-than-double growth factor to avoid excessive allocation. */ + assert(currentsize <= PY_SSIZE_T_MAX); if (currentsize > 65536) addend = currentsize >> 3; else @@ -598,26 +616,19 @@ new_buffersize(fileio *self, size_t currentsize static PyObject * fileio_readall(fileio *self) { -#ifdef HAVE_FSTAT struct stat st; Py_off_t pos, end; -#endif PyObject *result; - Py_ssize_t total = 0; + Py_ssize_t bytes_read = 0; Py_ssize_t n; - size_t newsize; + size_t bufsize; if (self->fd < 0) return err_closed(); if (!_PyVerify_fd(self->fd)) return PyErr_SetFromErrno(PyExc_IOError); - result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); - if (result == NULL) - return NULL; - -#ifdef HAVE_FSTAT -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS pos = _lseeki64(self->fd, 0L, SEEK_CUR); #else pos = lseek(self->fd, 0L, SEEK_CUR); @@ -626,44 +637,46 @@ fileio_readall(fileio *self) end = st.st_size; else end = (Py_off_t)-1; -#endif + + if (end > 0 && end >= pos && pos >= 0 && end - pos < PY_SSIZE_T_MAX) { + /* This is probably a real file, so we try to allocate a + buffer one byte larger than the rest of the file. If the + calculation is right then we should get EOF without having + to enlarge the buffer. */ + bufsize = (size_t)(end - pos + 1); + } else { + bufsize = SMALLCHUNK; + } + + result = PyBytes_FromStringAndSize(NULL, bufsize); + if (result == NULL) + return NULL; + while (1) { -#ifdef HAVE_FSTAT - newsize = new_buffersize(self, total, pos, end); -#else - newsize = new_buffersize(self, total); -#endif - if (newsize > PY_SSIZE_T_MAX || newsize <= 0) { - PyErr_SetString(PyExc_OverflowError, - "unbounded read returned more bytes " - "than a Python string can hold "); - Py_DECREF(result); - return NULL; - } + if (bytes_read >= (Py_ssize_t)bufsize) { + bufsize = new_buffersize(self, bytes_read); + if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) { + PyErr_SetString(PyExc_OverflowError, + "unbounded read returned more bytes " + "than a Python string can hold"); + Py_DECREF(result); + return NULL; + } - if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) { - if (_PyBytes_Resize(&result, newsize) < 0) { - if (total == 0) { - Py_DECREF(result); + if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) { + if (_PyBytes_Resize(&result, bufsize) < 0) return NULL; - } - PyErr_Clear(); - break; } } Py_BEGIN_ALLOW_THREADS errno = 0; - n = newsize - total; -#if defined(MS_WIN64) || defined(MS_WINDOWS) + n = bufsize - bytes_read; +#ifdef MS_WINDOWS if (n > INT_MAX) n = INT_MAX; - n = read(self->fd, - PyBytes_AS_STRING(result) + total, - (int)n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); #else - n = read(self->fd, - PyBytes_AS_STRING(result) + total, - n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); #endif Py_END_ALLOW_THREADS if (n == 0) @@ -676,7 +689,7 @@ fileio_readall(fileio *self) } continue; } - if (total > 0) + if (bytes_read > 0) break; if (errno == EAGAIN) { Py_DECREF(result); @@ -686,22 +699,19 @@ fileio_readall(fileio *self) PyErr_SetFromErrno(PyExc_IOError); return NULL; } - total += n; -#ifdef HAVE_FSTAT + bytes_read += n; pos += n; -#endif } - if (PyBytes_GET_SIZE(result) > total) { - if (_PyBytes_Resize(&result, total) < 0) { - /* This should never happen, but just in case */ - Py_DECREF(result); + if (PyBytes_GET_SIZE(result) > bytes_read) { + if (_PyBytes_Resize(&result, bytes_read) < 0) return NULL; - } } return result; } +#endif /* HAVE_FSTAT */ + static PyObject * fileio_read(fileio *self, PyObject *args) { @@ -722,7 +732,7 @@ fileio_read(fileio *self, PyObject *args) return fileio_readall(self); } -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS if (size > INT_MAX) size = INT_MAX; #endif @@ -734,7 +744,7 @@ fileio_read(fileio *self, PyObject *args) if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS n = read(self->fd, ptr, (int)size); #else n = read(self->fd, ptr, size); @@ -755,7 +765,7 @@ fileio_read(fileio *self, PyObject *args) if (n != size) { if (_PyBytes_Resize(&bytes, n) < 0) { - Py_DECREF(bytes); + Py_CLEAR(bytes); return NULL; } } @@ -782,7 +792,7 @@ fileio_write(fileio *self, PyObject *args) Py_BEGIN_ALLOW_THREADS errno = 0; len = pbuf.len; -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS if (len > 32767 && isatty(self->fd)) { /* Issue #11395: the Windows console returns an error (12: not enough space error) on writing into stdout if stdout mode is @@ -855,7 +865,7 @@ portable_lseek(int fd, PyObject *posobj, int whence) if (_PyVerify_fd(fd)) { Py_BEGIN_ALLOW_THREADS -#if defined(MS_WIN64) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS res = _lseeki64(fd, pos, whence); #else res = lseek(fd, pos, whence); @@ -1028,7 +1038,6 @@ mode_string(fileio *self) static PyObject * fileio_repr(fileio *self) { - _Py_IDENTIFIER(name); PyObject *nameobj, *res; if (self->fd < 0) @@ -1204,6 +1213,11 @@ static PyGetSetDef fileio_getsetlist[] = { {NULL}, }; +static PyMemberDef fileio_members[] = { + {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0}, + {NULL} +}; + PyTypeObject PyFileIO_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_io.FileIO", @@ -1225,7 +1239,7 @@ PyTypeObject PyFileIO_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ fileio_doc, /* tp_doc */ (traverseproc)fileio_traverse, /* tp_traverse */ (inquiry)fileio_clear, /* tp_clear */ @@ -1234,7 +1248,7 @@ PyTypeObject PyFileIO_Type = { 0, /* tp_iter */ 0, /* tp_iternext */ fileio_methods, /* tp_methods */ - 0, /* tp_members */ + fileio_members, /* tp_members */ fileio_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ @@ -1245,4 +1259,13 @@ PyTypeObject PyFileIO_Type = { PyType_GenericAlloc, /* tp_alloc */ fileio_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index e38473a..1b7cb0f 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -1,9 +1,9 @@ /* An implementation of the I/O abstract base classes hierarchy as defined by PEP 3116 - "New I/O" - + Classes defined here: IOBase, RawIOBase. - + Written by Amaury Forgeot d'Arc and Antoine Pitrou */ @@ -19,7 +19,7 @@ typedef struct { PyObject_HEAD - + PyObject *dict; PyObject *weakreflist; } iobase; @@ -63,6 +63,8 @@ _Py_IDENTIFIER(__IOBase_closed); #define IS_CLOSED(self) \ _PyObject_HasAttrId(self, &PyId___IOBase_closed) +_Py_IDENTIFIER(read); + /* Internal methods */ static PyObject * iobase_unsupported(const char *message) @@ -180,42 +182,44 @@ static PyObject * iobase_close(PyObject *self, PyObject *args) { PyObject *res; - _Py_IDENTIFIER(__IOBase_closed); if (IS_CLOSED(self)) Py_RETURN_NONE; res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL); - _PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True); - if (res == NULL) { + + if (_PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True) < 0) { + Py_XDECREF(res); return NULL; } - Py_XDECREF(res); + + if (res == NULL) + return NULL; + + Py_DECREF(res); Py_RETURN_NONE; } /* Finalization and garbage collection support */ -int -_PyIOBase_finalize(PyObject *self) +static void +iobase_finalize(PyObject *self) { PyObject *res; - PyObject *tp, *v, *tb; - int closed = 1; - int is_zombie; + PyObject *error_type, *error_value, *error_traceback; + int closed; + _Py_IDENTIFIER(_finalizing); + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); - /* If _PyIOBase_finalize() is called from a destructor, we need to - resurrect the object as calling close() can invoke arbitrary code. */ - is_zombie = (Py_REFCNT(self) == 0); - if (is_zombie) { - ++Py_REFCNT(self); - } - PyErr_Fetch(&tp, &v, &tb); /* If `closed` doesn't exist or can't be evaluated as bool, then the object is probably in an unusable state, so ignore. */ res = PyObject_GetAttr(self, _PyIO_str_closed); - if (res == NULL) + if (res == NULL) { PyErr_Clear(); + closed = -1; + } else { closed = PyObject_IsTrue(res); Py_DECREF(res); @@ -223,6 +227,10 @@ _PyIOBase_finalize(PyObject *self) PyErr_Clear(); } if (closed == 0) { + /* Signal close() that it was called as part of the object + finalization process. */ + if (_PyObject_SetAttrId(self, &PyId__finalizing, Py_True)) + PyErr_Clear(); res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close, NULL); /* Silencing I/O errors is bad, but printing spurious tracebacks is @@ -233,31 +241,25 @@ _PyIOBase_finalize(PyObject *self) else Py_DECREF(res); } - PyErr_Restore(tp, v, tb); - if (is_zombie) { - if (--Py_REFCNT(self) != 0) { - /* The object lives again. The following code is taken from - slot_tp_del in typeobject.c. */ - Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReference(self); - Py_REFCNT(self) = refcnt; - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --Py_TYPE(self)->tp_frees; - --Py_TYPE(self)->tp_allocs; -#endif - return -1; - } + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + +int +_PyIOBase_finalize(PyObject *self) +{ + int is_zombie; + + /* If _PyIOBase_finalize() is called from a destructor, we need to + resurrect the object as calling close() can invoke arbitrary code. */ + is_zombie = (Py_REFCNT(self) == 0); + if (is_zombie) + return PyObject_CallFinalizerFromDealloc(self); + else { + PyObject_CallFinalizer(self); + return 0; } - return 0; } static int @@ -270,8 +272,6 @@ iobase_traverse(iobase *self, visitproc visit, void *arg) static int iobase_clear(iobase *self) { - if (_PyIOBase_finalize((PyObject *) self) < 0) - return -1; Py_CLEAR(self->dict); return 0; } @@ -455,7 +455,6 @@ iobase_readline(PyObject *self, PyObject *args) int has_peek = 0; PyObject *buffer, *result; Py_ssize_t old_size = -1; - _Py_IDENTIFIER(read); _Py_IDENTIFIER(peek); if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) { @@ -536,7 +535,10 @@ iobase_readline(PyObject *self, PyObject *args) } old_size = PyByteArray_GET_SIZE(buffer); - PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b)); + if (PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b)) < 0) { + Py_DECREF(b); + goto fail; + } memcpy(PyByteArray_AS_STRING(buffer) + old_size, PyBytes_AS_STRING(b), PyBytes_GET_SIZE(b)); @@ -741,7 +743,7 @@ PyTypeObject PyIOBase_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ iobase_doc, /* tp_doc */ (traverseproc)iobase_traverse, /* tp_traverse */ (inquiry)iobase_clear, /* tp_clear */ @@ -760,6 +762,16 @@ PyTypeObject PyIOBase_Type = { 0, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + (destructor)iobase_finalize, /* tp_finalize */ }; @@ -831,12 +843,11 @@ rawiobase_readall(PyObject *self, PyObject *args) int r; PyObject *chunks = PyList_New(0); PyObject *result; - + if (chunks == NULL) return NULL; while (1) { - _Py_IDENTIFIER(read); PyObject *data = _PyObject_CallMethodId(self, &PyId_read, "i", DEFAULT_BUFFER_SIZE); if (!data) { @@ -905,7 +916,7 @@ PyTypeObject PyRawIOBase_Type = { 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ rawiobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -924,4 +935,14 @@ PyTypeObject PyRawIOBase_Type = { 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 603ee60..fb89a17 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -173,7 +173,8 @@ PyTypeObject PyTextIOBase_Type = { 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ textiobase_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -192,6 +193,16 @@ PyTypeObject PyTextIOBase_Type = { 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; @@ -691,7 +702,7 @@ typedef struct char seekable; char has_read1; char telling; - char deallocating; + char finalizing; /* Specialized encoding func (see below) */ encodefunc_t encodefunc; /* Whether or not it's the start of the stream */ @@ -758,7 +769,7 @@ utf16_encode(textio *self, PyObject *text) { if (!self->encoding_start_of_stream) { /* Skip the BOM and use native byte ordering */ -#if defined(WORDS_BIGENDIAN) +#if PY_BIG_ENDIAN return utf16be_encode(self, text); #else return utf16le_encode(self, text); @@ -787,7 +798,7 @@ utf32_encode(textio *self, PyObject *text) { if (!self->encoding_start_of_stream) { /* Skip the BOM and use native byte ordering */ -#if defined(WORDS_BIGENDIAN) +#if PY_BIG_ENDIAN return utf32be_encode(self, text); #else return utf32le_encode(self, text); @@ -906,35 +917,29 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds) } } if (encoding == NULL && self->encoding == NULL) { - if (state->locale_module == NULL) { - state->locale_module = PyImport_ImportModule("locale"); - if (state->locale_module == NULL) - goto catch_ImportError; - else - goto use_locale; - } - else { - use_locale: - self->encoding = _PyObject_CallMethodId( - state->locale_module, &PyId_getpreferredencoding, "O", Py_False); - if (self->encoding == NULL) { - catch_ImportError: - /* - Importing locale can raise a ImportError because of - _functools, and locale.getpreferredencoding can raise a - ImportError if _locale is not available. These will happen - during module building. - */ - if (PyErr_ExceptionMatches(PyExc_ImportError)) { - PyErr_Clear(); - self->encoding = PyUnicode_FromString("ascii"); - } - else - goto error; + PyObject *locale_module = _PyIO_get_locale_module(state); + if (locale_module == NULL) + goto catch_ImportError; + self->encoding = _PyObject_CallMethodId( + locale_module, &PyId_getpreferredencoding, "O", Py_False); + Py_DECREF(locale_module); + if (self->encoding == NULL) { + catch_ImportError: + /* + Importing locale can raise a ImportError because of + _functools, and locale.getpreferredencoding can raise a + ImportError if _locale is not available. These will happen + during module building. + */ + if (PyErr_ExceptionMatches(PyExc_ImportError)) { + PyErr_Clear(); + self->encoding = PyUnicode_FromString("ascii"); } - else if (!PyUnicode_Check(self->encoding)) - Py_CLEAR(self->encoding); + else + goto error; } + else if (!PyUnicode_Check(self->encoding)) + Py_CLEAR(self->encoding); } if (self->encoding != NULL) { encoding = _PyUnicode_AsString(self->encoding); @@ -1112,8 +1117,6 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds) static int _textiowrapper_clear(textio *self) { - if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) - return -1; self->ok = 0; Py_CLEAR(self->buffer); Py_CLEAR(self->encoding); @@ -1131,9 +1134,10 @@ _textiowrapper_clear(textio *self) static void textiowrapper_dealloc(textio *self) { - self->deallocating = 1; - if (_textiowrapper_clear(self) < 0) + self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) return; + _textiowrapper_clear(self); _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); @@ -1937,10 +1941,7 @@ typedef struct { #define COOKIE_BUF_LEN (sizeof(Py_off_t) + 3 * sizeof(int) + sizeof(char)) -#if defined(WORDS_BIGENDIAN) - -# define IS_LITTLE_ENDIAN 0 - +#if PY_BIG_ENDIAN /* We want the least significant byte of start_pos to also be the least significant byte of the cookie, which means that in big-endian mode we must copy the fields in reverse order. */ @@ -1952,9 +1953,6 @@ typedef struct { # define OFF_NEED_EOF 0 #else - -# define IS_LITTLE_ENDIAN 1 - /* Little-endian mode: the least significant byte of start_pos will naturally end up the least significant byte of the cookie. */ @@ -1975,7 +1973,7 @@ textiowrapper_parse_cookie(cookie_type *cookie, PyObject *cookieObj) return -1; if (_PyLong_AsByteArray(cookieLong, buffer, sizeof(buffer), - IS_LITTLE_ENDIAN, 0) < 0) { + PY_LITTLE_ENDIAN, 0) < 0) { Py_DECREF(cookieLong); return -1; } @@ -2001,9 +1999,9 @@ textiowrapper_build_cookie(cookie_type *cookie) memcpy(buffer + OFF_CHARS_TO_SKIP, &cookie->chars_to_skip, sizeof(cookie->chars_to_skip)); memcpy(buffer + OFF_NEED_EOF, &cookie->need_eof, sizeof(cookie->need_eof)); - return _PyLong_FromByteArray(buffer, sizeof(buffer), IS_LITTLE_ENDIAN, 0); + return _PyLong_FromByteArray(buffer, sizeof(buffer), + PY_LITTLE_ENDIAN, 0); } -#undef IS_LITTLE_ENDIAN static int _textiowrapper_decoder_setstate(textio *self, cookie_type *cookie) @@ -2353,7 +2351,7 @@ textiowrapper_tell(textio *self, PyObject *args) /* Note our initial start point. */ cookie.start_pos += skip_bytes; - cookie.chars_to_skip = chars_to_skip; + cookie.chars_to_skip = Py_SAFE_DOWNCAST(chars_to_skip, Py_ssize_t, int); if (chars_to_skip == 0) goto finally; @@ -2579,7 +2577,7 @@ textiowrapper_close(textio *self, PyObject *args) } else { PyObject *exc = NULL, *val, *tb; - if (self->deallocating) { + if (self->finalizing) { res = _PyObject_CallMethodId(self->buffer, &PyId__dealloc_warn, "O", self); if (res) Py_DECREF(res); @@ -2740,6 +2738,7 @@ static PyMemberDef textiowrapper_members[] = { {"encoding", T_OBJECT, offsetof(textio, encoding), READONLY}, {"buffer", T_OBJECT, offsetof(textio, buffer), READONLY}, {"line_buffering", T_BOOL, offsetof(textio, line_buffering), READONLY}, + {"_finalizing", T_BOOL, offsetof(textio, finalizing), 0}, {NULL} }; @@ -2776,7 +2775,7 @@ PyTypeObject PyTextIOWrapper_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ textiowrapper_doc, /* tp_doc */ (traverseproc)textiowrapper_traverse, /* tp_traverse */ (inquiry)textiowrapper_clear, /* tp_clear */ @@ -2795,4 +2794,14 @@ PyTypeObject PyTextIOWrapper_Type = { (initproc)textiowrapper_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ }; |
