summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2016-03-22 23:43:54 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2016-03-22 23:43:54 (GMT)
commit7bfa409ff841fd84dfa194dd9052650d0a28585d (patch)
treeb278b5b748e99e162101cbdf0a6bd59ad56e0159
parente19558af1b6979edf27f7a05a6e47a8b5d113390 (diff)
downloadcpython-7bfa409ff841fd84dfa194dd9052650d0a28585d.zip
cpython-7bfa409ff841fd84dfa194dd9052650d0a28585d.tar.gz
cpython-7bfa409ff841fd84dfa194dd9052650d0a28585d.tar.bz2
Implement finalizer for os.scandir() iterator
Issue #26603: * Implement finalizer for os.scandir() iterator * Set the source parameter when emitting the ResourceWarning warning * Close the iterator before emitting the warning
-rw-r--r--Modules/posixmodule.c64
1 files changed, 47 insertions, 17 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 65b20be..1cd0f24 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -12101,29 +12101,38 @@ ScandirIterator_exit(ScandirIterator *self, PyObject *args)
}
static void
-ScandirIterator_dealloc(ScandirIterator *iterator)
+ScandirIterator_finalize(ScandirIterator *iterator)
{
+ PyObject *error_type, *error_value, *error_traceback;
+
+ /* Save the current exception, if any. */
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
if (!ScandirIterator_is_closed(iterator)) {
- PyObject *exc, *val, *tb;
- Py_ssize_t old_refcount = Py_REFCNT(iterator);
- /* Py_INCREF/Py_DECREF cannot be used, because the refcount is
- * likely zero, Py_DECREF would call again the destructor.
- */
- ++Py_REFCNT(iterator);
- PyErr_Fetch(&exc, &val, &tb);
- if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
- "unclosed scandir iterator %R", iterator)) {
+ ScandirIterator_closedir(iterator);
+
+ if (PyErr_ResourceWarning((PyObject *)iterator, 1,
+ "unclosed scandir iterator %R", iterator)) {
/* Spurious errors can appear at shutdown */
- if (PyErr_ExceptionMatches(PyExc_Warning))
+ if (PyErr_ExceptionMatches(PyExc_Warning)) {
PyErr_WriteUnraisable((PyObject *) iterator);
+ }
}
- PyErr_Restore(exc, val, tb);
- Py_REFCNT(iterator) = old_refcount;
-
- ScandirIterator_closedir(iterator);
}
- Py_XDECREF(iterator->path.object);
+
+ Py_CLEAR(iterator->path.object);
path_cleanup(&iterator->path);
+
+ /* Restore the saved exception. */
+ PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+static void
+ScandirIterator_dealloc(ScandirIterator *iterator)
+{
+ if (PyObject_CallFinalizerFromDealloc((PyObject *)iterator) < 0)
+ return;
+
Py_TYPE(iterator)->tp_free((PyObject *)iterator);
}
@@ -12155,7 +12164,8 @@ static PyTypeObject ScandirIteratorType = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
+ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
@@ -12164,6 +12174,26 @@ static PyTypeObject ScandirIteratorType = {
PyObject_SelfIter, /* tp_iter */
(iternextfunc)ScandirIterator_iternext, /* tp_iternext */
ScandirIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 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 */
+ (destructor)ScandirIterator_finalize, /* tp_finalize */
};
static PyObject *