summaryrefslogtreecommitdiffstats
path: root/Modules/_io/bufferedio.c
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-10-29 10:38:18 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2010-10-29 10:38:18 (GMT)
commite033e06db077d5abcb4bc3729d03f8a4a09b2486 (patch)
tree04445ffa669d4d0df240d680249c7d7a7f661bd4 /Modules/_io/bufferedio.c
parent9cbdd75ec5deda8f55edd7caab42dff65d009da2 (diff)
downloadcpython-e033e06db077d5abcb4bc3729d03f8a4a09b2486.zip
cpython-e033e06db077d5abcb4bc3729d03f8a4a09b2486.tar.gz
cpython-e033e06db077d5abcb4bc3729d03f8a4a09b2486.tar.bz2
Issue #10093: ResourceWarnings are now issued when files and sockets are
deallocated without explicit closing. These warnings are silenced by default, except in pydebug mode.
Diffstat (limited to 'Modules/_io/bufferedio.c')
-rw-r--r--Modules/_io/bufferedio.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 615e644..3045169 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -197,6 +197,7 @@ typedef struct {
int detached;
int readable;
int writable;
+ int deallocating;
/* True if this is a vanilla Buffered object (rather than a user derived
class) *and* the raw stream is a vanilla FileIO object. */
@@ -342,6 +343,7 @@ typedef struct {
static void
buffered_dealloc(buffered *self)
{
+ self->deallocating = 1;
if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0)
return;
_PyObject_GC_UNTRACK(self);
@@ -382,6 +384,23 @@ buffered_clear(buffered *self)
return 0;
}
+/* Because this can call arbitrary code, it shouldn't be called when
+ the refcount is 0 (that is, not directly from tp_dealloc unless
+ the refcount has been temporarily re-incremented). */
+PyObject *
+buffered_dealloc_warn(buffered *self, PyObject *source)
+{
+ if (self->ok && self->raw) {
+ PyObject *r;
+ r = PyObject_CallMethod(self->raw, "_dealloc_warn", "O", source);
+ if (r)
+ Py_DECREF(r);
+ else
+ PyErr_Clear();
+ }
+ Py_RETURN_NONE;
+}
+
/*
* _BufferedIOMixin methods
* This is not a class, just a collection of methods that will be reused
@@ -435,6 +454,14 @@ buffered_close(buffered *self, PyObject *args)
Py_INCREF(res);
goto end;
}
+
+ if (self->deallocating) {
+ PyObject *r = buffered_dealloc_warn(self, (PyObject *) self);
+ if (r)
+ Py_DECREF(r);
+ else
+ PyErr_Clear();
+ }
/* flush() will most probably re-take the lock, so drop it first */
LEAVE_BUFFERED(self)
res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
@@ -1461,6 +1488,7 @@ static PyMethodDef bufferedreader_methods[] = {
{"writable", (PyCFunction)buffered_writable, METH_NOARGS},
{"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
{"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
+ {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
{"read", (PyCFunction)buffered_read, METH_VARARGS},
{"peek", (PyCFunction)buffered_peek, METH_VARARGS},
@@ -1843,6 +1871,7 @@ static PyMethodDef bufferedwriter_methods[] = {
{"writable", (PyCFunction)buffered_writable, METH_NOARGS},
{"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
{"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
+ {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
{"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
{"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
@@ -2227,6 +2256,7 @@ static PyMethodDef bufferedrandom_methods[] = {
{"writable", (PyCFunction)buffered_writable, METH_NOARGS},
{"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
{"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
+ {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
{"flush", (PyCFunction)buffered_flush, METH_NOARGS},
@@ -2296,4 +2326,3 @@ PyTypeObject PyBufferedRandom_Type = {
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
-