diff -r 11dea186d3fc Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h Wed Oct 13 15:15:02 2010 +0200 +++ b/Modules/_io/_iomodule.h Wed Oct 13 22:13:29 2010 +0200 @@ -19,7 +19,6 @@ extern PyTypeObject PyBufferedRandom_Typ extern PyTypeObject PyTextIOWrapper_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; - extern int _PyIO_ConvertSsize_t(PyObject *, void *); /* These functions are used as METH_NOARGS methods, are normally called @@ -41,6 +40,13 @@ extern int _PyIOBase_finalize(PyObject * Doesn't check the argument type, so be careful! */ extern int _PyFileIO_closed(PyObject *self); +/* Warn if the given RawIO object is not yet closed (used in dealloc + routines, hence the name). No-op if the object isn't a FileIO. */ +extern void _PyFileIO_dealloc_warn(PyObject *self, PyObject *source); + +/* Same with a BufferedIO object. */ +extern void _PyBufferedIO_dealloc_warn(PyObject *self, PyObject *source); + /* Shortcut to the core of the IncrementalNewlineDecoder.decode method */ extern PyObject *_PyIncrementalNewlineDecoder_decode( PyObject *self, PyObject *input, int final); diff -r 11dea186d3fc Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Wed Oct 13 15:15:02 2010 +0200 +++ b/Modules/_io/bufferedio.c Wed Oct 13 22:13:29 2010 +0200 @@ -342,6 +342,7 @@ typedef struct { static void buffered_dealloc(buffered *self) { + _PyBufferedIO_dealloc_warn((PyObject *) self, (PyObject *) self); if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); @@ -2297,3 +2298,16 @@ PyTypeObject PyBufferedRandom_Type = { PyType_GenericNew, /* tp_new */ }; + +void +_PyBufferedIO_dealloc_warn(PyObject *obj, PyObject *source) +{ + if (PyObject_TypeCheck(obj, &PyBufferedReader_Type) || + PyObject_TypeCheck(obj, &PyBufferedWriter_Type) || + PyObject_TypeCheck(obj, &PyBufferedRandom_Type)) { + buffered *self = (buffered *) obj; + if (self->raw) { + _PyFileIO_dealloc_warn(self->raw, source); + } + } +} diff -r 11dea186d3fc Modules/_io/fileio.c --- a/Modules/_io/fileio.c Wed Oct 13 15:15:02 2010 +0200 +++ b/Modules/_io/fileio.c Wed Oct 13 22:13:29 2010 +0200 @@ -2,6 +2,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "structmember.h" #ifdef HAVE_SYS_TYPES_H #include #endif @@ -55,6 +56,7 @@ typedef struct { unsigned int writable : 1; signed int seekable : 2; /* -1 means unknown */ unsigned int closefd : 1; + unsigned int deallocating: 1; PyObject *weakreflist; PyObject *dict; } fileio; @@ -69,6 +71,24 @@ _PyFileIO_closed(PyObject *self) return ((fileio *)self)->fd < 0; } +void +_PyFileIO_dealloc_warn(PyObject *obj, PyObject *source) +{ + fileio *self; + + if (!PyFileIO_Check(obj)) + return; + self = (fileio *) obj; + if (self->fd >= 0 && self->closefd) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + PyErr_SetString(PyExc_RuntimeWarning, + "file not yet closed when deallocating"); + PyErr_WriteUnraisable(source); + PyErr_Restore(exc, val, tb); + } +} + static PyObject * portable_lseek(int fd, PyObject *posobj, int whence); @@ -398,6 +418,7 @@ fileio_clear(fileio *self) static void fileio_dealloc(fileio *self) { + _PyFileIO_dealloc_warn((PyObject *) self, (PyObject *) self); if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); diff -r 11dea186d3fc Modules/_io/textio.c --- a/Modules/_io/textio.c Wed Oct 13 15:15:02 2010 +0200 +++ b/Modules/_io/textio.c Wed Oct 13 22:13:29 2010 +0200 @@ -1094,6 +1094,8 @@ _textiowrapper_clear(textio *self) static void textiowrapper_dealloc(textio *self) { + if (self->buffer) + _PyBufferedIO_dealloc_warn(self->buffer, (PyObject *) self); if (_textiowrapper_clear(self) < 0) return; _PyObject_GC_UNTRACK(self);