summaryrefslogtreecommitdiffstats
path: root/Modules/_io
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_io')
-rw-r--r--Modules/_io/_iomodule.c25
-rw-r--r--Modules/_io/_iomodule.h4
-rw-r--r--Modules/_io/bufferedio.c84
-rw-r--r--Modules/_io/fileio.c165
-rw-r--r--Modules/_io/iobase.c96
-rw-r--r--Modules/_io/textio.c105
6 files changed, 293 insertions, 186 deletions
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index 4a7e758..14457e8 100644
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -533,6 +533,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("locale");
+ 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..6fe5d58 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -190,7 +190,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 +210,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 +231,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 +395,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 +439,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 +517,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 +536,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 +672,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 +1758,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 +1791,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 +1810,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 +2150,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 +2183,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 +2202,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 +2447,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 +2466,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 +2563,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 +2596,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 +2615,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 2d0239e..e88ae87 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -51,7 +51,7 @@ typedef struct {
unsigned int writable : 1;
signed int seekable : 2; /* -1 means unknown */
unsigned int closefd : 1;
- unsigned int deallocating: 1;
+ char finalizing;
PyObject *weakreflist;
PyObject *dict;
} fileio;
@@ -128,7 +128,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);
@@ -391,12 +391,7 @@ 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;
}
}
@@ -452,7 +447,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);
@@ -538,7 +533,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);
@@ -561,33 +556,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
@@ -601,26 +590,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);
@@ -629,44 +611,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)
@@ -679,7 +663,7 @@ fileio_readall(fileio *self)
}
continue;
}
- if (total > 0)
+ if (bytes_read > 0)
break;
if (errno == EAGAIN) {
Py_DECREF(result);
@@ -689,22 +673,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)
{
@@ -725,7 +706,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
@@ -737,7 +718,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);
@@ -758,7 +739,7 @@ fileio_read(fileio *self, PyObject *args)
if (n != size) {
if (_PyBytes_Resize(&bytes, n) < 0) {
- Py_DECREF(bytes);
+ Py_CLEAR(bytes);
return NULL;
}
}
@@ -785,7 +766,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
@@ -858,7 +839,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);
@@ -1201,6 +1182,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",
@@ -1222,7 +1208,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 */
@@ -1231,7 +1217,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 */
@@ -1242,4 +1228,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..ae188dd 100644
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -196,26 +196,24 @@ iobase_close(PyObject *self, PyObject *args)
/* 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 +221,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 +235,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 +266,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;
}
@@ -741,7 +735,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 +754,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 */
};
@@ -905,7 +909,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 +928,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 111cc7e..2db37d3 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 */
};