@@ -197,6 +197,7 @@ typedef struct {
197197 int detached ;
198198 int readable ;
199199 int writable ;
200+ int deallocating ;
200201
201202 /* True if this is a vanilla Buffered object (rather than a user derived
202203 class) *and* the raw stream is a vanilla FileIO object. */
@@ -342,6 +343,7 @@ typedef struct {
342343static void
343344buffered_dealloc (buffered * self )
344345{
346+ self -> deallocating = 1 ;
345347 if (self -> ok && _PyIOBase_finalize ((PyObject * ) self ) < 0 )
346348 return ;
347349 _PyObject_GC_UNTRACK (self );
@@ -382,6 +384,23 @@ buffered_clear(buffered *self)
382384 return 0 ;
383385}
384386
387+ /* Because this can call arbitrary code, it shouldn't be called when
388+ the refcount is 0 (that is, not directly from tp_dealloc unless
389+ the refcount has been temporarily re-incremented). */
390+ PyObject *
391+ buffered_dealloc_warn (buffered * self , PyObject * source )
392+ {
393+ if (self -> ok && self -> raw ) {
394+ PyObject * r ;
395+ r = PyObject_CallMethod (self -> raw , "_dealloc_warn" , "O" , source );
396+ if (r )
397+ Py_DECREF (r );
398+ else
399+ PyErr_Clear ();
400+ }
401+ Py_RETURN_NONE ;
402+ }
403+
385404/*
386405 * _BufferedIOMixin methods
387406 * This is not a class, just a collection of methods that will be reused
@@ -435,6 +454,14 @@ buffered_close(buffered *self, PyObject *args)
435454 Py_INCREF (res );
436455 goto end ;
437456 }
457+
458+ if (self -> deallocating ) {
459+ PyObject * r = buffered_dealloc_warn (self , (PyObject * ) self );
460+ if (r )
461+ Py_DECREF (r );
462+ else
463+ PyErr_Clear ();
464+ }
438465 /* flush() will most probably re-take the lock, so drop it first */
439466 LEAVE_BUFFERED (self )
440467 res = PyObject_CallMethodObjArgs ((PyObject * )self , _PyIO_str_flush , NULL );
@@ -1461,6 +1488,7 @@ static PyMethodDef bufferedreader_methods[] = {
14611488 {"writable" , (PyCFunction )buffered_writable , METH_NOARGS },
14621489 {"fileno" , (PyCFunction )buffered_fileno , METH_NOARGS },
14631490 {"isatty" , (PyCFunction )buffered_isatty , METH_NOARGS },
1491+ {"_dealloc_warn" , (PyCFunction )buffered_dealloc_warn , METH_O },
14641492
14651493 {"read" , (PyCFunction )buffered_read , METH_VARARGS },
14661494 {"peek" , (PyCFunction )buffered_peek , METH_VARARGS },
@@ -1843,6 +1871,7 @@ static PyMethodDef bufferedwriter_methods[] = {
18431871 {"writable" , (PyCFunction )buffered_writable , METH_NOARGS },
18441872 {"fileno" , (PyCFunction )buffered_fileno , METH_NOARGS },
18451873 {"isatty" , (PyCFunction )buffered_isatty , METH_NOARGS },
1874+ {"_dealloc_warn" , (PyCFunction )buffered_dealloc_warn , METH_O },
18461875
18471876 {"write" , (PyCFunction )bufferedwriter_write , METH_VARARGS },
18481877 {"truncate" , (PyCFunction )buffered_truncate , METH_VARARGS },
@@ -2227,6 +2256,7 @@ static PyMethodDef bufferedrandom_methods[] = {
22272256 {"writable" , (PyCFunction )buffered_writable , METH_NOARGS },
22282257 {"fileno" , (PyCFunction )buffered_fileno , METH_NOARGS },
22292258 {"isatty" , (PyCFunction )buffered_isatty , METH_NOARGS },
2259+ {"_dealloc_warn" , (PyCFunction )buffered_dealloc_warn , METH_O },
22302260
22312261 {"flush" , (PyCFunction )buffered_flush , METH_NOARGS },
22322262
@@ -2296,4 +2326,3 @@ PyTypeObject PyBufferedRandom_Type = {
22962326 0 , /* tp_alloc */
22972327 PyType_GenericNew , /* tp_new */
22982328};
2299-
0 commit comments