]> granicus.if.org Git - python/commitdiff
Implement finalizer for os.scandir() iterator
authorVictor Stinner <victor.stinner@gmail.com>
Tue, 22 Mar 2016 23:43:54 +0000 (00:43 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 22 Mar 2016 23:43:54 +0000 (00:43 +0100)
Issue #26603:

* Implement finalizer for os.scandir() iterator
* Set the source parameter when emitting the ResourceWarning warning
* Close the iterator before emitting the warning

Modules/posixmodule.c

index 65b20be4686e666794ec486e1d34bd758e43850f..1cd0f24148c88950309dc6f06d3ccd9c2000206b 100644 (file)
@@ -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 *